目录python
什么是粘包问题呢?shell
在咱们写 tcp socket编程的时候,tcp协议是一个流式的协议,服务端第一次发送的数据,客户端没法准确一次性的接收完毕,下一次发送的数据与上一次数据粘在一块儿。编程
即:sass
一、 没法预测对方须要接收的数据大小长度安全
二、 屡次连续发送数据量小的,而且时间间隔短的数据 会一次性打包一块儿发送服务器
TCP 协议的特性:socket
会将屡次连续发送的数据量小的,而且时间间隔短的数据一次性发送完毕tcp
咱们用subprocess 模块来演示一个粘包问题。code
# 服务端 # coding=utf-8 import socket import subprocess server = socket.socket() address = ("127.0.0.1",8888) server.bind(address) server.listen(5) while True: conn , addr = server.accept() while True: try: cmd = conn.recv(1024).decode("utf-8") print(cmd) if cmd == "q": break obj = subprocess.Popen( cmd,shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE ) res = obj.stdout.read() + obj.stderr.read() conn.send(res) except Exception: break conn.close()
# 客户端 # coding=utf-8 import socket client = socket.socket() address = ("127.0.0.1",8888) client.connect(address) while True: cmd = input("请输入>>>") client.send(cmd.encode("utf-8")) if cmd == "q": break data = client.recv(1024) print(data.decode("gbk")) client.close()
终端打印结果server
请输入>>>tasklist 映像名称 PID 会话名 会话# 内存使用 ========================= ======== ================ =========== ============ System Idle Process 0 Services 0 24 K System 4 Services 0 3,172 K smss.exe 352 Services 0 1,200 K csrss.exe 464 Services 0 6,656 K wininit.exe 572 Services 0 5,168 K csrss.exe 588 Console 1 77,948 K services.exe 636 Services 0 12,288 K lsass.exe 652 Services 0 11,164 K lsm.exe 660 Services 0 4,664 K winlogon.exe 744 Console 1 8,180 K svchost.exe 812 Services 0 10,040 K svchost. 请输入>>>dir exe 892 Services 0 8,280 K svchost.exe 980 Services 0 21,744 K svchost.exe 168 Services 0 21,060 K svchost.exe 388 Services 0 40,792 K svchost.exe 908 Services 0 12,252 K WUDFHost.exe 1100 Services 0 8,096 K ZhuDongFangYu.exe 1188 Services 0 23,784 K svchost.exe 1236 Services 0 17,532 K wlanext.exe 1412 Services 0 5,268 K conhost.exe 1420 Services 0 2,860 K dwm.exe 1536 Console 1 38,436 K explorer.exe 1588 Console 1 70,028 K spoolsv.exe 1612 Services 0 12,204 K svchost.exe
咱们看到在输完tasklist 命令以后,再次输入其余命令,仍是上次命令的结果,
那么久证实了 服务端第一次发送的数据,客户端没法准确一次性的接收完毕,下一次发送的数据与上一次数据粘在一块儿。咱们在客户端接收的时候,接收的数据大小是1024个字节,服务器执行结果 超出了接收的大小,因此至关于把结果堆到了后面,一块儿发送,因此下次执行命令得不到正确的结果,那么咱们须要解决这个问题就须要用到 struct 模块
struct 模块必须先定义报头,,先发送报头,再发送真实数据
# 服务端 # coding=utf-8 import struct import socket import subprocess server = socket.socket() address = ("127.0.0.1",8888) server.bind(address) server.listen(5) while True: conn,addr = server.accept() while True: try: cmd = conn.recv(1024).decode("utf-8") print(cmd) if cmd == "q": break obj = subprocess.Popen( cmd ,shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE ) res = obj.stdout.read() + obj.stderr.read() # 将执行结果计算长度用i模式打包 res_len = struct.pack("i",len(res)) # 先发送数据长度 conn.send(res_len) # 再发送真实数据 conn.send(res) except Exception: break conn.close()
# 客户端 # coding=utf-8 import socket import struct client = socket.socket() address = ("127.0.0.1",8888) client.connect(address) while True: cmd = input("请输入命令>>>") client.send(cmd.encode("utf-8")) if cmd == "q": break # 用struct模块接收的长度统一是4个字节, head = client.recv(4) # 而后用struct模块解包获得数据的真实长度,返回的是元组类型,0表示第一个元素,就是真实长度 data_len = struct.unpack("i",head)[0] # 而后再把真实长度接收便可。 data = client.recv(data_len) print(data.decode("gbk")) client.close()
udp也是一种传输协议
1)不须要创建双向通道
2)不会粘包
3)客户端给服务端发送数据,不须要等待服务端返回接收成功
4)数据容易丢失,数据不安全。
TCP:就至关于与在打电话
UDP:就至关于与在发短信
# 服务端 # coding=utf-8 import socket server = socket.socket(type=socket.SOCK_DGRAM) address = ("127.0.0.1",8888) server.bind(address) while True: msg,addr = server.recvfrom(1024) print(msg.decode("utf-8")) # 服务端往客户端发送消息 send_msg = input("服务端发送消息") server.sendto(send_msg.encode("utf-8"),addr)
# 客户端 # coding=utf-8 import socket client = socket.socket(type=socket.SOCK_DGRAM) address = ("127.0.0.1",8888) while True: send_msg = input("请输入信息") client.sendto(send_msg.encode("utf-8"),address) data = client.recv(1024) print(data.decode("utf-8"))