CSIC_716_20191205【TCP-解决粘包问题、UDP模板】
------------------------------------------------------------------------------------------------------------------------------------
客户端代码模板:(以ssh为例)
# _*_ coding: gbk _*_ # @Author: Wonder import socket import json import struct client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) client.connect(('172.16.10.19', 9527)) while True: try: cmd = input('>>>请输入指令').strip() if not cmd: continue if cmd == 'q': break cmd = cmd.encode('utf-8') dict_context = { 'data_size': len(cmd) # 二进制的长度 } client_bytes = json.dumps(dict_context).encode('utf-8') # dict----->json------->binary 报头 head = struct.pack('i', len(client_bytes)) # struct 将报头长度巧妙的转为4 bit # 以下为一波socket三连发送操作。 client.send(head) # 发报头长度, client.send(client_bytes) # 发报头,里面有实际数据的长度 client.send(cmd) # 传数据 bin_head = client.recv(4) # 接收来自server的报头信息 json_head_len = struct.unpack('i', bin_head)[0] # unpack 获取报文头长度 head_json = client.recv(json_head_len).decode() # 解码 获得 json格式的 报头字典 dic_head = json.loads(head_json) # 反序列化,得到 data的长度所在的字典 size = dic_head.get('data_size') # 取到data的真实长度值 length = 0 bin_toatal = b'' while length < size: bin_content = client.recv(500) bin_toatal += bin_content length += len(bin_content) # 此处要累加bin_content的长度 print('当前下载进度',size , length , length / size) print('当前下载进度---------------->', length / size) print(bin_toatal.decode('gbk'))
except Exception as e: print(e) break client.close()
服务端模板:
# _*_ coding: gbk _*_ # @Author: Wonder import socket import subprocess import json import struct server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server.bind(('172.16.10.180', 9527)) server.listen(3) while True: conn, addr = server.accept() while True: try: bin_head = conn.recv(4) # 获取4位长度的报文头 json_head = struct.unpack('i', bin_head)[0] # 获得报头长度--->int bin_head = conn.recv(json_head).decode('utf-8') # 获取报头信息 ------>binary----->JSON dic_head = json.loads(bin_head) # 反序列化得到字典 size = dic_head.get('data_size') # 字典取值得到数据长度 length = 0 bin_toatal = b'' while length < size: # if 循环接收,直到长度和报头中的长度一致 bin_content = conn.recv(50) bin_toatal += bin_content length += len(bin_toatal) cmd = bin_toatal.decode('utf-8') subprocess_obj = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout = subprocess_obj.stdout.read() # binary stderr = subprocess_obj.stderr.read() back_data_len = len(stderr) + len(stdout) print(back_data_len) server_dict = { 'data_size': back_data_len # 务必代表二进制的长度 } back_json = json.dumps(server_dict).encode('utf-8') # 序列化成 json字典 ------->json----->binary server_head = struct.pack('i', len(back_json)) # 转成4位长度的二进制, 表示报头长度 conn.send(server_head) # 发报头长度 conn.send(back_json) # 发报头 conn.send(stdout) # 发数据 conn.send(stderr) except Exception as e: print(e) break conn.close() server.close()
UDP的初级使用
UDP服务端(即时通讯,你一句我一句)
# _*_ coding: gbk _*_ # @Author: Wonder import socket # 指定是 数据报,type= 一定要写,不然报错 sk = socket.socket(type=socket.SOCK_DGRAM) sk.bind( ('127.0.0.1', 9527) ) while True: data, addr = sk.recvfrom(1024) print(data.decode('utf-8')) sk.sendto('永不在线'.encode('UTF-8'), addr)
客户端要绑定, 接收是recvfrom ,接收的是data和addr ,发送是sendto,发送的是data和目标addr
UDP客户端
# _*_ coding: gbk _*_ # @Author: Wonder import socket sk = socket.socket(type=socket.SOCK_DGRAM) addr = ('127.0.0.1', 9527) while True: msg = input('>>>输入内容') if msg == 'q': break sk.sendto(msg.encode('utf-8'), addr) data, back = sk.recvfrom(1024) print(data.decode('utf-8'))