Python 中的套接字与 Ubuntu

Socket in Python with Ubuntu

提问人:XLC 提问时间:11/17/2023 最后编辑:XLC 更新时间:11/17/2023 访问量:43

问:

我正在使用 Python Socket 来实现 Ubuntu Server 中两个本地进程之间的交互。发生了一些奇怪的事情。当我在 Mac (i7) 中本地运行这两个进程时,它们在 1 秒内快速运行。但是,当我在 Ubuntu Server 中运行它们时,它的成本超过 30 秒。

我认为 TCP 在 Send() 和 Recv() 之间被阻塞了。当我只是让服务器发送和客户端接收消息时。然后,这些进程也可以在 1 秒内运行。所以我想知道发生了什么,是否有可能修复它。非常感谢!

这是代码

服务器:

if __name__=='__main__':
    server1 = ServerSocket("127.0.0.1", 4321)
    server1._conn_client() 
    print("xxx");

    start_time = time.time()
    for i in range(10000):
        server1.Recv()
        server1.Send("hello") ## delete this row to disable the server to send messages
        print(i)
    end_time = time.time()
    print("Server time:", end_time - start_time)

    server1.Send("hello")
    msg = server1.Recv()
    print("hi:", msg)
    server1.close()

客户:

if __name__ == '__main__':
    client = ClientSocket("127.0.0.1", 4321)
    client.Connect()
    print("xxx");

    start = time.time()
    for i in range(10000):
        client.Send("hello from client1")
        client.Recv() ## delete this to disable the cleint to receive messages
    end = time.time()
    print("Client time:", end - start)

    msg =client.Recv()
    print(msg)
    client.Send("hello from client1")
    client.close()

从其他套接字定义的函数:

class ServerSocket(object):
    def __init__(self, ip="127.0.0.1", port=7778):
        self.ip = ip
        self.port = port
        self._buffer_size = 80000
        self._init_socket()
        self._socket.settimeout(3000)

    def _init_socket(self):
        self._socket = socket.socket()
        ip_port = (self.ip, self.port)
        self._socket.bind(ip_port)

    def _conn_client(self):
        self._socket.listen(100)
        self._client_socket, addr = self._socket.accept()
        self._client_socket.settimeout(3000)

    def Recv(self):
        msg_len_pack = self._client_socket.recv(4)
        # print(struct.unpack('i', msg_len_pack))
        msg_len = struct.unpack('i', msg_len_pack)[0]
        # print("msg_len:", msg_len, "buffer:", self._buffer_size)
        if msg_len < self._buffer_size:
            msg_pack = self._client_socket.recv(msg_len)
            msg = json.loads(msg_pack.decode('utf-8'))
        return msg


    def Send(self,data):
        msg_pack = json.dumps(data).encode('utf-8')
        msg_len_pack = struct.pack('i', len(msg_pack))
        self._client_socket.send(msg_len_pack)
        self._client_socket.send(msg_pack) 

    def close(self):
        self._client_socket.close()

class ClientSocket(object):
    def __init__(self, ip="127.0.0.1", port=7778):
        self.ip = ip  
        self.port = port  
        self._buffer_size = 80000 

    def Connect(self):
        self._socket = socket.socket()  
        self._socket.connect((self.ip,self.port)) 

    def Send(self, data):
        msg_pack = json.dumps(data).encode('utf-8')
        msg_len_pack = struct.pack('i', len(msg_pack))
        self._socket.send(msg_len_pack)
        self._socket.send(msg_pack) 

    def Recv(self):
        msg_len_pack = self._socket.recv(4) 
        msg_len = struct.unpack('i', msg_len_pack)[0]
        if msg_len < self._buffer_size:
            msg_pack = self._socket.recv(msg_len)
            msg = json.loads(msg_pack.decode('utf-8'))
        return msg


    def close(self):
        self._socket.close()
python 套接字 ubuntu

评论

0赞 AKX 11/17/2023
FWIW,真的不需要那么不同——你真的想要和免费功能。这件事也没有多大意义——如果消息更长怎么办?那你根本不读它?ClientSocketServerSocketsend_message(socket, message)receive_message(socket)_buffer_size
0赞 XLC 11/17/2023
谢谢。首先,我同意他们不需要不同。其次,我之所以使用这个值,是因为测试中的消息不长。我尝试了一些更大的尺寸,但它们没有解决我的问题。
0赞 AKX 11/17/2023
是的,但你根本不需要它。
0赞 XLC 11/17/2023
当然,我会让他们变得更好。但现在,我真的很想知道是什么导致了 Ubuntu 的延迟。
0赞 mayosten 11/18/2023
嗨,欢迎!这是一个非常具有挑战性的问题,因为它涉及本地网络环境,作为审阅者进行复制将极具挑战性。祝你好运!

答:

-1赞 Tricotou 11/17/2023 #1

巨大的延迟来自您的优化:D 啊哈,开个玩笑,我理解你使用 struct 发送超过 4 个字节的 msg 大小的意愿,然后发送完整的 msg,而接收者等待确切的 msg 长度,等等......但在你的情况下,这是一个“错误”的优化。只需坚持默认缓冲区大小,如 1024 或 4096 或任何 2 的幂,不要太大,也不要太小。

然后处理它:你仍然可以发送JSON数据来提供有关未来的信息,关于下一个“大消息”的信息,这将是4 GB或其他什么,它将通过多个套接字数据包发送,仅此而已

另外,让我们避免在相同时将代码加倍,在您的情况下,可以完成单个类:

class Socket(object):
    def __init__(self, ip="127.0.0.1", port=7778, buffer=1024, is_server=False):
        self.buffer = buffer
        if is_server:
            self._socket = socket.socket()
            self._socket.bind((ip, port))
            self._socket.listen()
            self._connected_socket, addr = self._socket.accept()
        else:
            self._connected_socket = socket.socket()
            self._connected_socket.connect((ip, port))

    def Recv(self):
        msg_pack = self._connected_socket.recv(self.buffer)
        msg = json.loads(msg_pack.decode('utf-8'))
        return msg

    def Send(self, data):
        msg_pack = json.dumps(data).encode('utf-8')
        self._connected_socket.send(msg_pack)

    def close(self):
        self._connected_socket.close()

然后你只需为客户端实例化一种不同的方式:

if __name__ == '__main__':
    client = Socket(port=4321)
    print("xxx");

    start = time.time()
    for i in range(10000):
        client.Send("hello from client1")
        client.Recv()
    end = time.time()
    print("Client time:", end - start)

    msg = client.Recv()
    print(msg)
    client.Send("hello from client1")
    client.close()

对于服务器:

if __name__=='__main__':
    server1 = Socket(port=4321, is_server=True)
    print("xxx");

    start_time = time.time()
    for i in range(10000):
        server1.Recv()
        server1.Send("hello")
        print(i)
    end_time = time.time()
    print("Server time:", end_time - start_time)

    server1.Send("hello")
    msg = server1.Recv()
    print("hi:", msg)
    server1.close()

在 Ubuntu 上,超过 10 000 次的循环总共不到 0.3 秒,包括我猜大部分时间的打印......

评论

0赞 XLC 11/24/2023
你好!很抱歉,由于工作繁忙,回复晚了。我尝试了您的代码,它有效!多谢!这是非常有帮助的!