python基礎網絡編程--轉 python之網絡編程

本地的進程間通訊(IPC)有不少種方式,但能夠總結爲下面4類:php

  • 消息傳遞(管道、FIFO、消息隊列)
  • 同步(互斥量、條件變量、讀寫鎖、文件和寫記錄鎖、信號量)
  • 共享內存(匿名的和具名的)
  • 遠程過程調用(Solaris門和Sun RPC)

但這些都不是本文的主題!咱們要討論的是網絡中進程之間如何通訊?首要解決的問題是如何惟一標識一個進程,不然通訊無從談起!在本地能夠經過進程PID來惟一標識一個進程,可是在網絡中這是行不通的。其實TCP/IP協議族已經幫咱們解決了這個問題,網絡層的「ip地址」能夠惟一標識網絡中的主機,而傳輸層的「協議+端口」能夠惟一標識主機中的應用程序(進程)。這樣利用三元組(ip地址,協議,端口)就能夠標識網絡的進程了,網絡中的進程通訊就能夠利用這個標誌與其它進程進行交互。html

使用TCP/IP協議的應用程序一般採用應用編程接口:UNIX  BSD的套接字(socket)和UNIX System V的TLI(已經被淘汰),來實現網絡進程之間的通訊。就目前而言,幾乎全部的應用程序都是採用socket,而如今又是網絡時代,網絡中進程通訊是無處不在,這就是我爲何說「一切皆socket」。python


網絡通訊就是兩個進程在通訊

網絡編程對全部開發語言都是同樣的,Python也不例外。用Python進行網絡編程,就是在Python程序自己這個進程內,鏈接別的服務器進程的通訊端口進行通訊。linux

 

   (1) IP、TCP和UDP
    當您編寫socket應用程序的時候,您能夠在使用TCP仍是使用UDP之間作出選擇。它們都有各自的優勢和缺點。
    TCP是流協議,而UDP是數據報協議。換句話說,TCP在客戶機和服務器之間創建持續的開放鏈接,在該鏈接的生命期內,字節能夠經過該鏈接寫出(而且保證順序正確)。然而,經過 TCP 寫出的字節沒有內置的結構,因此須要高層協議在被傳輸的字節流內部分隔數據記錄和字段。
    另外一方面,UDP不須要在客戶機和服務器之間創建鏈接,它只是在地址之間傳輸報文。UDP的一個很好特性在於它的包是自分隔的(self-delimiting),也就是一個數據報都準確地指出它的開始和結束位置。然而,UDP的一個可能的缺點在於,它不保證包將會按順序到達,甚至根本就不保證。固然,創建在UDP之上的高層協議可能會提供握手和確認功能。
    對於理解TCP和UDP之間的區別來講,一個有用的類比就是電話呼叫和郵寄信件之間的區別。在呼叫者用鈴聲通知接收者,而且接收者拿起聽筒以前,電話呼叫不是活動的。只要沒有一方掛斷,該電話信道就保持活動,可是在通話期間,他們能夠自由地想說多少就說多少。來自任何一方的談話都按臨時的順序發生。另外一方面,當你發一封信的時候,郵局在投遞時既不對接收方是否存在做任何保證,也不對信件投遞將花多長時間作出有力保證。接收方可能按與信件的發送順序不一樣的順序接收不一樣的信件,而且發送方也可能在他們發送信件是交替地接收郵件。與(理想的)郵政服務不一樣,沒法送達的信件老是被送到死信辦公室處理,而再也不返回給發送。
