【问题标题】:How can the same socket object serve different clients?同一个套接字对象如何服务不同的客户端?
【发布时间】:2015-12-12 21:38:03
【问题描述】:

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

接受连接。套接字必须绑定到一个地址并且 监听连接。返回值是一对 (conn, address) 其中 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)

【问题讨论】:

  • 让我重新表述一下:如果您听例如端口10000和客户端连接,每个客户端连接获取一个随机的服务器端口来识别连接?
  • 您混淆了套接字和端口。只需要一个服务器端 port,但服务器每个连接都需要一个 socket

标签: python sockets


【解决方案1】:

我一直以为服务器会用不同的随机端口创建一个新的socket对象

这需要告诉客户端要使用哪个端口进行连接。很好,没有必要,见下文。这也意味着,与单个主机地址的打开连接不能超过 65535 个,这对于某些系统来说可能会中断很多。

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

元组(server_addr, server_port, client_addr, client_port) 在客户端连接后是唯一的。当一个数据包进来时,网络堆栈会搜索与这个元组匹配的开放连接,并将传入的数据包重定向到相关的套接字(/文件描述符)。

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

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

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

【讨论】:

  • 还有一个疑问。服务器如何在同一个套接字上侦听和服务客户​​端?每当请求到来时,操作系统是否总是会选择一个未连接但已绑定的套接字,该套接字与已连接和绑定的套接字不同?
  • @KartikAnand 小心术语。 socket 本质上是操作系统为您提供与网络堆栈交互的句柄。你不能有一个既监听又连接的套接字。但是,如果 连接建立请求(例如 TCP SYN)数据包进入与已建立的连接匹配,则它由现有连接处理(因此通常被忽略)。当您已经有一个时,您根本无法创建具有相同地址四倍的连接。
  • 感谢您的信息。您能否向我指出一个涵盖这些细节的特定资源。我用 Google 找不到他们!
  • 一般搜索 socket 时可能找不到好的结果,因为套接字涵盖了广泛的协议,甚至是无连接的协议。尝试搜索具体协议。例如,当您在已建立的 TCP 连接上获得 SYN 时会发生什么,有一个答案 here
猜你喜欢
  • 1970-01-01
  • 2016-12-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-06-08
  • 1970-01-01
  • 2014-08-18
相关资源
最近更新 更多