如何在Python中使用套接字接受两个连接

时间:2014-12-01 22:47:05

标签: python sockets client server

我正在开展聊天程序。但是现在它只能是一个客户端。我如何才能接受两个客户?当谈到套接字时,我仍然是一个菜鸟,所以你能解释得非常彻底吗?

服务器代码:

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)。但这似乎不允许第二个人连接。有人可以解释原因吗?

2 个答案:

答案 0 :(得分:0)

accept的一次通话接受一个连接。要接受两个连接,请拨打accept两次。

答案 1 :(得分:0)

如果你想按顺序连接两个连接,但一次只能连接一个,你只需要围绕c, addr = s.accept()及其后面的所有内容循环。然后它接受一个连接,处理它直到套接字关闭并执行break,然后处理第二个连接,依此类推。

在这种情况下,listen积压 - s.listen(2)中的2 - 意味着当您处理第一个时,它会排队不超过2个等待连接;任何人都会被拒绝。


如果您想要两个同时连接,则必须执行以下两项操作之一:

  • 多线程,每个连接都有一个线程。 (多处理和魔术绿色线程la gevent基本上是相同的想法。)
  • 多路复用,反应器或预处理器处理所有连接的非阻塞或异步I / O,而不是直接使用单个连接调用套接字。 (这个想法有很多变化,从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'消息。


对于多路复用服务器,不同的方法看起来非常不同,但所有这些方法都有很好的例子。请参阅asyncioselectors了解他们的示例,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中,databytes,因此将其转换为字符串表示形式,如"b'0Cool'"而不是"0Cool",这几乎肯定不是您想要的