編程

    (2)對等方、端口、名稱和地址
    除了TCP和UDP協議之外,通訊一方(客戶機或者服務器)還須要知道的關於與之通訊的對方機器的兩件事情:IP地址或者端口。IP地址是一個32位的數據值,爲了人們好記,通常用圓點分開的4組數字的形式來表示,好比:64.41.64.172。端口是一個16位的數據值,一般被簡單地表示爲一個小於65536的數字。大多數狀況下,該值介於10到100的範圍內。一個IP地址獲取送到某臺機器的一個數據包,而一個端口讓機器決定將該數據包交給哪一個進程/服務(若是有的話)。這種解釋略顯簡單,但基本思路是正確的。
    上面的描述幾乎都是正確的,但它也遺漏了一些東西。大多數時候,當人們考慮Internet主機(對等方)時,咱們都不會記憶諸如64.41.64.172這樣的數字,而是記憶諸如gnosis.cx這樣的名稱。爲了找到與某個特定主機名稱相關聯的IP地址,通常都使用域名服務器(DNS),可是有時會首先使用本地查找(常常是經過/etc/hosts的內容)。對於本教程,咱們將通常地假設有一個IP地址可用,不過下面討論編寫名稱查找代碼。
設計模式

    (3)主機名稱解析
    命令行實用程序nslookup能夠被用來根據符號名稱查找主機IP地址。實際上,許多常見的實用程序,好比ping或者網絡配置工具,也會順便作一樣的事情。可是以編程方式作這樣的事情很簡單。瀏覽器

======================TCP/IP======================
應用層: 它只負責產生相應格式的數據 ssh ftp nfs cifs dns http smtp pop3
-----------------------------------
傳輸層: 定義數據傳輸的兩種模式:
TCP(傳輸控制協議:面向鏈接,可靠的,效率相對不高)
UDP(用戶數據報協議:非面向鏈接,不可靠的,但效率高)
-----------------------------------
網絡層: 鏈接不一樣的網絡如以太網、令牌環網
IP (路由,分片) 、ICMP、 IGMP
ARP ( 地址解析協議,做用是將IP解析成MAC )
-----------------------------------
數據鏈路層: 以太網傳輸
-----------------------------------
物理層: 主要任務是規定各類傳輸介質和接口與傳輸信號相關的一些特性
-----------------------------------



服務器

TCP/IP(Transmission Control Protocol/Internet Protocol)即傳輸控制協議/網間協議,是一個工業標準的協議集,它是爲廣域網(WANs)設計的。網絡

TCP socket 因爲在通向前須要創建鏈接,因此其模式較 UDP socket 負責些。多線程

 

 

UDP(User Data Protocol,用戶數據報協議)是與TCP相對應的協議。它是屬於TCP/IP協議族中的一種。如圖:




UDP Socket圖:

 

UDP socket server 端代碼在進行bind後,無需調用listen方法。

TCP/IP協議族包括運輸層、網絡層、鏈路層,
而socket所在位置如圖,Socket是應用層與TCP/IP協議族通訊的中間軟件抽象層。


 

Socket是什麼

 

socket起源於Unix,而Unix/Linux基本哲學之一就是「一切皆文件」,均可以用「打開open –> 讀寫write/read –> 關閉close」模式來操做。Socket就是該模式的一個實現,socket便是一種特殊的文件,一些socket函數就是對其進行的操做(讀/寫IO、打開、關閉).
說白了Socket是應用層與TCP/IP協議族通訊的中間軟件抽象層,它是一組接口。在設計模式中,Socket其實就是一個門面模式,它把複雜的TCP/IP協議族隱藏在Socket接口後面,對用戶來講,一組簡單的接口就是所有,讓Socket去組織數據,以符合指定的協議。

 

注意:其實socket也沒有層的概念,它只是一個facade設計模式的應用,讓編程變的更簡單。是一個軟件抽象層。在網絡編程中,咱們大量用的都是經過socket實現的。

Socket是網絡編程的一個抽象概念。一般咱們用一個Socket表示「打開了一個網絡連接」,而打開一個Socket須要知道目標計算機的IP地址和端口號,再指定協議類型便可。

http://images2015.cnblogs.com/blog/720333/201611/720333-20161126215744846-706023541.png

TCP編程

Socket是網絡編程的一個抽象概念。一般咱們用一個Socket表示「打開了一個網絡連接」,而打開一個Socket須要知道目標計算機的IP地址和端口號,再指定協議類型便可。
TCP鏈接簡圖: 三次握手,數據傳輸,四次揮手

