一、基于UDP的套接字通信
(一)TCP与UDP协议的对比
1.可靠性
(1)TCP协议是可靠协议
对方必须回复一个ack确认消息,才会将自己这端的数据从内存中删除。
(2)UDP是不可靠协议
发送一条消息就会立即删除,不管对方是否接收到。
2.有无链接
tcp有链接,udp无链接。
3.传输数据的效率
udp更高。
4.粘包问题
udp协议称之为数据包协议,每次发送都是一个完整的数据报,一个发送唯一对应一个接收,所以udp没有粘包问题。
(二)基于UDP的套接字基本模板
udp是无链接的,先启动哪一端都不会报错。
1.udp服务端
ss = socket() #创建一个服务器的套接字
ss.bind() #绑定服务器套接字
inf_loop: #服务器无限循环
cs = ss.recvfrom()/ss.sendto() # 对话(接收与发送)
ss.close() # 关闭服务器套接字
2.udp客户端
cs = socket() # 创建客户套接字
comm_loop: # 通讯循环
cs.sendto()/cs.recvfrom() # 对话(发送/接收)
cs.close() # 关闭客户套接字
(三)UDP套接字简单示例
1.udp服务端
# UDP协议基本的服务端
from socket import *
import time
server = socket(AF_INET, SOCK_DGRAM)
server.bind(('127.0.0.1',8080))
while True:
data, client_addr = server.recvfrom(1024)
time.sleep(1)
server.sendto(data.upper(), client_addr)
2.udp客户端
# UDP协议基本的客户端
from socket import *
client = socket(AF_INET, SOCK_DGRAM)
while True:
msg = input('>>>:').strip()
client.sendto(msg.encode('utf-8'), ('127.0.0.1', 8080))
data, server_addr = client.recvfrom(1024)
print(data.decode('utf-8'))
二、基于socketserver实现并发编程
基于TCP的套接字循环,关键就是两个循环,一个链接循环,一个通信循环。
(一)socketserver模块的两大类:
1.server类
用于解决链接循环问题。
2.request类
用于解决通信循环问题。
(二)使用socketserver实现基于TCP的并发
1.TCP并发服务端
# TCP--server端------------
import socketserver
class MyRequestHandler(socketserver.BaseRequestHandler):
def handle(self):
print(self.client_address)
while True:
try:
data = self.request.recv(1024)
if len(data) == 0: break
self.request.send(data.upper())
except Exception:
break
self.request.close()
if __name__ == '__main__':
s = socketserver.ThreadingTCPServer(('127.0.0.1', 8080), MyRequestHandler, bind_and_activate=True)
s.serve_forever()
2.TCP并发客户端
# TCP--client端------------
from socket import *
client = socket(AF_INET, SOCK_STREAM)
client.connect(('127.0.0.1', 8080))
while True:
msg = input('>>>:').strip()
if len(msg) == 0:
continue
client.send(msg.encode('utf-8'))
data = client.recv(1024)
print(data.decode('utf-8'))
(三)使用socketserver实现基于UDP的并发
1.UDP并发服务端
# UDP--server端------------
import socketserver
class MyRequestHandler(socketserver.BaseRequestHandler):
def handle(self):
data, server = self.request
server.sendto(data.upper(), self.client_address)
if __name__ == '__main__':
s = socketserver.ThreadingUDPServer(('127.0.0.1', 8080), MyRequestHandler, bind_and_activate=True)
s.serve_forever()
2.UDP并发客户端
# UDP--client端------------
from socket import *
client = socket(AF_INET, SOCK_DGRAM)
while True:
msg = input('>>>:').strip()
client.sendto(msg.encode('utf-8'), ('127.0.0.1', 8080))
data, server_addr = client.recvfrom(1024)
print(data.decode('utf-8'))
(四)分析总结
1.基于tcp的socketserver我们自己定义的类中的
(1)self.server即套接字对象
(2)self.request即一个链接
(3)self.client_address即客户端地址
2.基于udp的socketserver我们自己定义的类中的
(1)self.request是一个元组(第一个元素是客户端发来的数据,第二部分是服务端的udp套接字对象),
如:(b’adsf’, <socket.socket fd=200, family=AddressFamily.AF_INET, type=SocketKind.SOCK_DGRAM, proto=0, laddr=(‘127.0.0.1’, 8080)>)
(2)self.client_address即客户端地址
(1)self.request是一个元组(第一个元素是客户端发来的数据,第二部分是服务端的udp套接字对象),
如:(b’adsf’, <socket.socket fd=200, family=AddressFamily.AF_INET, type=SocketKind.SOCK_DGRAM, proto=0, laddr=(‘127.0.0.1’, 8080)>)
(2)self.client_address即客户端地址