服务器只侦听来自第一个要连接的套接字的消息,即使它被设置为非阻塞,它也不会在它不接收数据时跳过它。我是网络新手,这是我的第一个项目,如果有人知道任何其他适合初学者的人请告诉我。谢谢!这是代码。
import socket
CONNECTED_SENDERS = []
CONNECTED_LISTENERS = []
def Main():
HOST = socket.gethostname()
PORT = 4444
SERVER_SOCKET = socket.socket()
SERVER_SOCKET.bind((HOST, PORT))
SERVER_SOCKET.listen(1)
for i in range(2):
CONNECTION, ADDRESS = SERVER_SOCKET.accept()
CONNECTED_LISTENERS.append(CONNECTION)
for i in range(2):
CONNECTION, ADDRESS = SERVER_SOCKET.accept()
CONNECTED_SENDERS.append(CONNECTION)
for DEVICE in CONNECTED_LISTENERS:
DEVICE.send(b'SERVER: You have succesfully connected.')
DEVICE.send(b'SERVER: Please wait for permission to talk.')
x = 0
for DEVICE in CONNECTED_LISTENERS:
DEVICE.send(b'SERVER: What is your name?')
Name = CONNECTED_SENDERS[x].recv(1024)
CONNECTED_LISTENERS[x] = (CONNECTED_LISTENERS[x], Name)
x += 1
del x, Name
for DEVICE, _ in CONNECTED_LISTENERS:
DEVICE.send(b'SERVER: You may now talk.')
SERVER_SOCKET.setblocking(0)
LEAVE = False
while LEAVE == False:
try:
MESSAGE = CONNECTED_SENDERS[0].recv(1024)
NAME = CONNECTED_LISTENERS[0][1]
for DEVICE, _ in CONNECTED_LISTENERS:
DEVICE.send(NAME + b': ' + MESSAGE)
if MESSAGE == 'QUIT':
LEAVE = True
except:
try:
MESSAGE = CONNECTED_SENDERS[1].recv(1024)
NAME = CONNECTED_LISTENERS[1][1]
for DEVICE, _ in CONNECTED_LISTENERS:
DEVICE.send(NAME + b': ' + MESSAGE)
if MESSAGE == 'QUIT':
LEAVE = True
except:
pass
for CONNECTION in CONNECTED_LISTENERS:
CONNECTION.close()
for CONNECTION in CONNECTED_SENDERS:
CONNECTION.close()
if __name__ == "__main__":
Main()
答案 0 :(得分:1)
您的代码存在许多问题,有些是小问题,有些是大问题。但主要问题是您将服务器套接字标记为非阻塞,而不是任何进行通信的套接字。
在标准TCP套接字编程中,您设置一个侦听传入连接的服务器。当该服务器接受新客户端时,将返回 new 套接字,并且在此新套接字上将发生与远程客户端的所有通信。换句话说,服务器套接字仅用于接受新连接,而不是其他任何东西。您永远不会通过服务器套接字写入数据。
因此SERVER_SOCKET
被标记为非阻塞并不重要,您必须执行以下操作:
conn, addr = server.accept()
conn.setblocking(False)
conn
是您与客户端通信的新套接字,可以非阻塞方式使用。
我还应该指出你打电话给SERVER_SOCKET.listen(1)
。 1
的参数意味着服务器只有来自一个客户端的等待连接的积压。因此,如果第二个客户端在建立第一个连接之前连接,则第二个客户端将收到错误ECONNREFUSED
。考虑到您尝试做的事情,我猜SERVER_SOCKET.listen(4)
是合适的。
接下来,非阻塞通信比阻塞协议困难得多。我建议您在解决之前提高网络技能,但是当您准备就绪时,请查看select
或selectors
模块以获取帮助。它们提供了等待来自任何一个客户端的通信的工具,而不是像所有客户那样在所有客户端上循环并检查数据是否可用。这种循环非常低效。
最后,在Python中,使用小写,下划线分隔名称命名变量是一种很好的做法。 UPPER_CASE_NAMES
通常保留给常量。因此,将SERVER_SOCKET
更改为server_socket
,将CONNECTED_LISTENERS
更改为connected_listeners
,等等。