tcp recv 如何判断数据传输结束
我没有找到较为明确的说明
参考博客:https://www.cnblogs.com/changzhendong/p/11419482.html
有人说在首部写入接下来的数据长度,这个也可以,但是也有限制,一般来说是用一个unsigned int,4个字节来表示报文的长度,但是如果4个字节放不下呢,也就是报文大小大于2^32-1个字节,就是说报文大于4GB时就会出问题,当然一般不会有这种问题,但是终究是可能会出现问题的。
有人说用一个特殊的报文来做结束,但是tcp传输中常常会把报文拼在一起(粘包问题),会导致你每次都要去匹配你的那个特殊报文,消耗估计也是不小的。
服务器启动,监听端口9999...
b'client1 data***************************************************************************************'
b'***************************************************************************************'
False
利用头部写入数据包大小的方法:
config:
from yacs.config import CfgNode as CN
config = CN()
config.server = CN()
config.server.port = 9999
config.server.ip = "127.0.0.1"
config.client = CN()
config.client.port = 8888
config.client.ip = "127.0.0.1"
server:
from socket import *
from config import config
import multiprocessing
import time
import struct
def server_listen():
HOST = config.server.ip
PORT = config.server.port
BUFFSIZE = 1024
ADDRESS = (HOST, PORT)
# 创建监听socket
tcpServerSocket = socket(AF_INET, SOCK_STREAM)
# 绑定IP地址和固定端口
tcpServerSocket.bind(ADDRESS)
print("服务器启动,监听端口{}...".format(ADDRESS[1]))
tcpServerSocket.listen(0)
process_list = []
try:
while True:
# print('服务器正在运行,等待客户端连接...')
# client_socket是专为这个客户端服务的socket,client_address是包含客户端IP和端口的元组
client_socket, client_address = tcpServerSocket.accept()
# print('客户端{}已连接!'.format(client_address))
p = multiprocessing.Process(target=server_accept, args=(client_socket, client_address)) # 参数与threading.Thread 一致,如果要传参数(args=(xxx))
p.daemon = True # 这个属性默认为False, 相当于主程序会等待子进程结束;设置True之后,子进程是一个后台进程
p.start()
process_list.append(p)
process_list_number = len(process_list)
i = 0
while i < process_list_number:
if process_list[i].is_alive() == False:
process_list.__delitem__(i)
i = 0
process_list_number = len(process_list)
else:
i += 1
# time.sleep(1)
finally:
# 关闭监听socket,不再响应其它客户端连接
for i in range(len(process_list)):
process_list[i].join()
tcpServerSocket.close()
def server_accept(client_socket, client_address):
BUFFSIZE = 2048
try:
while True:
# 接收客户端发来的数据,阻塞,直到有数据到来
# 事实上,除非当前客户端关闭后,才会跳转到外层的while循环,即一次只能服务一个客户
# 如果客户端关闭了连接,data是空字符串
recv_data = client_socket.recv(4)
if len(recv_data) == 0:
break
print(len(recv_data))
message_size = struct.unpack('i', recv_data)[0]
data = b''
while message_size > 0:
t_buffsize = BUFFSIZE
if message_size < BUFFSIZE:
t_buffsize = message_size
t_data = client_socket.recv(t_buffsize)
data = data + t_data
message_size -= len(t_data)
if len(data) > 0:
print('接收到消息 {}({} bytes) 来自 {}'.format(data.decode('utf-8'), len(data), client_address))
# 返回响应数据,将客户端发送来的数据原样返回
data = "ok"
data_encode = data.encode('utf-8')
# 发送数据
client_socket.sendall(struct.pack('i', len(data_encode)))
client_socket.sendall(data_encode)
else:
print('客户端 {} 已断开!'.format(client_address))
break
finally:
# 关闭为这个客户端服务的socket
client_socket.close()
if __name__ == '__main__':
server_listen()
client:
import time
from socket import *
from config import config
import multiprocessing
import json
import struct
def client(client_no):
HOST = config.server.ip
PORT = config.server.port
BUFFSIZE = 1024
ADDRESS = (HOST, PORT)
tcpClientSocket = socket(AF_INET, SOCK_STREAM)
try:
tcpClientSocket.connect(ADDRESS)
data = "client{0}".format(client_no)
data_encode = data.encode('utf-8')
# 发送数据
tcpClientSocket.sendall(struct.pack('i', len(data_encode)))
tcpClientSocket.sendall(data_encode)
# socket 不会发送长度为0的报文,因为许多代码在判断一个socket是否被客户端close掉了的时候会用报文的长度为0来判断。
# 接收数据
recv_data = tcpClientSocket.recv(4)
if len(recv_data) > 0:
message_size = struct.unpack('i', recv_data)[0]
data = b''
while message_size > 0:
t_buffsize = BUFFSIZE
if message_size < BUFFSIZE:
t_buffsize = message_size
t_data = tcpClientSocket.recv(t_buffsize)
data = data + t_data
message_size -= len(t_data)
if len(data) > 0:
print("服务器端响应:", data.decode('utf-8'))
except:
print("client connect failed!")
tcpClientSocket.close()
if __name__ == '__main__':
# process_list = []
#
# process_number = 10
# for i in range(process_number):
# p = multiprocessing.Process(target=client, args=(i,))
# p.start()
# process_list.append(p)
#
# for i in range(process_number):
# process_list[i].join()
# while 1:
# client(1)
# time.sleep(1)
client(1)