socket编程
基于TCP协议的套接字编程
Socket:我们常常把socket翻译成套接字,其是在应用层和传输层中间的抽象层,把TCP/IP层复杂的操作抽象为几个简单的接口供应用层调用已经实现的进程在网络中通信。
套接字的分类:
AF_UNIX:用在局域网中
AF_INET:用在互联网中
关于启动客户端和服务端:
先启动服务端,再启动客户端。服务端起来后,等待客户端连接,客户端启动后接收客户端发起来的消息。
简易版套接字编程
SOCK_STREAM: TCP协议
SOCK_DGRAM:UDP协议
服务端 import socket #实例化 server = socket.socket() #连接 server.bind(('127.0.0.1',8080)) print('等待消息传入') # 听 server.listen(5) #5代表的是半连接池:可以等待的客户端的数量
while True: #循环解决了单次传入消息的问题 #接收 sock , addr = server.accept() while True: # 解决客户端只能传入一次 #真正接收 data = sock.recv(1024) if len(data) == 0: #解决客户端终止后服务端进行死循环 break #死循环的原因是客户端突然终止,服务端以为传入的消息是空,所以死循环 print('收到客户端发来的消息:',data) #发 sock.send(data.upper()) #断开客户端连接 sock.close() #彻底关闭 server.close()
客户端 import socket client = socket.socket() #实例化 #连接 client.connect(('127.0.0.1',8080)) while True: #发送消息 news = input('发送消息:') if len(news) == 0: continue client.send(news.encode('utf8')) #发送消息 data = client.recv(1024) #接收消息 print('收到服务端发来的消息:',data.decode('utf8')) client.close()
基于UDP协议的套接字编程
服务端
import socket server = socket.socket(socket.AF_INET,socket.SOCK_DGRAM) server.bind(('127.0.0.1',8080)) while True: #接收客服端发来的消息 data,addr = server.recvfrom(1024) print('客户端发来的消息:',data) server.sendto(data.upper(),addr) #发送客户端发来的消息和端口 server.close()
客户端
import socket #连接 client = socket.socket(socket.AF_INET,socket.SOCK_DGRAM) while True: res = input('输入消息:') #发送消息 client.sendto(res.encode('utf8'),('127.0.0.1',8080)) #需要传地址 data,sever_addr = client.recvfrom(1024) print(data) client.close()
粘包现象
粘包现象:管道中的数据没有完全取出来
TCP的特征:流式协议
当客户端发送的数据量很小且时间间隔很小的时候
它会把数据打包成一个包一次性发送
报头:不管给多少数据,都会打包成一个固定长度的数据。
解决粘包问题的核心就是:为字节流加上自定义固定长度报头,报头中包含字节流长度,然后一次send到对端,对端在接收时,先从缓存中取出定长的报头,然后再取真实数据。
打包(举例子):obj = struct.pack('i', 1222222222223)
解包(举例子):res = struct.unpack('i', obj)