標籤:
一、通訊端
通訊端是為特定網路通訊協定(例如TCP/IP,ICMP/IP,UDP/IP等)套件對上的網路應用程式提供者提供當前可移植標準的對象。它們允許程式接受並進行串連,如發送和接受資料。為了建立通訊通道,網路通訊的每個端點擁有一個通訊端對象極為重要。
通訊端為BSD UNIX系統核心的一部分,而且他們也被許多其他類似UNIX的作業系統包括Linux所採納。許多非BSD UNIX系統(如ms-dos,windows,os/2,mac os及大部分主機環境)都以庫形式提供對通訊端的支援。
三種最流行的通訊端類型是:stream,datagram和raw。stream和datagram通訊端可以直接與TCP協議進行介面,而raw通訊端則介面到IP協議。但通訊端並不限於TCP/IP。
二、通訊端模組
通訊端模組是一個非常簡單的基於對象的介面,它提供對低層BSD通訊端樣式網路的訪問。使用該模組可以實現客戶機和伺服器通訊端。要在python中建立具有TCP和流通訊端的簡單伺服器,需要使用socket模組。利用該模組包含的函數和類定義,可產生通過網路通訊的程式。一般來說,建立伺服器串連需要六個步驟。
第1步是建立socket對象。調用socket建構函式。
socket=socket.socket(familly,type)
要建立一個通訊端,你必須使用socket.socket()函數,它在socket模組,其中有一般的文法:
s = socket.socket (socket_family, socket_type, protocol=0)
下面是參數的描述:
family的值可以是AF_UNIX(Unix域,用於同一台機器上的進程間通訊),也可以是AF_INET(對於IPV4協議的TCP和UDP),至於type參數,SOCK_STREAM(流通訊端)或者 SOCK_DGRAM(資料報文通訊端),SOCK_RAW(raw通訊端)。
第2步則是將socket綁定(指派)到指定地址上,socket.bind(address)
address必須是一個雙元素元組,((host,port)),主機名稱或者ip地址+連接埠號碼。如果連接埠號碼正在被使用或者保留,或者主機名稱或ip地址錯誤,則引發socke.error異常。
第3步,綁定後,必須準備好通訊端,以便接受串連請求。
socket.listen(backlog)
backlog指定了最多串連數,至少為1,接到串連請求後,這些請求必須排隊,如果隊列已滿,則拒絕請求。
第4步,伺服器通訊端通過socket的accept方法等待客戶請求一個串連:
connection,address=socket.accept()
調用accept方法時,socket會進入‘waiting‘(或阻塞)狀態。客戶請求串連時,方法建立串連並返回伺服器。accept方法返回一個含有倆個元素的元組,形如(connection,address)。第一個元素(connection)是新的socket對象,伺服器通過它與客戶通訊;第二個元素(address)是客戶的internet地址。
第5步是處理階段,伺服器和客戶通過send和recv方法通訊(傳輸資料)。伺服器調用send,並採用字串形式向客戶發送資訊。send方法返回已發送的字元個數。伺服器使用recv方法從客戶接受資訊。調用recv時,必須指定一個整數來控制本次調用所接受的最大資料量。recv方法在接受資料時會進入‘blocket‘狀態,最後返回一個字串,用它來表示收到的資料。如果發送的量超過recv所允許,資料會被截斷。多餘的資料將緩衝於接受端。以後調用recv時,多餘的資料會從緩衝區刪除。
第6步,傳輸結束,伺服器調用socket的close方法以關閉串連。
建立一個簡單客戶串連則需要4個步驟。
第1步,建立一個socket以串連伺服器 socket=socket.socket(family,type)
第2步,使用socket的connect方法串連伺服器 socket.connect((host,port))
第3步,客戶和伺服器通過send和recv方法通訊。
第4步,結束後,客戶通過調用socket的close方法來關閉串連。
執行個體:
這是Socket Server 部分:
import sockets = socket.socket()host = socket.gethostname()port = 8088s.bind((host,port))s.listen(5)while True:c, addr = s.accept()print ‘Got connection from‘, addrc.send(‘Thank you for connection‘)c.close()
這是Socket Client 部分:
import sockets = socket.socket()host = socket.gethostname()port = 8088s.connect((host,port))print s.recv(1024)
運行時,請將對應的連接埠(這裡是8088)添加到防火牆的InBound和OutBound的規則中。
1.2 urllib 和 urllib2 模組
urllib
和 urllib2
是Python標準庫中最強的的網路工作庫。通過這兩個庫所提供的上層介面,使我們可以像讀取本地檔案一樣讀取網路上的檔案。而且urllib2
並不是 urllib
的升級版本(應該是一種補充),二者是不可相互替代的。
通過使用 urllib
的 urlopen
函數可以很容易的開啟遠端檔案,如下:
from urllib import urlopenwebpage = urlopen(‘http://www.cnblogs.com/IPrograming/‘)txt = webpage.readline(45)print txt # !DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0
也可以通過在通過在路徑的前面添加 file:
來訪問本地檔案:
from urllib import urlopenwebpage = urlopen(r‘file:D:\H\sr23upd\ADD_ABBR.txt‘)txt = webpage.readline(45)print txt
如果你還可以通過 urllib
提供的 urlretrieve
函數,來直接儲存遠程檔案副本:
from urllib import urlretrievewebpage = urlretrieve(‘http://www.cnblogs.com/IPrograming/‘,‘C:\\temp.html‘)print type(webpage) # <type ‘tuple‘>
1.3 其他與網路相關的模組
除了 socket、urllib和urllib2這些模組以外標準庫還有很多和網路相關的模組,下面的列表是其中的一部分:
===========================================================模組 描述===========================================================asynchat asyncore的增強版本 asyncore 非同步socket處理常式 cgi 基本的CGI支援 Cookie Cookie對象操作,主要用於伺服器操作 cookielib 用戶端cookie支援 email E-mail訊息支援(包括MIME) ftplib FTP用戶端模組 gopherlib gopher用戶端部落格 httplib HTTP用戶端模組 imaplib IMAP4用戶端模組 mailbox 讀取幾種郵件的格式 mailcap 通過mailcap檔案訪問MIME配置 mhlib 訪問MH郵箱 nntplib NNTP用戶端模組 poplib POP用戶端模組 robotparser 支援解析Web伺服器的robot檔案 SimpleXMLRPCServer 一個簡單的XML-RPC伺服器 stmpd SMTP伺服器模組 smtplib SMTP用戶端模組 telnetlib Telnet用戶端模組 urlparse 支援解析URL xmlrpclib XML-RPC的用戶端支援
Python網路模組
可以使用Python中的網路/互連網編程的一些重要的模組列表.
Protocol |
Common function |
Port No |
Python module |
HTTP |
Web pages |
80 |
httplib, urllib, xmlrpclib |
NNTP |
Usenet news |
119 |
nntplib |
FTP |
File transfers |
20 |
ftplib, urllib |
SMTP |
Sending email |
25 |
smtplib |
POP3 |
Fetching email |
110 |
poplib |
IMAP4 |
Fetching email |
143 |
imaplib |
Telnet |
Command lines |
23 |
telnetlib |
Gopher |
Document transfers |
70 |
gopherlib, urllib |
請查看上面提到所有庫的合作與FTP,SMTP的POP,IMAP協議.
最後:
1、建立socket
建立socket對象需要搞清通訊類型和協議家族。通訊類型指明了用什麼協議來傳輸資料。協議的例子包括IPv4、IPv6、IPX\SPX、AFP。對於internet通訊,通訊類型基本上都是AF_INET(和IPv4對應)。協議家族一般表示TCP通訊的SOCK_STREAM或者表示UDP通訊的SOCK_DGRAM。因此對於TCP通訊,建立一個socket串連的語句為:
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
對於UDP通訊,建立一個socket串連的語句為:
s=socket.socket(socket.AF_INET,SOCK_DGRAM)
2、串連socket
串連socket需要提供一個tuple,包括host(主機名稱或者IP)和port(遠程連接埠),類似代碼為:
s.connect(("www.baidu.com",80)
3、尋找連接埠號碼
socket庫中利用getservbyname()函數可以查詢連接埠號碼,一般需要兩個參數:一是協議名,如http、smtp、pop3等,一個是連接埠名,如tcp、udp
例如:
import socket
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
port=socket.getservbyname(‘http‘,‘tcp‘)
port的返回值為80。若改為:
port=socket.getservbyname(‘smtp‘,‘tcp‘)
port的返回值為25。
4、從socket擷取資訊
建立socket串連後,可以通過getsockname()擷取本身的ip地址和連接埠號碼,也可以通過getpeername()顯示遠程機器的ip地址和連接埠號碼。
如:在python shell中
>>> import socket
>>> s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
>>> port=socket.getservbyname(‘http‘,‘tcp‘)
>>> s.connect((‘www.baidu.com‘,port))
>>> print s.getsockname()
(‘192.168.87.138‘, 3213)
>>> print s.getpeername()
(‘220.181.111.147‘, 80)
Socket 模組的類方法
類方法 說明
Socket 低層網路介面(每個 BSD API)
socket.socket(family, type) 建立並返回一個新的 socket 對象
socket.getfqdn(name) 將使用點號分隔的 IP 位址字串轉換成一個完整的網域名稱
socket.gethostbyname(hostname) 將主機名稱解析為一個使用點號分隔的 IP 位址字串
socket.fromfd(fd, family, type) 從現有的檔案描述符建立一個 socket 對象
Socket 模組的執行個體方法
執行個體方法 說明
sock.bind( (adrs, port) ) 將 socket 綁定到一個地址和連接埠上
sock.accept() 返回一個客戶機 socket(帶有客戶機端的地址資訊)
sock.listen(backlog) 將 socket 設定成監聽模式,能夠監聽 backlog 外來的串連請求
sock.connect( (adrs, port) ) 將 socket 串連到定義的主機和連接埠上
sock.recv( buflen[, flags] ) 從 socket 中接收資料,最多 buflen 個字元
sock.recvfrom( buflen[, flags] ) 從 socket 中接收資料,最多 buflen 個字元,同時返回資料來源的遠程主機和連接埠號碼
sock.send( data[, flags] ) 通過 socket 發送資料
sock.sendto( data[, flags], addr ) 通過 socket 發送資料
sock.close() 關閉 socket
sock.getsockopt( lvl, optname ) 獲得指定 socket 選項的值
sock.setsockopt( lvl, optname, val ) 設定指定 socket 選項的值
舉例:
>>> import socket
>>> socket.gethostbyname(‘www.baidu.com‘)
‘220.181.111.147‘
>>> socket.gethostbyname(‘www.126.com‘)
‘123.125.50.22‘
>>> socket.getfqdn(‘123.125.50.22‘)
‘123.125.50.22‘
這裡getfqdn卻不能返回網域名稱?
5、處理錯誤
關於錯誤異常的處理,主要就是用try、except語句。如將python網路編程學習筆記(1)中gopherclient.py進行一下修改:
複製代碼 代碼如下:
# -*- coding: cp936 -*-
##modify by 小五義
import socket,sys
port =70
host=sys.argv[1]
filename=sys.argv[2]
try:
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
except Socket.error,e:
print "建立socket錯誤:%s"%e
try:
s.connect((host,port))
except socket.gaierror,e:
print "host或者連接埠錯誤:%s" %e
except socket.error,e:
print "串連錯誤:%s" %e
try:
s.sendall(filename+"\r\n")
except socket.error,e:
print "資料發送錯誤:%s" %e
sys.exit(1)
while 1:
try:
buf=s.recv(2048)
except socket.error,e:
print "接收錯誤:%s"%e
sys.exit(1)
if ‘does not exist‘ in buf:
print "%s檔案不存在" %filename
else:
if not len(buf):
break
sys.stdout.write(buf)
參考文獻:
http://www.jb51.net/article/50857.htm
http://www.cnblogs.com/IPrograming/p/Python-socket.html
http://blog.csdn.net/alpha5/article/details/24122749
http://www.cppblog.com/lai3d/archive/2008/02/19/42919.html
http://www.showerlee.com/archives/1051
Python之網路編程