socket中TCP的三次握手創建鏈接詳解

咱們知道tcp創建鏈接要進行「三次握手」,即交換三個分組。大體流程以下:

  • 客戶端向服務器發送一個SYN J
  • 服務器向客戶端響應一個SYN K,並對SYN J進行確認ACK J+1
  • 客戶端再想服務器發一個確認ACK K+1

只有就完了三次握手,可是這個三次握手發生在socket的那幾個函數中呢?請看下圖:

image

圖一、socket中發送的TCP三次握手

從圖中能夠看出,當客戶端調用connect時,觸發了鏈接請求,向服務器發送了SYN J包,這時connect進入阻塞狀態;服務器監聽到鏈接請求,即收到SYN J包,調用accept函數接收請求向客戶端發送SYN K ,ACK J+1,這時accept進入阻塞狀態;客戶端收到服務器的SYN K ,ACK J+1以後,這時connect返回,並對SYN K進行確認;服務器收到ACK K+1時,accept返回,至此三次握手完畢,鏈接創建。

總結:客戶端的connect在三次握手的第二個次返回,而服務器端的accept在三次握手的第三次返回。

五、socket中TCP的四次握手釋放鏈接詳解

上面介紹了socket中TCP的三次握手創建過程,及其涉及的socket函數。如今咱們介紹socket中的四次握手釋放鏈接的過程,請看下圖:

image

圖二、socket中發送的TCP四次握手

圖示過程以下:

  • 某個應用進程首先調用 close主動關閉鏈接,這時TCP發送一個FIN M;
  • 另外一端接收到FIN M以後,執行被動關閉,對這個FIN進行確認。它的接收也做爲文件結束符傳遞給應用進程,由於FIN的接收意味着應用進程在相應的鏈接上再也接收不到額外數據;
  • 一段時間以後,接收到文件結束符的應用進程調用 close關閉它的socket。這致使它的TCP也發送一個FIN N;
  • 接收到這個FIN的源發送端TCP對它進行確認。

這樣每一個方向上都有一個FIN和ACK。

Python3 網絡編程

Python 提供了兩個級別訪問的網絡服務。:

  • 低級別的網絡服務支持基本的 Socket,它提供了標準的 BSD Sockets API,能夠訪問底層操做系統Socket接口的所有方法。
  • 高級別的網絡服務模塊 SocketServer, 它提供了服務器中心類,能夠簡化網絡服務器的開發。

什麼是 Socket?

Socket又稱"套接字",應用程序一般經過"套接字"向網絡發出請求或者應答網絡請求,使主機間或者一臺計算機上的進程間能夠通信。

socket和file的區別:

  • file模塊是針對某個指定文件進行【打開】【讀寫】【關閉】
  • socket模塊是針對 服務器端 和 客戶端Socket 進行【打開】【讀寫】【關閉】

 

 服務器端先初始化Socket,而後與端口綁定(bind),對端口進行監聽(listen),調用accept阻塞,等待客戶端鏈接。在這時若是有個客戶端初始化一個Socket,而後鏈接服務器(connect),若是鏈接成功,這時客戶端與服務器端的鏈接就創建了。客戶端發送數據請求,服務器端接收請求並處理請求,而後把迴應數據發送給客戶端,客戶端讀取數據,最後關閉鏈接,一次交互結束。


socket()函數

Python 中,咱們用 socket()函數來建立套接字,語法格式以下:

1
socket.socket([family[, type [, proto]]])

參數

  • family: 套接字家族可使AF_UNIX或者AF_INET
  • type: 套接字類型能夠根據是面向鏈接的仍是非鏈接分爲SOCK_STREAMSOCK_DGRAM
  • protocol: 通常不填默認爲0.

簡單實例

服務端

咱們使用 socket 模塊的 socket 函數來建立一個 socket 對象。socket 對象能夠經過調用其餘函數來設置一個 socket 服務。

如今咱們能夠經過調用 bind(hostname, port) 函數來指定服務的 port(端口)

接着,咱們調用 socket 對象的 accept 方法。該方法等待客戶端的鏈接,並返回 connection 對象,表示已鏈接到客戶端。

完整代碼以下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#!/usr/bin/python3
# 文件名:server.py
 
# 導入 socket、sys 模塊
import socket
import sys
 
# 建立 socket 對象
serversocket = socket.socket(
             socket.AF_INET, socket.SOCK_STREAM)
 
# 獲取本地主機名
host = socket.gethostname()
 
port = 9999
 
# 綁定端口
serversocket.bind((host, port))
 
# 設置最大鏈接數,超事後排隊
serversocket.listen( 5 )
 
while True :
     # 創建客戶端鏈接
     clientsocket,addr = serversocket.accept()     
 
     print ( "鏈接地址: %s" % str (addr))
     
     msg = '歡迎訪問python教程!' + "\r\n"
     clientsocket.send(msg.encode( 'utf-8' ))
     clientsocket.close()

 

客戶端

接下來咱們寫一個簡單的客戶端實例鏈接到以上建立的服務。端口號爲 12345。

socket.connect(hosname, port ) 方法打開一個 TCP 鏈接到主機爲 hostname 端口爲 port 的服務商。鏈接後咱們就能夠從服務端後期數據,記住,操做完成後須要關閉鏈接。

完整代碼以下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#!/usr/bin/python3
# 文件名:client.py
 
# 導入 socket、sys 模塊
import socket
import sys
 
# 建立 socket 對象
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
 
# 獲取本地主機名
host = socket.gethostname()
 
# 設置端口好
port = 9999
 
# 鏈接服務,指定主機和端口
s.connect((host, port))
 
# 接收小於 1024 字節的數據
msg = s.recv( 1024 )
 
s.close()
 
print (msg.decode( 'utf-8' ))

 先執行server端,而後打開client端就能看到結果

 

客戶端

大多數鏈接都是可靠的TCP鏈接。建立TCP鏈接時,主動發起鏈接的叫客戶端,被動響應鏈接的叫服務器。

舉個例子,當咱們在瀏覽器中訪問新浪時,咱們本身的計算機就是客戶端,瀏覽器會主動向新浪的服務器發起鏈接。若是一切順利,新浪的服務器接受了咱們的鏈接,一個TCP鏈接就創建起來的,後面的通訊就是發送網頁內容了。

因此,咱們要建立一個基於TCP鏈接的Socket,能夠這樣作:

1
2
3
4
5
6
7
# 導入socket庫:
import socket
 
# 建立一個socket:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 創建鏈接:
s.connect(( 'www.sina.com.cn' , 80 ))

 

建立Socket時,AF_INET指定使用IPv4協議,若是要用更先進的IPv6,就指定爲AF_INET6SOCK_STREAM指定使用面向流的TCP協議,這樣,一個Socket對象就建立成功,可是尚未創建鏈接。

客戶端要主動發起TCP鏈接,必須知道服務器的IP地址和端口號。新浪網站的IP地址能夠用域名www.sina.com.cn自動轉換到IP地址,可是怎麼知道新浪服務器的端口號呢?

答案是做爲服務器,提供什麼樣的服務,端口號就必須固定下來。因爲咱們想要訪問網頁,所以新浪提供網頁服務的服務器必須把端口號固定在80端口,由於80端口是Web服務的標準端口。其餘服務都有對應的標準端口號,例如SMTP服務是25端口,FTP服務是21端口,等等。端口號小於1024的是Internet標準服務的端口,端口號大於1024的,能夠任意使用。

所以,咱們鏈接新浪服務器的代碼以下:

1
s.connect(( 'www.sina.com.cn' , 80 ))

 

注意參數是一個tuple,包含地址和端口號。

創建TCP鏈接後,咱們就能夠向新浪服務器發送請求,要求返回首頁的內容:

1
2
# 發送數據:
s.send(b 'GET / HTTP/1.1\r\nHost: www.sina.com.cn\r\nConnection: close\r\n\r\n' )

 

TCP鏈接建立的是雙向通道,雙方均可以同時給對方發數據。可是誰先發誰後發,怎麼協調,要根據具體的協議來決定。例如,HTTP協議規定客戶端必須先發請求給服務器,服務器收到後才發數據給客戶端。

發送的文本格式必須符合HTTP標準,若是格式沒問題,接下來就能夠接收新浪服務器返回的數據了:

 
 

接收數據時,調用recv(max)方法,一次最多接收指定的字節數,所以,在一個while循環中反覆接收,直到recv()返回空數據,表示接收完畢,退出循環。

當咱們接收完數據後,調用close()方法關閉Socket,這樣,一次完整的網絡通訊就結束了:

1
2
# 關閉鏈接:
s.close()

 

接收到的數據包括HTTP頭和網頁自己,咱們只須要把HTTP頭和網頁分離一下,把HTTP頭打印出來,網頁內容保存到文件:

1
2
3
4
5
header, html = data.split(b '\r\n\r\n' , 1 )
print (header.decode( 'utf-8' ))
# 把接收的數據寫入文件:
with open ( 'sina.html' , 'wb' ) as f:
     f.write(html)

 

如今,只須要在瀏覽器中打開這個sina.html文件,就能夠看到新浪的首頁了。

服務器

和客戶端編程相比,服務器編程就要複雜一些。

服務器進程首先要綁定一個端口並監聽來自其餘客戶端的鏈接。若是某個客戶端鏈接過來了,服務器就與該客戶端創建Socket鏈接,隨後的通訊就靠這個Socket鏈接了。

因此,服務器會打開固定端口(好比80)監聽,每來一個客戶端鏈接,就建立該Socket鏈接。因爲服務器會有大量來自客戶端的鏈接,因此,服務器要可以區分一個Socket鏈接是和哪一個客戶端綁定的。一個Socket依賴4項:服務器地址、服務器端口、客戶端地址、客戶端端口來惟一肯定一個Socket。

可是服務器還須要同時響應多個客戶端的請求,因此,每一個鏈接都須要一個新的進程或者新的線程來處理,不然,服務器一次就只能服務一個客戶端了。

咱們來編寫一個簡單的服務器程序,它接收客戶端鏈接,把客戶端發過來的字符串加上Hello再發回去。

首先,建立一個基於IPv4和TCP協議的Socket:

1
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

 

而後,咱們要綁定監聽的地址和端口。服務器可能有多塊網卡,能夠綁定到某一塊網卡的IP地址上,也能夠用0.0.0.0綁定到全部的網絡地址,還能夠用127.0.0.1綁定到本機地址。127.0.0.1是一個特殊的IP地址,表示本機地址,若是綁定到這個地址,客戶端必須同時在本機運行才能鏈接,也就是說,外部的計算機沒法鏈接進來。

端口號須要預先指定。由於咱們寫的這個服務不是標準服務,因此用9999這個端口號。請注意,小於1024的端口號必需要有管理員權限才能綁定:

1
2
# 監聽端口:
s.bind(( '127.0.0.1' , 9999 ))

 

緊接着,調用listen()方法開始監聽端口,傳入的參數指定等待鏈接的最大數量:

1
2
s.listen( 5 )
print ( 'Waiting for connection...' )

 

接下來,服務器程序經過一個永久循環來接受來自客戶端的鏈接,accept()會等待並返回一個客戶端的鏈接:

1
2
3
4
5
6
while True :
     # 接受一個新鏈接:
     sock, addr = s.accept()
     # 建立新線程來處理TCP鏈接:
     t = threading.Thread(target = tcplink, args = (sock, addr))
     t.start()

 

每一個鏈接都必須建立新線程(或進程)來處理,不然,單線程在處理鏈接的過程當中,沒法接受其餘客戶端的鏈接:

1
2
3
4
5
6
7
8
9
10
11
def tcplink(sock, addr):
     print ( 'Accept new connection from %s:%s...' % addr)
     sock.send(b 'Welcome!' )
     while True :
         data = sock.recv( 1024 )
         time.sleep( 1 )
         if not data or data.decode( 'utf-8' ) = = 'exit' :
             break
         sock.send(( 'Hello, %s!' % data.decode( 'utf-8' )).encode( 'utf-8' ))
     sock.close()
     print ( 'Connection from %s:%s closed.' % addr)

 

鏈接創建後,服務器首先發一條歡迎消息,而後等待客戶端數據,並加上Hello再發送給客戶端。若是客戶端發送了exit字符串,就直接關閉鏈接。

要測試這個服務器程序,咱們還須要編寫一個客戶端程序:

1
2
3
4
5
6
7
8
9
10
11
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 創建鏈接:
s.connect(( '127.0.0.1' , 9999 ))
# 接收歡迎消息:
print (s.recv( 1024 ).decode( 'utf-8' ))
for data in [b 'Michael' , b 'Tracy' , b 'Sarah' ]:
     # 發送數據:
     s.send(data)
     print (s.recv( 1024 ).decode( 'utf-8' ))
s.send(b 'exit' )
s.close()

 

咱們須要打開兩個命令行窗口,一個運行服務器程序,另外一個運行客戶端程序,就能夠看到效果了:

UDP編程

TCP是創建可靠鏈接,而且通訊雙方均可以以流的形式發送數據。相對TCP,UDP則是面向無鏈接的協議。

使用UDP協議時,不須要創建鏈接,只須要知道對方的IP地址和端口號,就能夠直接發數據包。可是,能不能到達就不知道了。

雖然用UDP傳輸數據不可靠,但它的優勢是和TCP比,速度快,對於不要求可靠到達的數據,就可使用UDP協議。

咱們來看看如何經過UDP協議傳輸數據。和TCP相似,使用UDP的通訊雙方也分爲客戶端和服務器。服務器首先須要綁定端口:

1
2
3
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# 綁定端口:
s.bind(( '127.0.0.1' , 9999 ))

 

建立Socket時,SOCK_DGRAM指定了這個Socket的類型是UDP。綁定端口和TCP同樣,可是不須要調用listen()方法,而是直接接收來自任何客戶端的數據:

1
2
3
4
5
6
print 'Bind UDP on 9999...'
while True :
     # 接收數據:
     data, addr = s.recvfrom( 1024 )
     print 'Received from %s:%s.' % addr
     s.sendto( 'Hello, %s!' % data, addr)

 

recvfrom()方法返回數據和客戶端的地址與端口,這樣,服務器收到數據後,直接調用sendto()就能夠把數據用UDP發給客戶端。

注意這裏省掉了多線程,由於這個例子很簡單。

客戶端使用UDP時,首先仍然建立基於UDP的Socket,而後,不須要調用connect(),直接經過sendto()給服務器發數據:

1
2
3
4
5
6
7
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
for data in [ 'Michael' , 'Tracy' , 'Sarah' ]:
     # 發送數據:
     s.sendto(data, ( '127.0.0.1' , 9999 ))
     # 接收數據:
     print s.recv( 1024 )
s.close()

 

從服務器接收數據仍然調用recv()方法。

小結

UDP的使用與TCP相似,可是不須要創建鏈接。此外,服務器綁定UDP端口和TCP端口互不衝突,也就是說,UDP的9999端口與TCP的9999端口能夠各自綁定。

 

Python 提供了兩個級別訪問的網絡服務。:

  • 低級別的網絡服務支持基本的 Socket,它提供了標準的 BSD Sockets API,能夠訪問底層操做系統Socket接口的所有方法。
  • 高級別的網絡服務模塊 SocketServer, 它提供了服務器中心類,能夠簡化網絡服務器的開發。

 

Socket 對象(內建)方法

