socket套接字
Posted kbman
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了socket套接字相关的知识,希望对你有一定的参考价值。
什么是套接字?
- 一组接口
- 作用于应用层与传输层之间
- 隐藏了传输层下面复杂的TCP/IP协议的实现
基于TCP协议的socket
- 流式协议,面向流的通信是无消息保护边界的
- 会将数据少、时间间隔短的数据一次性打包发送
- 可靠但粘包
- 数据不会丢,包没收完,会继续上次继续接收数据
- 数据是可靠的
- 只有TCP有粘包现象
粘包问题:
产生原因:
- 发送的数据小,时间段,TCP会议会自动合成数据,造成粘包。(发送方的缓存机制)
- 接收数据只接收一部分,下次接收会继续上次接收数据。(接收方的缓存机制)
只发生在TCP协议。
问题的根源:
? 接收方不知道消息的大小
解决方案:
- 发送方提供数据大小
- 利用struct模块调用.pack将长度打包header报头发送
- 接收方利用struct调用.unpack解包header报头取出长度
案例:利用subprocess模拟终端命令输入
客户端 服务端:
1、连接服务 1、开启服务
2、发送命令 2、接收客户端命令
3、接收header报头 3、利用subprocess返回命令结果res
4、struct.unpack header报头得到字典长度 4、构造res数据的字典
5、利用字典长度接收字典 5、序列化字典,得出序列化后的字典长度
6、拿出字典里面真实数据长度 6、利用struct模块构造字典长度的header头
7、分段接收真实数据 7、发送header头
8、发送字典
9、发送真实数据
client.py:
import socket
import struct
import json
IP = '127.0.0.1'
PORT = 8001
client = socket.socket()
client.connect((IP, PORT))
while True:
cmd = input('>>>').strip()
client.send(cmd.encode('utf-8'))
# 接收字典报头
data = client.recv(4)
dict_size = struct.unpack('i', data)[0]
# 接收字典数据
dict_data = client.recv(dict_size)
dic = json.loads(dict_data.decode('utf-8'))
# 取出数据长度
file_size = dic.get('file_size')
#接收真实数据
recv_size = 0
real_data = b''
while recv_size < file_size:
data = client.recv(1024)
real_data += data
recv_size += len(data)
print(real_data.decode('utf-8'))
server.py
from socket import SOL_SOCKET, SO_REUSEADDR
import socket
import subprocess
import struct
import json
IP = '127.0.0.1'
PORT = 8001
server = socket.socket()
server.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
server.bind((IP, PORT))
server.listen(5)
while True:
conn, addr = server.accept()
while True:
try:
print('客户端地址:', addr)
cmd = conn.recv(1024)
obj = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
res = obj.stdout.read() + obj.stderr.read()
# 构造一个字典
dic = 'name': 'jason', 'file_size': len(res), 'info': 'great'
dump_dict = json.dumps(dic)
# 制作字典报头
header = struct.pack('i', len(dump_dict))
# 发送字典报头
conn.send(header)
# 发送字典
conn.send(dump_dict.encode('utf-8'))
# 发送真实数据
conn.send(res)
except ConnectionResetError as e:
break
conn.close()
以上是关于socket套接字的主要内容,如果未能解决你的问题,请参考以下文章