socket层
socket:是应用层与TCP/IP协议通信的中间软件抽象层,是一组接口,在设计模式中,socket其实就是一个门面模式,它把复杂的TCP/IP协议隐藏在socket接口后面。
基于TCP协议的socket
tcp是基于链接,必须先启动服务端,然后在启动客户端去链接服务端
server端
1 import socket 2 sk=socket.socket() 3 sk.bind(('127.0.0.1',9000)) #把地址绑定到套接字 4 sk.listen() #监听链接 5 conn,addr = sk.accept()#接受客户端链接 6 ret=conn.recv(1024) #接受客户端信息 7 print(ret) #打印客户端信息 8 conn.send(b'hi') #向客户端发送信息 9 conn.close() #关闭客户端套接字 10 sk.close() #关闭服务器套接字
client
1 import socket 2 sk=socket.socket() #创建客户套接字 3 sk.connect(('127.0.0.1',9000)) 尝试链接服务器 4 sk.send(b'hello') 5 ret=sk.recv(1024) #对话 6 print(ret) 7 sk.close() #关闭客户套接字
问题:有的同学在重启服务端时可能遇到
解决办法:
1 #加入一条socket配置,重用ip和端口 2 import socket 3 from socket import SOL_SOCKET,SO_REUSEADDR 4 sk = socket.socket() 5 sk.setsockopt(SOL_SOCKET,SO_REUSEADDR,1) #就是它,在bind前加 6 sk.bind(('127.0.0.1',8898)) #把地址绑定到套接字 7 sk.listen() #监听链接 8 conn,addr = sk.accept() #接受客户端链接 9 ret = conn.recv(1024) #接收客户端信息 10 print(ret) #打印客户端信息 11 conn.send(b'hi') #向客户端发送信息 12 conn.close() #关闭客户端套接字 13 sk.close() #关闭服务器套接字(可选)
关于UDP协议的socket
udp是无链接的,启动服务之后可以直接接受消息,不需要提前建立链接。
server端
1 import socket 2 udp_sk=socket.socket(type=socket.SOCK_DGRAM) 3 udp_sk.bind(('127.0.0.1',9000)) 4 msg,addr=udp_sk.recvfrom(1024) 5 print(msg) 6 udp_sk.sendto(b'hi',addr) 7 udp_sk.close()
client端
1 import socket 2 ip_port=('127.0.0.1',9000) 3 udp_sk=socket.socket(type=socket.SOCK_DGRAM) 4 udp_sk.sendto(b'hello',ip_port) 5 back_msg,addr=udp_sk.recvfrom(1024) 6 print(back_msg.decode('utf-8'),addr)
socket参数的详解
socket.socket(family=AF_INET,type=SOCK_STREAM,proto=0,fileno=None)
创建socket对象的参数说明:
family | 地址系列应为AF_INET(默认值),AF_INET6,AF_UNIX,AF_CAN或AF_RDS。 (AF_UNIX 域实际上是使用本地 socket 文件来通信) |
type | 套接字类型应为SOCK_STREAM(默认值),SOCK_DGRAM,SOCK_RAW或其他SOCK_常量之一。 SOCK_STREAM 是基于TCP的,有保障的(即能保证数据正确传送到对方)面向连接的SOCKET,多用于资料传送。 SOCK_DGRAM 是基于UDP的,无保障的面向消息的socket,多用于在网络上发广播信息。 |
proto | 协议号通常为零,可以省略,或者在地址族为AF_CAN的情况下,协议应为CAN_RAW或CAN_BCM之一。 |
fileno | 如果指定了fileno,则其他参数将被忽略,导致带有指定文件描述符的套接字返回。 与socket.fromfd()不同,fileno将返回相同的套接字,而不是重复的。 这可能有助于使用socket.close()关闭一个独立的插座。 |