1

私はサーバーで作業しており、すべてのデータは行ベースです。必要以上のデータを読み取ることなく、行が特定の長さを超えたときに例外を発生させたいと考えています。たとえば、行の長さの制限が 1024 バイトであっても、クライアントXは 16KB の長さの行を送信します。1024 バイトを超えて読み取った後、追加のデータの読み取りを停止し、ソケットを閉じて例外を発生させたいと考えています。ドキュメントとソース コードの一部を調べましたが、_readline メソッドを書き換えずにこれを行う方法がわかりません。私が見落としている簡単な方法はありますか?

編集:コメントにより、さらに情報を追加する必要があることに気づきました。これを行うためのロジックを書くことはあまり手間をかけずにできることはわかっていますが、自分で再度実装したり、必要に応じてチャンクを読み取ったり、結合したり、分割したりする単純なアプローチを採用するのではなく、ビルトインを使用してメモリビューによる効率的なバッファリングを利用したいと考えていました。メモリビューなし。

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()

client.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 に答える