我编写了一个python脚本,通过TCP连接执行文件传输。 每三或四次启动程序(有时更频繁),都会发生错误,并显示消息:“[Errno 10054]远程主机强行关闭现有连接”。服务器端发生错误,客户端发送所有数据并关闭几秒钟后。为什么客户端在服务器收到所有字节之前关闭连接? TCP协议不可靠吗?客户端应该等待接收每个段的ACK。当我使用Wireshark捕获数据包时,我得到一堆消息:'Tcp Spurious Retransmission','TCP ACKed unseen segment',最后,RST标志由客户端发送。服务器侦听localhost:12000时不会发生此问题。我知道我可以使用HTTP来达到这个目的,但我想尝试自己编写代码。
这是我的代码:
#Server.py
from message import message
from socket import *
interface = '...'
port = 12000
serverSocket = socket(AF_INET, SOCK_STREAM)
serverSocket.bind((interface, port))
serverSocket.listen(1)
connectionSocket, addr = serverSocket.accept()
msg = message(connectionSocket)
msg.recv()
print 'Header:'
for key, value in msg.getHeader().iteritems():
print '\t' + key + ': ' + value
f = open('out.pdf', 'wb')
f.write(msg.getData())
f.close()
connectionSocket.shutdown(SHUT_WR)
connectionSocket.close()
serverSocket.close()
#Client.py
from message import message
from socket import *
host = '...'
port = 12000
f = open('in.pdf', 'rb')
data = f.read()
f.close()
clientSocket = socket(AF_INET, SOCK_STREAM)
clientSocket.connect((host, port))
msg = message(clientSocket)
msg.send(data)
clientSocket.shutdown(SHUT_WR)
clientSocket.close()
#message.py
import socket
### This class encapsulates a protocol message exchanged by two end-users on the Internet.
#Structure of message:
#header
#field: value
#...
#field: value
#
#data
# ...
# ...
#Supported fields:
#size - size of data in bytes (required)
class message:
CHUNK_SIZE = 65536 #64KB
def __init__(self, sock, dataSeparator = '\n\n', fieldSeparator = '\n', fieldValueSeparator = ':'):
self.__sock = sock
self.__dataSeparator = dataSeparator
self.__fieldSeparator = fieldSeparator
self.__fieldValueSeparator = fieldValueSeparator
#public methods
def recv(self):
#init data
self.__data = ''
self.__header = dict()
self.__junkData = ''
self.__getHeader()
dataSize = int(self.__header['size'])
self.__getData(dataSize)
def send(self, msg, header = dict()):
#init data
self.__data = ''
self.__header = header
self.__header['size'] = str(len(msg))
#join header and message
i = 0
headerLen = len(self.__header)
for key, value in self.__header.iteritems():
i = i + 1
self.__data += key + self.__fieldValueSeparator + value
if i < headerLen:
self.__data += self.__fieldSeparator
self.__data += self.__dataSeparator + msg
total_sent = 0
size = len(self.__data)
while total_sent < size:
sent = self.__sock.send(self.__data[total_sent:total_sent + message.CHUNK_SIZE])
total_sent += sent
if sent == 0:
raise IOError('Connection problem.')
def getHeader(self):
return self.__header
def getData(self):
return self.__data
def getJunkData(self):
return self.__junkData
#private methods
def __getHeader(self):
tmp = ''
while True:
chunk = self.__sock.recv(message.CHUNK_SIZE)
if not chunk:
raise IOError('Connection problem.')
tmp += chunk
if self.__dataSeparator in tmp:
pos = tmp.find(self.__dataSeparator)
headerData = tmp[:pos]
#parse header data
for line in headerData.split(self.__fieldSeparator):
parts = line.split(self.__fieldValueSeparator)
if len(parts) != 2:
raise AttributeError('Incorrect attribute format.')
self.__header[parts[0].strip()] = parts[1].strip()
if 'size' not in self.__header: #size field is required
raise AttributeError('Field \'size\' is required.')
size = int(self.__header['size'])
self.__data = tmp[pos + 2:pos + 2 + size]
self.__junkData = tmp[pos + 2 + size:]
break
def __getData(self, size):
total = len(self.__data)
diff = size - total
chunk = ''
while total < size:
chunk = self.__sock.recv(message.CHUNK_SIZE)
if not chunk:
raise IOError('Connection problem.')
diff = size - total
self.__data += chunk[:diff]
total += min(diff, len(chunk))
print 'chunk len: ' + str(len(chunk)) + ', diff: ' + str(diff) + ', total: ' + str(total) + ', size: ' + str(size)
#print str(total) + '/' + str(size)
self.__junkData += chunk[diff:]