Python 向所有客户端发送消息

Python 向所有客户端发送消息,python,python-3.x,sockets,server,Python,Python 3.x,Sockets,Server,这可能是一个非常简单的套接字消息交换编程,但由于我对套接字和其他方面的想法不充分,我无法使它真正正常工作,所以我寻求帮助 场景:两个客户端发送消息。第一个发送Halo和Seeya在第一个发送这些消息之后,第二个发送Hello和Bye(此客户端只需睡眠6秒即可保持此顺序)。对于所有消息,服务器会回复(原始消息),客户端(编号)和回复消息将广播到两个客户端 因此,理想情况下,两个客户端上的结果如下所示: Halo, client 1! Seeya, client 1! He

这可能是一个非常简单的套接字消息交换编程,但由于我对套接字和其他方面的想法不充分,我无法使它真正正常工作,所以我寻求帮助

场景:两个客户端发送消息。第一个发送
Halo
Seeya
在第一个发送这些消息之后,第二个发送
Hello
Bye
(此客户端只需睡眠6秒即可保持此顺序)。对于所有消息,服务器会回复
(原始消息),客户端(编号)和回复消息将广播到两个客户端

因此,理想情况下,两个客户端上的结果如下所示:

    Halo, client 1!
    Seeya, client 1!

    Hello, client 2!
    Bye, client 2 !
我无法为每个客户编号,但这是我的代码,工作起来很奇怪

服务器 客户1 client2-第一次连接,但等待消息顺序6秒 我得到的结果是

    # On client 1 side 
    Halo, client!                  # no Seeya, Hello, Bye
                                   # connection isn't closed

    # On client 2 side
    Hello, client!                 # no Seeya, Bye
    Halo, client!                  # connection is closed

这里有几个问题。第一个也是最主要的一个问题是,服务器的主循环出错了。每次通过循环时,服务器都希望
接受连接。因此,第一个连接的客户机被接受,并立即收到其第一条消息。但另一个客户端尚未被接受,因此不会收到第一条消息。然后,第二个客户端连接被接受,它的第一条消息被发送到两个客户端,但随后循环再次迭代,在第三个客户端连接之前,不会从服务器发送更多消息。等等

因此,您需要将接受连接和接收消息分开。这可以通过几种方式实现。最直接的方法是使用
select
功能一次等待多个套接字。也就是说,如果您有一个套接字列表,包括侦听套接字和以前接受的套接字,您可以执行以下操作:

# List starts with only listening socket
list_of_sockets = [lsock]
...
while True:
    # Wait until some socket becomes "readable"
    rfds, _wfds, _xfds = select.select(list_of_socks, [], [])
    for sock in rfds:
        if sock is lsock:
            # Listening socket ready. Accept new connection
            c, addr = lsock.accept()
            print(f"Accepted {c}")
            list_of_socks.append(c)
        else:
            msg = sock.recv(1024)
            if msg:
                # Received data from connected socket. Send to all
                print(f"Got {msg.decode()} from {sock}")
                broadcast(msg)
            else:
                # Got end of file (this client closed). Remove client from list
                print(f"Closed {sock}")
                list_of_socks.remove(sock)
上面的服务器代码无法解决您的代码的另一个问题:您不能假设您发送的每条消息都将作为一个独立的单元接收。也就是说,如果服务器发送“Halo”,然后在您(客户机)执行
recv
之前发送“Hello”,那么很可能所有数据都会一次性返回;那是“你好”

因此,通常需要在数据中放置某种分隔符(如换行符[
\n
]——但随后需要解析接收到的数据),或者最好在每条消息前面放置一个固定长度字段,给出后续可变长度部分的长度,这样您一次只能接收和处理一条消息。(在python中,这通常涉及使用
struct
模块的
pack
unpack
函数。)因此,您当前的客户端代码可能无法按照您的意愿对消息进行正确排序


此外,虽然不太可能引起问题,
send
:您不应该假设
send(N)
只发送
N
字节。它可能发送1、2、3或
N-1
字节。您可以使用
sendall
确保发送所有字节。

大量缺少的代码。提供一个复制问题的方法。
    ### here goes connection part ###

    time.sleep(6)               # waits for message order
    s.send(("Hello").encode())
    print(f"server = {(s.recv(1024)).decode()}")

    # I've tried adding socket closing/connection part here

    s.send(("Bye").encode())
    print((s.recv(1024)).decode())
    time.sleep(3)
    s.close()
    # On client 1 side 
    Halo, client!                  # no Seeya, Hello, Bye
                                   # connection isn't closed

    # On client 2 side
    Hello, client!                 # no Seeya, Bye
    Halo, client!                  # connection is closed
# List starts with only listening socket
list_of_sockets = [lsock]
...
while True:
    # Wait until some socket becomes "readable"
    rfds, _wfds, _xfds = select.select(list_of_socks, [], [])
    for sock in rfds:
        if sock is lsock:
            # Listening socket ready. Accept new connection
            c, addr = lsock.accept()
            print(f"Accepted {c}")
            list_of_socks.append(c)
        else:
            msg = sock.recv(1024)
            if msg:
                # Received data from connected socket. Send to all
                print(f"Got {msg.decode()} from {sock}")
                broadcast(msg)
            else:
                # Got end of file (this client closed). Remove client from list
                print(f"Closed {sock}")
                list_of_socks.remove(sock)