Python TCP套接字:[Errno 10054]远程主机强制关闭现有连接

时间:2017-07-31 15:06:53

标签: python sockets tcp

我编写了一个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:]

0 个答案:

没有答案