Python 中的網絡編程-socket模塊、創建TCP服務器、創建TCP客戶端
Python 中的網絡編程
一、socket()模塊
二、創建TCP服務器
三、創建TCP客戶端
一、socket模塊
套接字:
套接字最初是為同一主機上的應用程序所創建,使得主機上運行的一個程序(又名一個 進程)與另一個運行的程序進行通信。這就是所謂的進程間通信(Inter Process Communication, IPC)。有兩種類型的套接字:基於文件的和面向網絡的。總的來說,Python 只支持 AF_UNIX、AF_NETLINK、AF_TIPC 和 AF_INET 家族。
socket()模塊函數 要創建套接字,必須使用 socket.socket()函數,它一般的語法 :
1 socket(socket_family, socket_type, protocol=0)
其中,socket_family是AF_UNIX或AF_INET(如前所述),socket_type是SOCK_STREAM 或 SOCK_DGRAM(也如前所述)。protocol通常省略,默認為 0。
所以,為了創建 TCP/IP 套接字,可以用下面的方式調用 socket.socket()。
tcpSock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
同樣,為了創建 UDP/IP 套接字,需要執行以下語句。
udpSock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
因為有很多 socket 模塊屬性,所以此時使用“from module import *”這種導入方式可以 接受,不過這只是其中的一個例外。如果使用“from socket import *”,那麽我們就把 socket 屬性引入到了命名空間中。雖然這看起來有些麻煩,但是通過這種方式將能夠大大縮短代碼, 正如:
tcpSock = socket(AF_INET, SOCK_STREAM)
表格查詢
名 字 | 描 述 |
s.send() | 發送 TCP 消息 |
s.sendall() | 完整地發送 TCP 消息 |
s.recvfrom() | 接收 UDP 消息 |
s.recvfrom_into() | 接收 UDP 消息到指定的緩沖區 |
s.sendto() | 發送 UDP 消息 |
s.getpeername() | 連接到套接字(TCP)的遠程地址 |
s.getsockname() | 當前套接字的地址 |
s.getsockopt() | 返回給定套接字選項的值 |
s.setsockopt() | 設置給定套接字選項的值 |
s.shutdown() | 關閉連接 |
s.close() | 關閉套接字 |
s.detach() |
在未關閉文件描述符的情況下關閉套接字,返回文件描述符 |
s.ioctl() |
控制套接字的模式(僅支持 Windows) 面向阻塞的套接字方法 |
s.setblocking() | 設置套接字的阻塞或非阻塞模式 |
s.settimeout() | 設置阻塞套接字操作的超時時間 |
s.gettimeout() |
獲取阻塞套接字操作的超時時間 面向文件的套接字方法 |
s.makefile() | 創建與套接字關聯的文件對象 數據屬性 |
s.family | 套接字家族 |
s.proto | 套接字協議 |
二、創建TCP服務器
創建通用 TCP 服務器的一般偽代碼,然後對這些代碼的含義進行一般 性的描述。
ss = socket() # 創建服務器套接字 ss.bind() # 套接字與地址綁定 ss.listen() # 監聽連接 inf_loop: # 服務器無限循環 cs = ss.accept() # 接受客戶端連接 comm_loop: # 通信循環 cs.recv()/cs.send() # 對話(接收/發送) cs.close() # 關閉客戶端套接字 ss.close() # 關閉服務器套接字#(可選)
所有套接字都是通過使用 socket.socket()函數來創建的。因為服務器需要占用一個端口並 等待客戶端的請求,所以它們必須綁定到一個本地地址。因為 TCP 是一種面向連接的通信系 統,所以在 TCP 服務器開始操作之前,必須安裝一些基礎設施。特別地,TCP 服務器必須監 聽(傳入)的連接。一旦這個安裝過程完成後,服務器就可以開始它的無限循環。
接下來這個腳本創建一個TCP服務器,它接受來自客戶端的消息,然後將消息加上時間戳前綴並發送回客戶端
第 6~13 行 HOST 變量是空白的,這是對 bind()方法的標識,表示它可以使用任何可用的地址。我 們也選擇了一個隨機的端口號,並且該端口號似乎沒有被使用或被系統保留。另外,對於該 應用程序,將緩沖區大小設置為 1KB。可以根據網絡性能和程序需要改變這個容量。listen() 方法的參數是在連接被轉接或拒絕之前,傳入連接請求的最大數。 在第 11 行,分配了 TCP 服務器套接字(tcpSerSock),緊隨其後的是將套接字綁定到服 務器地址以及開啟 TCP 監聽器的調用。
第 15~28 行 一旦進入服務器的無限循環之中,我們就(被動地)等待客戶端的連接。當一個連接請求出 現時,我們進入對話循環中,在該循環中我們等待客戶端發送的消息。如果消息是空白的,這意 味著客戶端已經退出,所以此時我們將跳出對話循環,關閉當前客戶端連接,然後等待另一個客 戶端連接。如果確實得到了客戶端發送的消息,就將其格式化並返回相同的數據,但是會在這些 數據中加上當前時間戳的前綴。
三、創建TCP客戶端
創建客戶端比服務器要簡單得多。
如:
cs = socket() # 創建客戶端套接字 cs.connect() # 嘗試連接服務器 comm_loop: # 通信循環 cs.send()/cs.recv() # 對話(發送/接收) cs.close() # 關閉客戶端套接字
正如前面提到的,所有套接字都是利用 socket.socket()創建的。然而,一旦客戶端擁有了 一個套接字,它就可以利用套接字的 connect()方法直接創建一個到服務器的連接。當連接建 立之後,它就可以參與到與服務器的一個對話中。最後,一旦客戶端完成了它的事務,它就 可以關閉套接字,終止此次連接。
接下來這個腳本創建一個TCP客戶端,它提示用戶輸入發送到服務器端的消息,並接收從服務器端返回的添加了時間戳前 綴的相同消息,然後將結果展示給用戶。
第 1~3 行 在 UNIX 啟動行後,從 socket 模塊導入所有屬性。 第 5~11 行 HOST 和 PORT 變量指服務器的主機名與端口號。因為在同一臺計算機上運行測試(在 本例中),所以 HOST 包含本地主機名(如果你的服務器運行在另一臺主機上,那麽需要進 行相應修改)。端口號 PORT 應該與你為服務器設置的完全相同(否則,將無法進行通信)。 此外,也將緩沖區大小設置為 1KB。 在第 10 行分配了 TCP 客戶端套接字(tcpCliSock),接著主動調用並連接到服務器。 第 13~23 行 客戶端也有一個無限循環,但這並不意味著它會像服務器的循環一樣永遠運行下去。客戶 端循環在以下兩種條件下將會跳出:用戶沒有輸入(第 14~16 行),或者服務器終止且對 recv() 方法的調用失敗(第 18~20 行)。否則,在正常情況下,用戶輸入一些字符串數據,把這些數 據發送到服務器進行處理。然後,客戶端接收到加了時間戳的字符串,並顯示在屏幕上。在這個代碼片段中,需要將本地主機修改成它的 IPv6 地址“::1”,同時請求套接字的 AF_INET6 家族。如果結合 tsTclnt3.py 和 tsTclntV6.py 中的變化,那麽將得到一個 Python 3 版本的 IPv6 TCP 客戶端。
Python 中的網絡編程-socket模塊、創建TCP服務器、創建TCP客戶端