我正在开展聊天程序。但是现在它只能是一个客户端。我如何才能接受两个客户?当谈到套接字时,我仍然是一个菜鸟,所以你能解释得非常彻底吗?
服务器代码:
import socket
def mainFunc():
host = ""
port = 50000
ipList = []
nickNameList = []
num = True
s = socket.socket()
s.bind((host, port))
s.listen(1)
c, addr = s.accept()
print("Connection from: " + str(addr) + "\n")
ipList.insert(0, str(addr))
while True:
data = c.recv(1024)
if not data:
break
if num == True:
nickNameList.insert(0, str(data))
num = False
else:
print("From " + nickNameList[0] + ": " + str(data) + "\n")
message = raw_input("Message you want to send: ")
print("\n")
c.send(message)
c.close()
我尝试将s.listen(1)更改为s.listen(2)。但这似乎不允许第二个人连接。有人可以解释原因吗?
答案 0 :(得分:0)
对accept
的一次通话接受一个连接。要接受两个连接,请拨打accept
两次。
答案 1 :(得分:0)
如果你想按顺序连接两个连接,但一次只能连接一个,你只需要围绕c, addr = s.accept()
及其后面的所有内容循环。然后它接受一个连接,处理它直到套接字关闭并执行break
,然后处理第二个连接,依此类推。
在这种情况下,listen
积压 - s.listen(2)
中的2 - 意味着当您处理第一个时,它会排队不超过2个等待连接;任何人都会被拒绝。
如果您想要两个同时连接,则必须执行以下两项操作之一:
gevent
基本上是相同的想法。)asyncio
等协程安排程序到select
周围的简单循环。)在这种情况下,listen
积压实际上只有当你的程序太慢而无法及时跟上连接时才会这么做。当发生这种情况时,拒绝新连接通常比拒绝新连接更好。接受它们并进一步降低速度,因此保留一小部分积压是一个好主意。
但是,由于你的连接处理程序在每个套接字消息之后阻塞raw_input
,这至少可以说是一种奇怪的设计。 (不是阻塞部分 - 您可以通过为stdin分配线程,select
条目,协同程序等来解决这个问题。但是实际上发生与输入有关。你已经得到了8个连接,只有1个输入。当用户输入内容时,哪个连接得到结果?)
这是一个简单的线程服务器:
def connection(c, addr):
while True:
# your existing while True loop
while True:
c, addr = s.accept()
t = threading.Thread(target=connection, args=(c, addr))
t.start()
但是,对于您希望能够以某种方式关闭的真实服务器,您将需要提供某种方法来关闭连接线程。此外,对于在客户端之间交互的服务器(例如将一个用户的聊天消息发送给所有其他用户),您需要某种方式在线程之间传递消息,或者在它们之间共享信息。通常,每个连接最终需要两个线程 - 一个阻止c.recv
,另一个阻塞队列并与其他用户呼叫c.send
'消息。
对于多路复用服务器,不同的方法看起来非常不同,但所有这些方法都有很好的例子。请参阅asyncio
,selectors
了解他们的示例,Socket Programming HOWTO代表select
示例,Google代表第三方库示例,例如Twisted,gevent等。
作为旁注,您似乎期望send
可以保证一次发送完整的邮件,而另一方recv
将收到整个邮件,没有其他的。 TCP保证没有这样的事情。有关详细信息,请参阅Sockets are byte streams, not message streams。
此外,在nickNameList.insert(0, str(data))
中,str
是什么?在Python 2.x中,data
已经是str
,所以这只是浪费地制作了一个额外的副本,没有充分的理由。在Python 3.x中,data
是bytes
,因此将其转换为字符串表示形式,如"b'0Cool'"
而不是"0Cool"
,这几乎肯定不是您想要的