2012-07-01 3 views
0

저는 서버에서 작업 중이며 모든 데이터는 라인 기반입니다. 내가 필요로하는 것보다 더 많은 데이터를 읽지 않고 라인이 주어진 길이를 초과 할 때 예외를 발생시킬 수 있기를 원한다. 예를 들어, 클라이언트 X은 줄 길이 제한이 1024 바이트이지만 16KB 길이의 줄을 보냅니다. 1024 바이트 이상을 읽은 후에는 추가 데이터를 읽지 않고 소켓을 닫고 예외를 발생 시키려고합니다. 워드 프로세서와 소스 코드 중 일부를 살펴 봤는데 _readline 메소드를 다시 작성하지 않으면이 작업을 수행 할 방법이 없습니다. 내가 간과하는 쉬운 방법이 있습니까?Python 소켓의 readline 길이 제한

편집 : 의견을 내게 더 많은 정보를 추가해야한다는 것을 알게되었습니다. 나는 많은 일을하지 않고이 일을 할 수있는 논리를 쓸 수 있다는 것을 알고 있지만 builtins를 사용하여 메모리 뷰를 효율적으로 버퍼링하는 대신 자체적으로 구현하거나 필요에 따라 청크 읽기, 결합 및 분할하는 순진한 접근 방식을 사용하기를 바랬다. 메모리 뷰없이.

+0

개행 문자가 발생할 때까지 바이트 읽기를 시도해 보셨습니까? 너무 많이 읽었습니까? – jdi

+0

줄 바꾸기 문자까지 읽는'readline' 대신 1024 바이트의 버퍼를 사용하여 읽어야합니다. –

+0

@AlexW 그 문제는'\ n'의 인덱스가 <1023 일 때 모든 경우의 데이터를 버퍼링해야한다는 것입니다. 그 시점에서 필자는 내부 버퍼링 로직을 다시 작성하려고합니다. 파이프 라이닝이나 효율적인 버퍼링을 무시하면 어쨌든이 작업을 수행 할 수 있습니다. –

답변

1

나는 당신의 편집이 당신이 원하는 것이 당신의 목표 달성을위한 기본 접근 방식임을 분명히하고 있음을 알고 있습니다. 그러나 나는 readline 접근에 대한 세심한 통제에서 당신을 도울 기존 존재에 대해 알지 못한다. 하지만 제 생각에는 발전기와 분할로 코드화 된 접근법을 수행하는 예제를 포함 할 수 있다고 생각했습니다.

참조 라인을 읽는 좋은 발전기이 다른 질문/대답 :

server.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 : 그 독자를 바탕으로
https://stackoverflow.com/a/822788/496445

,363,210
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 변경으로 임의의 길이의 데이터를 전송합니다.

1

나는 정말로 질문에 답하지 않는 대답을 받아들이는 것을 좋아하지 않으므로, 실제로 취하는 방법은 여기에있다. 나는 더 나은 해결책이 없다면 커뮤니티 위키에 표시하거나 대답하지 않을 것이다. :

#!/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) 

나는 확신하는 코드를 비교 귀찮게하지 않은,하지만 난 적은 회씩 연결 및 분할하고 있어요, 그래서 난 내보다 효율적으로 할 수있다 생각합니다.