Различают между сообщениями python3 tcp сокеты - PullRequest
0 голосов
/ 23 октября 2018

Итак, я пытаюсь создать приложение, в котором пользовательский клиент будет отправлять сообщения на сервер.Я хочу найти способ различать одно сообщение от следующего, чтобы я мог перебрать sock.recv(1), пока не узнаю, что сообщение закончилось, и сохранить сообщение, а затем перейти к следующему сообщению.Я мог бы пойти по этому пути совсем неправильно, но я не уверен, как это сделать с потоками TCP.Прямо сейчас у меня есть только это для user.py

import socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect(("localhost", 1234))
while True:
    resp = someEventThatReturnsAMessage()
    if resp:
        resp += "|"
        sock.send(resp.encode('utf-8'))

и это для моего сервера

import socket, threading
class Client(threading.Thread):
    def __init__(self, conn):
        self.sock = conn
    def recv(self)
        msg = ''
        while True:
            try:
                l = self.sock.recv(1)
                if l.decode('utf-8') == "|":
                    return msg
                if l == b'':
                    return "Terminated"
                msg += l.decode("utf-8")
            except:
                return "Nothing to Receive"

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)   
sock.bind(('', 1234))
sock.listen(5)
while True:
    conn, addr = sock.accept()
    conn.setBlocking(0)
    threadedClient = Client(conn)

Дело в том, что если я когда-нибудь отправлю |, это все испортит.Я не знаю, что делать.

Ответы [ 2 ]

0 голосов
/ 24 октября 2018

Поскольку TCP является протоколом потоковой передачи байтов без границ сообщений, одним из решений является обертывание сокета на уровне протокола, который только отправляет и получает полные сообщения.Далее определяется сообщение как «байты в кодировке UTF-8, заканчивающиеся символом новой строки (\ n)»:

from socket import *

class Socket:
    def __init__(self,s=None):
        '''default create a new socket, or wrap an existing one.
        '''
        self.sock = socket() if s is None else s
        self.buffer = b''

    def connect(self,addr):
        self.sock.connect(addr)

    def bind(self,addr):
        self.sock.bind(addr)

    def listen(self,n):
        self.sock.listen(n)

    def accept(self):
        c,a = self.sock.accept()
        # Wrap the client socket in a Socket.
        return Socket(c),a

    def get_msg(self):
        # Buffer data until a newline is found.
        while b'\n' not in self.buffer:
            data = self.sock.recv(1024)
            if not data:
                return b''
            self.buffer += data
        # split off the message bytes from the buffer.
        msg,_,self.buffer = self.buffer.partition(b'\n')
        return msg.decode()

    def put_msg(self,msg):
        self.sock.sendall(msg.encode() + b'\n')

    def close(self):
        self.sock.close()

Используйте его следующим образом:

import threading
import time

From mysocket import Socket

def server():
    s = Socket()
    s.bind(('',8000))
    s.listen(5)

    while True:
        c,a = s.accept()
        print(f'server: {a[0]}:{a[1]} connected')
        while True:
            msg = c.get_msg()
            if not msg:
                break
            print(f'server: {msg}')
            c.put_msg(f'[{msg}]')
        print(f'server: {a[0]}:{a[1]} disconnected')
        c.close()

def client():
    s = Socket()
    s.connect(('localhost',8000))
    s.put_msg('Hello')
    s.put_msg('马克')
    print(f'client: {s.get_msg()}')
    print(f'client: {s.get_msg()}')
    s.close()

t = threading.Thread(target=server,daemon=True)
t.start()
client()

Вывод:

server: 127.0.0.1:1354 connected
server: Hello
server: 马克
client: [Hello]
client: [马克]
server: 127.0.0.1:1354 disconnected
0 голосов
/ 23 октября 2018

Чтение из потока по одному символу за раз будет довольно медленным.Можно попробовать отправить по одному сообщению за раз, а затем полностью прочитать поток на принимающей стороне перед отправкой другого сообщения.

Вот пример кода, на который вы можете сослаться:

def read_all_from_connection(self):
    def _read_entire_stream_chunked():
        while True:
            incremental_bytes = self.sock.recv(1024)
            if len(incremental_bytes) == 0:
                return
            yield incremental_bytes
    full_message = b""
    for partial_msg_bytes in _read_entire_stream_chunked():
        full_message += partial_msg_bytes
    self.sock.close()
    return full_message.decode("utf-8")

РЕДАКТИРОВАТЬ: Я не указал это явно, но эта стратегия будет читать одно сообщение для каждого соединения.Падение производительности должно быть незначительным, и может быть легче избежать полуоткрытых / зависших соединений.Если есть причины производительности для желания повторно использовать сокет между сообщениями, проверьте: https://websockets.readthedocs.io/en/stable/intro.html вместо.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...