简体   繁体   English

如何正确处理 tcp stream 并在 python 中按行拆分?

[英]How to correctly handle tcp stream and split by lines in python?

I am using the code below to handle the date coming in from tcp connections.我正在使用下面的代码来处理来自 tcp 连接的日期。 But sometimes, on slower connections, the data is not correctly split into lines and i get handle_line() called with half of the line I want to deal with.但有时,在较慢的连接上,数据没有正确地分成几行,我用我想要处理的一半行调用了 handle_line()。 The second part of the line get called as next.该行的第二部分被称为下一个。 Any ideas how to solve this?任何想法如何解决这个问题? This is used for HTTP so each line is ending with \r\n.这用于 HTTP,因此每行都以 \r\n 结尾。

from io import BytesIO
import time
import logging
import errno
import threading
import socket
import os

def listener(client, address):
   try:
      with BytesIO() as buffer:
         while True:
            time.sleep(0.5) #slow down for low speed of data transmission to get fill lines, still does not solve
            resp = client.recv(1024)
            if not resp:
               logging.info('Connection closed by ' + str(address))
               break
            else:
               buffer.write(resp)          # Write to the BytesIO object
               buffer.seek(0)              # Set the file pointer to the SoF
               start_index = 0             # Count the number of characters processed
               for line in buffer:
                   start_index += len(line)
                   handle_line(client,line)       # Do something with your line
               if start_index:
                   buffer.seek(start_index)
                   remaining = buffer.read()
                   buffer.truncate(0)
                   buffer.seek(0)
                   buffer.write(remaining)
               else:
                   buffer.seek(0, 2)
   except IOError as e:
      if e.errno == errno.EPIPE:
         logging.warning(e)
      else:
         logging.warning(e)
   finally:
      client.close()


class nc(threading.Thread):
   def run(self):
      s = socket.socket()
      s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
      try:
         s.bind((tcp_host,tcp_port))
      except:
         logging.error('Can not bind address')
         os._exit(1)
      s.listen(1)
      th = []
      while True:
         client, address = s.accept()
         logging.info('Incoming connection from ' + str(address))
         th.append(threading.Thread(target=listener, args = (client,address)).start())
      s.close()


tcp_host = 'localhost'
tcp_port = 8080

server = nc()
server.daemon = True
server.start()

This is how TCP works.这就是 TCP 的工作原理。 If you want complete messages, buffer the data stream until you have a complete message and extract it from the buffer.如果你想要完整的消息,缓冲数据 stream 直到你有一个完整的消息并从缓冲区中提取它。 There is a built-in "file-like" wrapper to sockets that has a .readline() method that you can use. sockets 有一个内置的“类文件”包装器,它有一个可以使用的.readline()方法。 Also use with to automatically close the reader and client objects.也可以使用with来自动关闭阅读器和客户端对象。

Untested:未经测试:

def listener(client, address):
    with client, client.makefile('rb') as reader:
        try:
            while True:
                resp = reader.readline()
                if not resp:
                   logging.info('Connection closed by ' + str(address))
                   break
                handle_line(client,line)       # Do something with your line
        except IOError as e:
            if e.errno == errno.EPIPE:
                logging.warning(e)
            else:
                logging.warning(e)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM