区分消息python3 tcp套接字

时间:2018-10-23 14:13:34

标签: python python-3.x sockets tcp

因此,我正在尝试开发一个应用程序,以便用户客户端将消息发送到服务器。我想找到一种区分一条消息和另一条消息的方法,这样我就可以遍历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 :(得分:1)

从流中一次读取一个字符将非常慢。您可以尝试的方法是一次发送一条消息,然后在发送另一条消息之前在接收端完全读取流。

这是您可以参考的一些示例代码:

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

答案 1 :(得分:1)

由于TCP是一种无消息边界的字节流协议,因此一种解决方案是将套接字包装在仅发送和接收完整消息的协议层中。以下内容将消息定义为“以换行符(\ n)字符结尾的UTF-8编码字节”:

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