1

我在服务器上工作,所有数据都是基于行的。我希望能够在一行超过给定长度时引发异常,而无需读取比我需要的更多数据。例如,客户端X发送的行长度为 16KB,即使行长度限制为 1024 字节。读取超过 1024 字节后,我想停止读取附加数据,关闭套接字并引发异常。我查看了文档和一些源代码,但如果不重写 _readline 方法,我看不到这样做的方法。有没有更简单的方法可以让我忽略?

编辑:评论让我意识到我需要添加更多信息。我知道我可以编写逻辑来执行此操作而无需太多工作,但我希望使用内置函数来利用 memoryview 的有效缓冲,而不是自己再次实现它或使用读取块、连接和拆分的幼稚方法根据需要没有记忆视图。

4

2 回答 2

2

我真的不喜欢接受不能真正回答问题的答案,所以这是我最终采用的方法,如果没有人有更好的解决方案,我只会标记它社区 wiki 或稍后未回答:

#!/usr/bin/env python3
class TheThing(object):
    def __init__(self, connection, maxlinelen=8192):
        self.connection = connection
        self.lines = self._iterlines()
        self.maxlinelen = maxlinelen

    def _iterlines(self):
        """
        Yield lines from class member socket object.
        """
        buffered = b''
        while True:
            received = self.connection.recv(4096)
            if not received:
                if buffered:
                    raise Exception("Unexpected EOF.")
                yield received
                continue

            elif buffered:
                received = buffered + received

            if b'\n' in received:
                for line in received.splitlines(True):
                    if line.endswith(b'\n'):
                        if len(line) > self.maxlinelen:
                            raise LineTooLong("Line size: %i" % len(line))
                        yield line
                    else:
                        buffered = line
            else:
                buffered += received

            if len(buffered) > self.maxlinelen:
                raise LineTooLong("Too much data in internal buffer.")

    def _readline(self):
        """
        Return next available line from member socket object.
        """
        return next(self.lines)

我没有费心比较代码来确定,但我做的连接和拆分更少,所以我认为我的可能更有效。

于 2012-07-02T23:01:18.297 回答
1

我意识到您的编辑正在澄清您想要的是实现目标的内置方法。但我不知道有任何东西可以帮助您对 readline 方法进行细粒度控制。但我想我可能只包括一个使用生成器和拆分进行编码方法的示例......只是为了好玩。

参考这个其他问题/答案以获得读取行的漂亮生成器:
https ://stackoverflow.com/a/822788/496445

基于该读者:

服务器.py

import socket

MAXLINE = 100

def linesplit(sock, maxline=0):
    buf = sock.recv(16)
    done = False
    while not done:
        # mid line check        
        if maxline and len(buf) > maxline:
            yield buf, True

        if "\n" in buf:
            (line, buf) = buf.split("\n", 1)
            err = maxline and len(line) > maxline
            yield line+"\n", err
        else:
            more = sock.recv(16)
            if not more:
                done = True
            else:
                buf = buf+more
    if buf:
        err = maxline and len(buf) > maxline
        yield buf, err


HOST = ''                
PORT = 50007             
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((HOST, PORT))
s.listen(1)
conn, addr = s.accept()
print 'Connected by', addr
for line, err in linesplit(conn, MAXLINE):
    if err:
        print "Error: Line greater than allowed length %d (got %d)" \
                % (MAXLINE, len(line))
        break
    else:
        print "Received data:", line.strip()
conn.close()

客户端.py

import socket
import time
import random

HOST = ''    
PORT = 50007             
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))
while True:
    val = 'x'*random.randint(1, 50)
    if random.random() > .5:
        val += "\n"
    s.sendall(val)
    time.sleep(.1)
s.close()

输出

Connected by ('127.0.0.1', 57912)
Received data: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Received data: xxxxxxxxxxxxxxxxxxxxxxxxxxxx
Received data: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
...
Received data: xxxxxxxxxxx
Received data: xxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Error: Line greater than allowed length 100 (got 102)

服务器读取它接收到的数据,并在组装后不断检查行的长度。如果在任何时候该行超过指定的数量,它会返回一个错误代码。我把它放在一起的速度很快,所以我确信可以进一步清理检查,并且可以更改读取缓冲区的数量,以解决您希望在消耗过多数据之前检测长行的速度。在上面的输出示例中,我只得到了比允许的多 2 个字节,并且它停止了。

客户端只是发送随机长度的数据,换行的 50/50 变化。

于 2012-07-01T05:47:33.287 回答