同一套接字对象如何为不同的客户端服务?

时间:2015-09-16 10:37:37

标签: python sockets

如文档中所述:Python socket.accept()

  

接受连接。套接字必须绑定到一个地址和   听取联系。返回值是一对(conn,地址)   其中conn是一个可用于发送和接收数据的新套接字对象   连接,地址是绑定到套接字的地址   连接的另一端。

     

新创建的套接字是不可继承的。

     

版本3.4中已更改:套接字现在是不可继承的。

服务器代码是

>>> from socket import *
>>> sock = socket(AF_INET, SOCK_STREAM)
>>> sock.bind(("localhost", 20000))
>>> sock.getsockname()
('127.0.0.1', 20000)
>>> sock.listen(1)
>>> while True: 
...     conn, address = sock.accept()
...     print("Address of client : {0}".format(address))
...     print("Address of socket : {0}".format(conn.getsockname()))
... 
Address of client : ('127.0.0.1', 47165)
Address of socket : ('127.0.0.1', 20000)
Address of client : ('127.0.0.1', 47166)
Address of socket : ('127.0.0.1', 20000)

客户端代码是

>>> from socket import *
>>> sclient1 = socket(AF_INET, SOCK_STREAM)
>>> sclient2 = socket(AF_INET, SOCK_STREAM)
>>> sclient1.connect(("localhost", 20000))
>>> sclient2.connect(("localhost", 20000))

返回的新socket对象的地址始终与实际接受连接的原始socket相同。

我一直认为服务器会创建一个具有不同随机端口的新socket对象,但是如上所述,即使对于多个客户端,新conn对象的地址和端口也是如此。还是一样。那么服务器如何处理多个客户端呢?

修改

我知道上面的代码是阻塞的。如果我使用多个线程来处理不同的客户端连接,我将不得不将新的套接字对象和客户端地址发送到我的线程函数。因此,多个线程使用相同的服务器地址和端口处理多个客户端。

线程服务器

>>> from socket import *    
>>> import threading
>>> def handler(conn, address):
...     print("Address of client : {0}".format(address))
...     print("Address of socket : {0}".format(conn.getsockname()))
... 
>>> sock = socket(AF_INET, SOCK_STREAM)
>>> sock.bind(("localhost", 20000))
>>> sock.listen(1)
>>> while 1:
...     conn, address = sock.accept()
...     t = threading.Thread(target=handler, args=[conn, address])
...     t.start()
... 
Address of client : ('127.0.0.1', 47169)
Address of socket : ('127.0.0.1', 20000)
Address of client : ('127.0.0.1', 47170)
Address of socket : ('127.0.0.1', 20000)

1 个答案:

答案 0 :(得分:3)

  

我一直认为服务器会创建一个具有不同随机端口的新套接字对象

这需要告诉客户端哪个 new 端口用于连接。很好,没有必要,见下文。这也意味着,单个主机地址的开放连接数不能超过65535,这可能会对某些系统造成很大影响。

  

那么服务器如何处理多个客户端?

元组(server_addr, server_port, client_addr, client_port)在客户端连接后是唯一的。当数据包进入时,网络堆栈会搜索与此元组匹配的打开连接,并将传入的数据包重定向到相关的套接字(/ file descriptor)。

服务器套接字(您执行accept()),未连接 listen() ),但绑定。这意味着它在另一端没有对等端(没有客户端地址),但它确实有一个本地地址(服务器端)。

accept()返回一个新套接字。这个绑定连接。绑定与上面相同:它有一个本地地址和端口。该地址与服务器套接字相同,但新套接字的状态也是已连接。这意味着我们可以与另一方存在已知的对等方(具有地址)。我们还有对等方的地址(对等地址)和端口(对等端口)。此信息足以唯一标识连接。

客户端套接字仅接受与(server_addr, server_port, client_addr, client_port)的所有四个匹配的数据。