Python TCP套接字数据有时缺少部件。套接字溢出?

时间:2016-02-23 22:01:45

标签: python python-2.7 sockets tcp buffer-overflow

简短说明:

客户端通过TCP套接字发送服务器数据。数据长度不一,字符串由分隔符“~~~ * ~~~”

分解

在大多数情况下,它工作正常。一阵子。几分钟后,数据遍布整个地方。所以我开始跟踪问题,数据最终在错误的地方,因为还没有通过。

所有内容都进入服务器脚本,并由不同的分隔符 -New Data- *解析,然后放入队列中。这是代码:

是的我知道缓冲区大小很大。不,我不会一次性发送那种大小的数据,但我一直在玩它。

class service(SocketServer.BaseRequestHandler):
    def handle(self):
        data = 'dummy'

        #print "Client connected with ", self.client_address
        while len(data):
            data = self.request.recv(163840000)
            #print data
            BigSocketParse = []
            BigSocketParse = data.split('*-New*Data-*')

            print "Putting data in queue"
            for eachmatch in BigSocketParse:
                #print eachmatch
                q.put(str(eachmatch))

            #print data
            #self.request.send(data)

        #print "Client exited"
        self.request.close()


class ThreadedTCPServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer):
    pass

t = ThreadedTCPServer(('',500), service)
t.serve_forever()

然后我运行了一个线程而不是q.empty():它通过另一个分隔符解析数据“~~~ * ~~~”

所以这有效一段时间了。我正在发送的数据类型的一个示例:

2016-02-23 18:01:24.140000~~~*~~~Snowboarding~~~*~~~Blue Hills~~~*~~~Powder 42
~~~*~~~Board Rental~~~*~~~15.0~~~*~~~1~~~*~~~http://bigshoes.com
~~~*~~~No Wax~~~*~~~50.00~~~*~~~No Ramps~~~*~~~2016-02-23 19:45:00.000000~~~*~~~-15

但事情开始破裂。所以我拿了一些控制数据并将其发送到循环中。会工作一段时间然后结果开始在错误的地方结束。这出现在我的队列中:

2016-02-23 18:01:24.140000~~~*~~~Snowboarding~~~*~~~Blue Hills~~~*~~~Powder 42
~~~*~~~Board Rental~~~*~~~15.0~~~*~~~1~~~*~~~http://bigshoes.com
~~~*~~~No Wax~~~*~~~50.00~~~*~~~No Ramps~~~*~~~2016-02-23 19:45:00.000000~~~*~

删掉最后一个“~~ -15”。

所以完全相同的数据然后才会起作用。这表明我有些溢出。

客户端连接如下:

class Connect(object):

    def connect(self):
        host = socket.gethostname() # Get local machine name
        #host = "127.0.0.1"
        port = 500                # Reserve a port for your service.
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        #print('connecting to host')
        sock.connect((host, port))
        return sock

    def send(self, command):
        sock = self.connect()
        #recv_data = ""
        #data = True

        #print('sending: ' + command)
        sock.sendall(command)
        sock.close()
        return

它不会等待回应,因为我不希望它等待一个回应。但是它会关闭套接字并且(据我所知)我不需要刷新套接字缓冲区,也不需要在连接关闭时自行清除它。

真的很感激这方面的任何帮助。在这一点上,这让我有点闲暇。

更新

我在我的本地计算机和非常强大的服务器上运行它,我会被迫相信这是一个硬件问题。服务器/客户端都在本地运行,套接字用作它们进行通信的一种方式,所以我不认为延迟是原因。

我一直在阅读TCP通信的问题。我觉得我很快就会失去深度的一个区域,但我开始怀疑这不是一个溢出而只是一些拥挤的国王。

如果客户端上的sendall不能确保发送所有内容,可能会在服务器端进行某种定时器/检查,以确保不会再发生任何事情。

2 个答案:

答案 0 :(得分:3)

基本问题是你的:

data = self.request.recv(163840000)

保证一次接收所有数据(无论你制作缓冲区有多大)。

为了正常运行,您必须处理一次无法获取所有数据的情况(您需要跟踪您的位置并附加到其中)。请参阅Python docs on using a socket中的相关示例:

  

现在我们来到套接字的主要障碍 - 发送和recv在网络缓冲区上运行。它们不一定处理你所处理的所有字节(或期望它们),因为它们主要关注的是处理网络缓冲区。通常,它们在关联的网络缓冲区已填充(发送)或清空(recv)时返回。然后他们告诉你他们处理了多少字节。在您的信息完全处理完毕之前,您有责任再次致电他们。

答案 1 :(得分:2)

如上所述,即使您有大的缓冲区大小,也没有收到完整的消息。你需要保持接收,直到你得到零字节。您可以编写自己的生成器来获取request对象并生成部件。好的一面是你可以开始处理消息,而有些仍在进入

def recvblocks(request):
    buf = ''
    while 1:
        newdata = request.recv(10000)
        if not newdata:
            if buf:
                yield buf
            return
        buf += newdata
        parts = buf.split('*-New*Data-*')
        buf = parts.pop()
        for part in parts:
            yield part

但是你也需要修复你的客户端。您需要在关闭真正关闭TCP连接之前关闭套接字

    sock.sendall(command)
    sock.shutdown(request.SHUT_RDWR)
    sock.close()