socket(套接字)
基于socket实现客户端与服务端通信服务端套接字函数
s.bind() 绑定(主机,端口号)到套接字
s.listen() 开始TCP监听
s.accept() 被动接受TCP客户的连接,(阻塞式)等待连接的到来
客户端套接字函数
s.connect() 主动初始化TCP服务器连接
s.connect_ex() connect()函数的扩展版本,出错时返回出错码,而不是抛出异常
公共用途的套接字函数
s.recv() 接收TCP数据
s.send() 发送TCP数据(send在待发送数据量大于己端缓存区剩余空间时,数据丢失,不会发完)
socket初识
127.0.0.1:本地回环地址,只能本机访问
-----------------------------服务端------------------------------import socketserver = socket.socket() # 类似于买手机server.bind(('127.0.0.1', 8080)) # 类似于插手机卡 bind((IP,PORT))server.listen(5) # 开机 半连接池conn, addr = server.accept() # 待机等待接电话data = conn.recv(1024) # 接听别人说话 只接收1024个字节 bytesprint(data)conn.send(b'hello!') # 跟别人说话conn.close() # 关闭通信连接server.close() # 关闭服务端-----------------------------客户端------------------------------import socketclient = socket.socket()client.connect(('127.0.0.1', 8080)) # 找服务器client.send(b'hello how much?')data = client.recv(1024)print(data)client.close()
TCP协议的特点
会将数据量比较小的,并且时间间隔比较短的数据,一次性打包发送给接收端
-----------------------------服务端------------------------------import socketserver = socket.socket()server.bind(('127.0.0.1',8088))server.listen(5) # 半连接池conn,addr = server.accept()data = conn.recv(1024)print(data)data = conn.recv(1024)print(data)data = conn.recv(1024)print(data)>>>:b'hellohellohello' b'' b''-----------------------------客户端------------------------------import socketclient = socket.socket()client.connect(('127.0.0.1',8088))client.send(b'hello')client.send(b'hello')client.send(b'hello')
通信循环
-----------------------------服务端------------------------------import socket"""服务端:要有固定的ip和port24小时不间断提供服务"""server = socket.socket()server.bind(('127.0.0.1', 8080))server.listen(5)conn, addr = server.accept() # 阻塞while True: try: data = conn.recv(1024) # 阻塞 if len(data) == 0: break # 针对linux和mac系统 客户端异常断开反复收空的情况 print(data) conn.send(data.upper()) except ConnectionResetError: breakconn.close()server.close()-----------------------------客户端------------------------------import socketclient = socket.socket()client.connect(('127.0.0.1', 8080))while True: msg = input('>>>:').encode('utf-8') if len(msg) == 0: continue client.send(msg) data = client.recv(1024) print(data)
struct模块
import structdata = 'seionksngjgm,xmdnabnk ko'res = struct.pack('i',len(data))print('res:',res) # res: b'\x18\x00\x00\x00'print('len(res):',len(res)) # 4ret = struct.unpack('i',res)print('ret:',ret) # (24,)print('ret[0]:',ret[0]) # 24
链接循环
-----------------------------服务端------------------------------import socketimport subprocessimport structimport json"""服务端:要有固定的ip和port24小时不间断提供服务"""server = socket.socket()server.bind(('127.0.0.1', 8081))server.listen(5) # 半连接池while True: conn, addr = server.accept() # 阻塞 while True: try: data = conn.recv(1024).decode('utf-8') # 阻塞 if len(data) == 0: break # 针对linux和mac系统 客户端异常断开反复收空的情况 obj = subprocess.Popen(data, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout = obj.stdout.read() stderr = obj.stderr.read() print(len(stdout + stderr)) header_dic = { 'filename': 'cls.av', 'len': len(stdout + stderr) } header_bytes = json.dumps(header_dic).encode('utf-8') # 制作报头 header = struct.pack('i', len(header_bytes)) # 将需要发送给客户端的数据打包成固定4个字节 conn.send(header) conn.send(header_bytes) conn.send(stdout + stderr) except ConnectionResetError: break conn.close()server.close()-----------------------------客户端------------------------------import socketimport structimport jsonclient = socket.socket()client.connect(('127.0.0.1', 8081))while True: msg = input('>>>:').encode('utf-8') if len(msg) == 0: continue client.send(msg) header = client.recv(4) # 对这个头进行解包,获取真实数据的长度 head_len = struct.unpack('i', header)[0] head_dic = json.loads(client.recv(head_len).decode('utf-8')) print(head_dic) # 对需要接受的数据 进行循环接收 total_size = head_dic['len'] recv_size = 0 res = b'' while recv_size < total_size: data = client.recv(1024) res += data recv_size += len(data) print(res.decode('gbk'))
粘包问题
-----------------------------服务端------------------------------import socket"""服务端:要有固定的ip和port24小时不间断提供服务"""server = socket.socket()server.bind(('127.0.0.1', 8080))server.listen(5) # 半连接池while True: conn, addr = server.accept() # 阻塞 while True: try: data = conn.recv(1024) # 阻塞 if len(data) == 0: break # 针对linux和mac系统 客户端异常断开反复收空的情况 print(data) conn.send(data.upper()) except ConnectionResetError: break conn.close()server.close()-----------------------------客户端------------------------------import socketclient = socket.socket()client.connect(('127.0.0.1', 8080))while True: msg = input('>>>:').encode('utf-8') if len(msg) == 0: continue client.send(msg) data = client.recv(1024) print(data)
首先:只有在TCP协议中才会出现粘包现象,因为TCP协议是流式协议特点:TCP协议会将数据量小并且时间间隔比较短的数据一次性打包发送出去本质:其实还是因为我们不知道需要接收的数据的长短# 如何解决粘包问题?# 1 发送数据直接先告诉对方数据量的大小# 2 利用struct模块定制我们自己的消息传输协议
最终方法:解决粘包问题 1.先发报头 2.再发字典 3.再发你的真实数据 1.先收4个长度的报头 2.解包拿到字典数据长度 3.接收字典(反序列化) 》》》 获取字典里面所有信息 4.接收真实数据