1 服务端: 2 ss=socket() #创建服务器套接字 3 ss.bind() #把地址绑定到套接字 4 ss.listen() #监听套接字, 5 inf_loop: #服务器无限循环 6 cs=ss.accept() 接受客户端连接 7 comm_loop: #通讯循环 8 cs.recv()/cs.send() #对话(接收与发送) 9 cs.close() #关闭客户端套接字 10 ss.close() #关闭服务器套接字(可选) 11 12 13 #客户端
14 cs=socker() #创建客户端套接字
15 cs.connet() #尝试连接服务器
16 command_loop: #通讯循环
17 cs.send()/cs.recv() #对话(发送/接收)
18 cs.close() #关闭客户端套接字
这是基于TCP连接的套接字模型。
UDP链接的套接字模型是这样的:
服务端: ss=socket() #创建一个服务器的套接字 ss.bind() #绑定服务器套接字 inf_loop: #服务器无限循环 cs=ss.recvfrom()/ss.sendto() #对话(接收与发送) ss.cloes() #关闭服务器套接字 客户端: cs=socket() #创建客户端套接字 comm_loop: #通信循环 cs.sendto()/cs.recvfrom() #对话(发送和接收) cs.close() #关闭客户套接字
UDP的会话的无关先启动哪一端,先启动服务端或者客户端都不会报错。
而且当客户端发消息的时候,无论服务端收到或者收不到都不会报错;
客户端和服务端收到的消息都分为两部分,
(b"发送的内容",("127.0.0.1",4888)) 我们可以利用 data1,client_addr=udp_server.recvfrom(1024)这种方式来收取数据和对方的地址。
1 #udp服务端 2 from socket import * 3 4 udp_server=socket(AF_INET,SOCK_DGRAM) 5 udp_server.bind(('127.0.0.1',8080)) 6 7 while True: 8 data,client_addr=udp_server.recvfrom(1024) 9 print(data,client_addr) 10 udp_server.sendto(data.upper(),client_addr) 11 12 13 14 #udp client 15 from socket import * 16 17 udp_client=socket(AF_INET,SOCK_DGRAM) 18 19 while True: 20 msg=input('>>: ').strip() 21 udp_client.sendto(msg.encode('utf-8'),('127.0.0.1',8080)) 22 data,server_addr=udp_client.recvfrom(1024) 23 print(data.decode('utf-8'))
基于TCP的连接,发送数据的时候可能会发生粘包(在数据量比较小,时间间隔比较短的情况下),所以我们要探讨下UDP会不会出现这种情况。
#测试代码:
1 #udp server 2 from socket import * 3 udp_server=socket(AF_INET,SOCK_DGRAM) 4 udp_server.bind(('127.0.0.1',8080)) 5 6 data1,client_addr=udp_server.recvfrom(1) 7 print('data1',data1) 8 data2,client_addr=udp_server.recvfrom(1024) 9 print('data2',data2) 10 11 12 13 #udp client 14 from socket import * 15 udp_client=socket(AF_INET,SOCK_DGRAM) 16 17 udp_client.sendto('hello'.encode('utf-8'),('127.0.0.1',8080)) 18 udp_client.sendto('world'.encode('utf-8'),('127.0.0.1',8080))
#通过代码测试我们可以清楚的看到,基于UDP的链接不会发生粘包现象
#但是当UDP发送的字节大于服务端(或者客户端)所接收的字节时,会报错。
实现并发的UDP链接:
#服务端 import socketserver class MyUDPhandler(socketserver.BaseRequestHandler): def handle(self): print(self.request)
#(b'aaa', <socket.socket fd=252, family=AddressFamily.AF_INET, type=SocketKind.SOCK_DGRAM, proto=0, laddr=('127.0.0.1', 8080)>)打印出来是这种格式 #数据+用来给回消息的socket+地址
self.request[1].sendto(self.request[0].upper(),self.client_address) if __name__ == '__main__': s=socketserver.ThreadingUDPServer(('127.0.0.1',8080),MyUDPhandler) #UDP的socket服务进程,()内的是地址和端口,后边跟的是自己定义的类 s.serve_forever()