基于tcp协议的socket,客户端一次接受不完,下一次继续接受(若是间隔时间相对过长,后续的数据会与以前剩余的数据黏在一块儿),send数据时,连续的发送少许的数据(时间间隔很短),这些数据会积压在一块儿发送出去.python
每一个 socket 被建立后,都会分配两个缓冲区,输入缓冲区和输出缓冲区。程序员
write()/send() 并不当即向网络中传输数据,而是先将数据写入缓冲区中,再由TCP协议将数据从缓冲区发送到目标机器。一旦将数据写入到缓冲区,函数就能够成功返回,无论它们有没有到达目标机器,也无论它们什么时候被发送到网络,这些都是TCP协议负责的事情。shell
TCP协议独立于 write()/send() 函数,数据有可能刚被写入缓冲区就发送到网络,也可能在缓冲区中不断积压,屡次写入的数据被一次性发送到网络,这取决于当时的网络状况、当前线程是否空闲等诸多因素,不禁程序员控制。json
read()/recv() 函数也是如此,也从输入缓冲区中读取数据,而不是直接从网络中读取。网络
这些I/O缓冲区特性可整理以下:socket
1.I/O缓冲区在每一个TCP套接字中单独存在;
2.I/O缓冲区在建立套接字时自动生成;
3.即便关闭套接字也会继续传送输出缓冲区中遗留的数据;
4.关闭套接字将丢失输入缓冲区中的数据。tcp
服务端ide
import socket import subprocess import struct server_side = socket.socket() server_side.bind(("127.0.0.1", 8848)) server_side.listen(5) while 1: conn, addr = server_side.accept() while 1: try: cmd = conn.recv(1024) if cmd.decode("utf-8") == 'q': break obj = subprocess.Popen(cmd.decode("utf-8"), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, ) result = obj.stdout.read() + obj.stderr.read() # 制做报头 total_size = len(result) # 将不固定长度的int数据类型的报头,转化成固定长度的4bytes total_size_bytes = struct.pack("i", total_size) # 发送报头 conn.send(total_size_bytes) # 发送数据 conn.send(result) except ConnectionResetError: break conn.close() server_side.close()
客户端函数
import socket import struct client_side = socket.socket() client_side.connect(("127.0.0.1", 8848)) while 1: to_send = input("请输入你要执行的命令:") if to_send.upper() == "Q": client_side.send("q".encode("utf-8")) break client_side.send(to_send.encode("utf-8")) # 接收报头 head_bytes = client_side.recv(4) # 反解报头 total_size = struct.unpack("i", head_bytes)[0] # 循环接收数据 data = b"" while len(data) < total_size: data += client_side.recv(1024) print(data.decode("gbk")) client_side.close()
服务端线程
import socket import subprocess import json import struct phone = socket.socket() phone.bind(("127.0.0.1", 8848)) phone.listen(5) conn, addr = phone.accept() while 1: try: cmd = conn.recv(1024) obj = subprocess.Popen(cmd.decode("utf-8"), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE ) result = obj.stdout.read() + obj.stderr.read() result = result.decode("gbk").encode("utf-8") # 1.制做报头 head_dict = {"md5": "df", "file_name": "新建文件夹", "file_size": len(result)} # 2. 将报头字典转化成json字符串 head_dict_json = json.dumps(head_dict) # 3. 将json字符串转化成bytes head_dict_json_bytes = head_dict_json.encode("utf-8") # 4. 获取报头的长度 head_len = len(head_dict_json_bytes) # 5. 将报头长度转化成固定的4个bytes head_len_bytes = struct.pack("i", head_len) # 6. 发送固定的4个字节 conn.send(head_len_bytes) # 7. 发送报头 conn.send(head_dict_json_bytes) # 8. 发送原数据 conn.send(result) except ConnectionResetError: break conn.close() phone.close()
客户端
import socket import struct import json phone = socket.socket() phone.connect(("127.0.0.1", 8848)) while 1: cmd = input("请输入指令") phone.send(cmd.encode("utf-8")) # 1. 接收报头长度 head_len_bytes = phone.recv(4) # 2. 将报头数字转化成int类型 head_len = struct.unpack("i", head_len_bytes)[0] # 3. 接收bytes类型的报头字典 head_dict_json_bytes = phone.recv(head_len) # 4. 将bytes类型的字典转化成json字符串 head_dict_json = head_dict_json_bytes.decode("utf-8") # 5. 将json字符串转化成字典 head_dict = json.loads(head_dict_json) # 6. 循环接收原数据 total_data = b'' while len(total_data) < head_dict["file_size"]: total_data += phone.recv(1024) print(total_data.decode("utf-8")) phone.close