一、解决粘包问题的方法(简单版)
- 服务端
from socket import *
from subprocess import PIPE, Popen
import struct
server = socket(AF_INET, SOCK_STREAM)
server.bind(('127.0.0.1', 8000))
server.listen(5)
while True:
conn, client_addr = server.accept()
print(client_addr)
while True: # 通信循环
try:
cmd = conn.recv(8096)
if len(cmd) == 0: # 针对于linux系统
break
obj = Popen(cmd.decode('utf-8'),
shell=True,
stderr=PIPE,
stdout=PIPE, )
res1 = obj.stdout.read()
res2 = obj.stderr.read()
total_size = len(res1) + len(res2)
# 先把数据的长度给发过去,长度为4
header = struct.pack('i', total_size)
conn.send(header)
# 再发送真正的数据
conn.send(res2) # 利用TCP协议的特性
conn.send(res1) # nagle算法规定,TCP协议会将数据量较小、
# 时间间隔短的数据合并为一条发送给客户端
except Exception:
break
conn.close() # 异常断开后回收资源
- 客户端
from socket import *
from subprocess import PIPE, Popen
import struct
client = socket(AF_INET, SOCK_STREAM)
client.connect(('127.0.0.1', 8000))
while True:
cmd = input('>>>:').strip()
if len(cmd) == 0:
continue
client.send(cmd.encode('utf-8'))
# 先接收数据的长度
header = client.recv(4)
total_size = struct.unpack('i', header)[0] # 提取出字节长度
# 接收真正的数据
recv_size = 0
res = b''
while recv_size < total_size:
data = client.recv(1024)
recv_size += len(data)
res += data
print(res.decode('gbk'))
二、解决粘包问题的方法(优化版)
- 服务端
import json
from socket import *
import struct
from subprocess import PIPE, Popen
server = socket(AF_INET, SOCK_STREAM)
server.bind(('127.0.0.1', 8000))
server.listen(5)
while True: # 链接循环
conn, client_addr = server.accept()
print(client_addr)
while True: # 通信循环
try:
cmd = conn.recv(8096)
if len(cmd) == 0:
break
obj = Popen(cmd.decode('utf-8'),
shell=True,
stdout=PIPE,
stderr=PIPE)
res1 = obj.stdout.read()
res2 = obj.stderr.read()
header_dic = {
'filename': 'a.txt',
'total_size': len(res1) + len(res2),
'md5': 'qwe165qwqwe65456qw5'
}
header_json = json.dumps(header_dic)
header_bytes = header_json.encode('utf-8')
# 先发四个字节
conn.send(struct.pack('i', len(header_bytes)))
# 再发报头字典
conn.send(header_bytes)
# 最后发真正的数据
conn.send(res1)
conn.send(res2)
except Exception:
break
conn.close() # 关闭窗口来回收资源
- 客户端
from socket import *
import struct
import json
client = socket(AF_INET, SOCK_STREAM)
client.connect(('127.0.0.1', 8000))
while True:
cmd = input('>>>: ').strip()
if len(cmd) == 0:
continue
client.send(cmd.encode('utf-8'))
# 先接收四个字节,提取header_bytes的长度
header_bytes_len = struct.unpack('i', client.recv(4)[0])
# 再收header_bytes,提取header_dic
header_bytes = client.recv(header_bytes_len)
header_json = header_bytes.decode('utf-8')
header_dic = json.loads(header_json)
print(header_json)
total_size = header_dic['total_size']
# 再接收真正的数据
recv_size = 0
res = b''
while recv_size < total_size:
data = client.recv(1024)
recv_size += len(data)
res += data
print(res.decode('gbk'))
三、基于UDP套接字的编写
- 服务端
import socket
server = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # 造手机
server.bind(('127.0.0.1', 8000)) # 需要绑定,不许要监听
while True: # 通信循环
data, client_addr = server.recvfrom(1024)
# 解压赋值(文本,发送端的端口号)
print(data)
server.sendto(data.upper(), client_addr)
- 客户端
from socket import *
client = socket(AF_INET, SOCK_DGRAM) # 造手机
while True: # 输入循环
msg = input('输入:').strip()
client.sendto(msg.encode('utf8'), ('127.0.0.1', 8000))
# sendto(发送内容二进制,接收端口)
data, client_addr = client.recvfrom(1024)
# 解压赋值(接收的文本,端口)
print(data.decode('utf-8'))
- UDP协议一般不会用于大数据的传输
- UDP套接字虽然没有粘包的问题,但是不能代替TCP套接字,因为UDP协议有一个缺陷,如果数据发送的途中,数据丢失,则数据就丢失了,而TCP协议则不会有这种缺陷,因此一般的UDP套接字用户无关紧要的数据发送,例如QQ、微信聊天等.
四、socketserver模块
- 基本使用框架
import socketserver
class MyHandler(socketserver.BaseRequestHandler):
# 通信循环
def handle(self): # 调用的话以上不变
# data = self.request.recv(1024) # self.recv(1024)
# print(data)
# self.request.send(data.upper())
if __name__ == '__main__':
server = socketserver.ThreadingTCPServer(('127.0.0.1', 8080), MyHandler, bind_and_activate=True)
server.serve_forever()
- 多并发——服务端
# 同一时刻有多个人在接听
import socketserver
import json
from subprocess import Popen, PIPE
import struct
class MyHandler(socketserver.BaseRequestHandler):
# 通信循环
def handle(self): # 调用的话以上不变
# data = self.request.recv(1024) # self.recv(1024)
# print(data)
# self.request.send(data.upper())
try:
cmd = self.request.recv(8096)
obj = Popen(cmd.decode('utf-8'),
shell=True,
stdout=PIPE,
stderr=PIPE,
)
res1 = obj.stdout.read()
res2 = obj.stderr.read()
header_dic = {
'filename': "a.txt",
'total_size': len(res1) + len(res2),
'md5': '123dfsfsaf123213'
}
header_json = json.dumps(header_dic)
header_bytes = header_json.encode('utf-8')
# 先发4个字节
self.request.send(struct.pack('i', len(header_bytes)))
# 再发报头字典
self.request.send(header_bytes)
# 最后发送真正的数据
self.request.send(res1)
self.request.send(res2)
except Exception:
self.request.close()
# 使用socketserver的连接循环(并发),但是使用了自己的通信循环
if __name__ == '__main__':
server = socketserver.ThreadingTCPServer(('127.0.0.1', 8080), MyHandler, bind_and_activate=True)
server.serve_forever()
# 调用的话只需要将conn改成self.request即可
- 多并发——客户端1
from socket import *
import struct
import json
client = socket(AF_INET, SOCK_STREAM)
client.connect(('127.0.0.1', 8080))
while True:
cmd = input(">>>: ").strip()
if len(cmd) == 0:
continue
client.send(cmd.encode('utf-8'))
# 先收4个字节,提取header_bytes的长度
header_bytes_len = struct.unpack('i', client.recv(4))[0]
# 再收header_bytes,提取header_dic
header_bytes = client.recv(header_bytes_len)
header_json = header_bytes.decode('utf-8')
header_dic = json.loads(header_json)
print(header_dic)
total_size = header_dic['total_size']
# 再接收真正的数据
recv_size = 0
res = b''
while recv_size < total_size:
data = client.recv(1024)
recv_size += len(data)
res += data
print(res.decode('gbk'))
- 多并发——客户端2
from socket import *
import struct
import json
client = socket(AF_INET, SOCK_STREAM)
client.connect(('127.0.0.1', 8080))
while True:
cmd = input(">>>: ").strip()
if len(cmd) == 0:
continue
client.send(cmd.encode('utf-8'))
# 先收4个字节,提取header_bytes的长度
header_bytes_len = struct.unpack('i', client.recv(4))[0]
# 再收header_bytes,提取header_dic
header_bytes = client.recv(header_bytes_len)
header_json = header_bytes.decode('utf-8')
header_dic = json.loads(header_json)
print(header_dic)
total_size = header_dic['total_size']
# 再接收真正的数据
recv_size = 0
res = b''
while recv_size < total_size:
data = client.recv(1024)
recv_size += len(data)
res += data
print(res.decode('gbk'))