函數 描述
服務器端套接字
s.bind() 綁定地址(host,port)到套接字, 在AF_INET下,以元組(host,port)的形式表示地址。
s.listen() 開始TCP監聽。backlog指定在拒絕鏈接以前,操做系統能夠掛起的最大鏈接數量。該值至少爲1,大部分應用程序設爲5就能夠了。
s.accept() 被動接受TCP客戶端鏈接,(阻塞式)等待鏈接的到來
客戶端套接字
s.connect() 主動初始化TCP服務器鏈接,。通常address的格式爲元組(hostname,port),若是鏈接出錯,返回socket.error錯誤。
s.connect_ex() connect()函數的擴展版本,出錯時返回出錯碼,而不是拋出異常
公共用途的套接字函數
s.recv() 接收TCP數據,數據以字符串形式返回,bufsize指定要接收的最大數據量。flag提供有關消息的其餘信息,一般能夠忽略。
s.send() 發送TCP數據,將string中的數據發送到鏈接的套接字。返回值是要發送的字節數量,該數量可能小於string的字節大小。
s.sendall() 完整發送TCP數據,完整發送TCP數據。將string中的數據發送到鏈接的套接字,但在返回以前會嘗試發送全部數據。成功返回None,失敗則拋出異常。
s.recvform() 接收UDP數據,與recv()相似,但返回值是(data,address)。其中data是包含接收數據的字符串,address是發送數據的套接字地址。
s.sendto() 發送UDP數據,將數據發送到套接字,address是形式爲(ipaddr,port)的元組,指定遠程地址。返回值是發送的字節數。
s.close() 關閉套接字
s.getpeername() 返回鏈接套接字的遠程地址。返回值一般是元組(ipaddr,port)。
s.getsockname() 返回套接字本身的地址。一般是一個元組(ipaddr,port)
s.setsockopt(level,optname,value) 設置給定套接字選項的值。
s.getsockopt(level,optname[.buflen]) 返回套接字選項的值。
s.settimeout(timeout) 設置套接字操做的超時期,timeout是一個浮點數,單位是秒。值爲None表示沒有超時期。通常,超時期應該在剛建立套接字時設置,由於它們可能用於鏈接的操做(如connect())
s.gettimeout() 返回當前超時期的值,單位是秒,若是沒有設置超時期,則返回None。
s.fileno() 返回套接字的文件描述符。
s.setblocking(flag) 若是flag爲0,則將套接字設爲非阻塞模式,不然將套接字設爲阻塞模式(默認值)。非阻塞模式下,若是調用recv()沒有發現任何數據,或send()調用沒法當即發送數據,那麼將引發socket.error異常。
s.makefile() 建立一個與該套接字相關連的文件

 

server端:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#!/usr/bin/env python
# -*- coding:utf-8 -*-
 
import socket
 
ip_port = ( '127.0.0.1' , 9999 )
 
sk = socket.socket()
sk.bind(ip_port)
sk.listen( 5 )
 
while True :
     print 'server waiting...'
     conn,addr = sk.accept()
 
     client_data = conn.recv( 1024 )
     print client_data
     conn.sendall( '不要回答,不要回答,不要回答' )
 
     conn.close()
 
socket server

 client:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import socket
ip_port = ( '127.0.0.1' , 9999 )
 
sk = socket.socket()
sk.connect(ip_port)
 
sk.sendall( '請求佔領地球' )
 
server_reply = sk.recv( 1024 )
print server_reply
 
sk.close()
 
socket client

 WEB服務應用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#!/usr/bin/env python
#coding:utf-8
import socket
  
def handle_request(client):
     buf = client.recv( 1024 )
     client.send( "HTTP/1.1 200 OK\r\n\r\n" )
     client.send( "Hello, World" )
  
def main():
     sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
     sock.bind(( 'localhost' , 8080 ))
     sock.listen( 5 )
  
     while True :
         connection, address = sock.accept()
         handle_request(connection)
         connection.close()
  
if __name__ = = '__main__' :
   main()
相關文章
相關標籤/搜索