2015-09-16 31 views
1

如本文件中所提及:Python socket.accept()Python:同一套接字對象如何服務於不同的客戶端?

接受連接。套接字必須綁定到一個地址,並且監聽連接。返回值是一對(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) 
+0

讓我重新說一句:你的印象是,如果你聽,例如,端口'10000'和客戶端連接,每個客戶端連接都會獲得一個隨機的服務器端口來識別連接? – dhke

+0

@dhke是的,我做到了! –

+0

你在混淆套接字和端口。一個服務器端*端口*是所有必需的,但服務器需要每個連接有一個*套接字*。 – EJP

回答

0

我一直認爲,服務器將創建一個新的socket對象用不同的隨機端口

這需要告訴客戶這端口用於連接。很好,這是沒有必要的,見下文。

那麼服務器如何處理多個客戶端呢?

元組(server_addr, server_port, client_addr, client_port)在客戶端連接後是唯一的。當數據包進入時,網絡堆棧會搜索與此元組相匹配的打開連接,並將傳入數據包重定向到相關套接字(/文件描述符)。

服務器套接字(您執行上accept()),是無關(這是listen()荷蘭國際集團),但結合。這意味着它沒有對方(沒有客戶端地址),但它有一個本地地址(服務器端)。

accept()返回一個新的套接字。這一個是綁定連接。綁定與上面相同:它具有本地地址和端口。該地址與服務器套接字相同,但客戶端套接字狀態與服務器套接字的狀態不同:已連接。這意味着我們可以與另一方通信的已知對等方(地址)。我們也有同行的地址(對等地址)和套接字。這些信息足以唯一標識連接。

客戶端套接字只接受匹配(server_addr, server_port, client_addr, client_port)所有四個數據。

+0

還有一個疑問。服務器如何能夠在同一個套接字上監聽併爲客戶端提供服務?無論何時請求到來,操作系統是否總是使用一個未連接但綁定的套接字,該套接字與連接和綁定的套接字不同? –

+0

@KartikAnand注意術語。 * socket *本質上是操作系統爲您提供的與網絡棧交互的句柄。你不能有一個既監聽又連接的套接字。然而,如果一個*連接建立請求*(例如TCP'SYN')包進來與一個已建立的連接相匹配,它將被現有連接處理(因此通常被忽略)。如果您已經擁有一個地址,則無法創建具有相同地址四倍的連接。 – dhke

+0

感謝您的信息。你能否指出我在這些具體細節所涵蓋的特定資源上?我無法使用Google找到他們! –

相關問題