1、套接字
套接字是為特定網(wǎng)絡(luò)協(xié)議(例如TCP/IP,ICMP/IP,UDP/IP等)套件對(duì)上的網(wǎng)絡(luò)利用程序提供者提供當(dāng)前可移植標(biāo)準(zhǔn)的對(duì)象。它們?cè)试S程序接受并進(jìn)行連接,如發(fā)送和接受數(shù)據(jù)。為了建立通訊通道,網(wǎng)絡(luò)通訊的每一個(gè)端點(diǎn)具有1個(gè)套接字對(duì)象極其重要。
套接字為BSD UNIX系統(tǒng)核心的1部份,而且他們也被許多其他類似UNIX的操作系統(tǒng)包括Linux所采用。許多非BSD UNIX系統(tǒng)(如ms-dos,windows,os/2,mac os及大部份主機(jī)環(huán)境)都以庫情勢(shì)提供對(duì)套接字的支持。
3種最流行的套接字類型是:stream,datagram和raw。stream和datagram套接字可以直接與TCP協(xié)議進(jìn)行接口,而raw套接字則接口到IP協(xié)議。但套接字其實(shí)不限于TCP/IP。
2、套接字模塊
套接字模塊是1個(gè)非常簡(jiǎn)單的基于對(duì)象的接口,它提供對(duì)低層BSD套接字樣式網(wǎng)絡(luò)的訪問。使用該模塊可以實(shí)現(xiàn)客戶機(jī)和服務(wù)器套接字。要在python中建立具有TCP和流套接字的簡(jiǎn)單服務(wù)器,需要使用socket模塊。利用該模塊包括的函數(shù)和類定義,可生成通過網(wǎng)絡(luò)通訊的程序。1般來講,建立服務(wù)器連接需要6個(gè)步驟。
第1步是創(chuàng)建socket對(duì)象。調(diào)用socket構(gòu)造函數(shù)。
socket=socket.socket(familly,type)
要?jiǎng)?chuàng)建1個(gè)套接字,你必須使用socket.socket()函數(shù),它在socket模塊,其中有1般的語法:
下面是參數(shù)的描寫:
socket_family: 這是AF_UNIX或AF_INET,正如我剛才解釋.
socket_type: 這是SOCK_STREAM,或?yàn)镾OCK_DGRAM.
protocol: 這通常被不用關(guān)心,默許為0.
第2步則是將socket綁定(指派)到指定地址上,socket.bind(address)
address必須是1個(gè)雙元素元組,((host,port)),主機(jī)名或ip地址+端口號(hào)。如果端口號(hào)正在被使用或保存,或主機(jī)名或ip地址毛病,則引發(fā)socke.error異常。
第3步,綁定后,必須準(zhǔn)備好套接字,以便接受連接要求。
socket.listen(backlog)
backlog指定了最多連接數(shù),最少為1,接到連接要求后,這些要求必須排隊(duì),如果隊(duì)列已滿,則謝絕要求。
第4步,服務(wù)器套接字通過socket的accept方法等待客戶要求1個(gè)連接:
connection,address=socket.accept()
調(diào)用accept方法時(shí),socket會(huì)進(jìn)入'waiting'(或阻塞)狀態(tài)。客戶要求連接時(shí),方法建立連接并返回服務(wù)器。accept方法返回1個(gè)含有倆個(gè)元素的元組,形如(connection,address)。第1個(gè)元素(connection)是新的socket對(duì)象,服務(wù)器通過它與客戶通訊;第2個(gè)元素(address)是客戶的internet地址。
第5步是處理階段,服務(wù)器和客戶通過send和recv方法通訊(傳輸數(shù)據(jù))。服務(wù)器調(diào)用send,并采取字符串情勢(shì)向客戶發(fā)送信息。send方法返回已發(fā)送的字符個(gè)數(shù)。服務(wù)器使用recv方法從客戶接受信息。調(diào)用recv時(shí),必須指定1個(gè)整數(shù)來控制本次調(diào)用所接受的最大數(shù)據(jù)量。recv方法在接受數(shù)據(jù)時(shí)會(huì)進(jìn)入'blocket'狀態(tài),最后返回1個(gè)字符串,用它來表示收到的數(shù)據(jù)。如果發(fā)送的量超過recv所允許,數(shù)據(jù)會(huì)被截?cái)唷_^剩的數(shù)據(jù)將緩沖于接受端。以后調(diào)用recv時(shí),過剩的數(shù)據(jù)會(huì)從緩沖區(qū)刪除。
第6步,傳輸結(jié)束,服務(wù)器調(diào)用socket的close方法以關(guān)閉連接。
建立1個(gè)簡(jiǎn)單客戶連接則需要4個(gè)步驟。
第1步,創(chuàng)建1個(gè)socket以連接服務(wù)器 socket=socket.socket(family,type)
第2步,使用socket的connect方法連接服務(wù)器 socket.connect((host,port))
第3步,客戶和服務(wù)器通過send和recv方法通訊。
第4步,結(jié)束后,客戶通過調(diào)用socket的close方法來關(guān)閉連接。
實(shí)例:
這是Socket Server 部份:
import socket
s = socket.socket()
host = socket.gethostname()
port = 8088
s.bind((host,port))
s.listen(5)
while True:
c, addr = s.accept()
print 'Got connection from', addr
c.send('Thank you for connection')
c.close()
這是Socket Client 部份:
import socket
s = socket.socket()
host = socket.gethostname()
port = 8088
s.connect((host,port))
print s.recv(1024)
運(yùn)行時(shí),請(qǐng)將對(duì)應(yīng)的端口(這里是8088)添加到防火墻的InBound和OutBound的規(guī)則中。
urllib
和 urllib2
是Python標(biāo)準(zhǔn)庫中最強(qiáng)的的網(wǎng)絡(luò)工作庫。通過這兩個(gè)庫所提供的上層接口,使我們可以像讀取本地文件1樣讀取網(wǎng)絡(luò)上的文件。而且
urllib2
其實(shí)不是 urllib
的升級(jí)版本(應(yīng)當(dāng)是1種補(bǔ)充),2者是不可相互替換的。
通過使用 urllib
的 urlopen
函數(shù)可以很容易的打開遠(yuǎn)程的文件,以下:
from urllib import urlopen
webpage = urlopen('http://www.cnblogs.com/IPrograming/')
txt = webpage.readline(45)
print txt # !DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0
也能夠通過在通過在路徑的前面添加 file:
來訪問本地文件:
from urllib import urlopen
webpage = urlopen(r'file:D:Hsr23updADD_ABBR.txt')
txt = webpage.readline(45)
print txt
如果你還可以通過 urllib
提供的 urlretrieve
函數(shù),來直接保存遠(yuǎn)程文件副本:
from urllib import urlretrieve
webpage = urlretrieve('http://www.cnblogs.com/IPrograming/','C: emp.html')
print type(webpage) # <type 'tuple'>
除 socket、urllib和urllib2這些模塊之外標(biāo)準(zhǔn)庫還有很多和網(wǎng)絡(luò)相干的模塊,下面的列表是其中的1部份:
===========================================================
模塊 描寫
===========================================================
asynchat asyncore的增強(qiáng)版本
asyncore 異步socket處理程序
cgi 基本的CGI支持
Cookie Cookie對(duì)象操作,主要用于服務(wù)器操作
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服務(wù)器的robot文件
SimpleXMLRPCServer 1個(gè)簡(jiǎn)單的XML-RPC服務(wù)器
stmpd SMTP服務(wù)器模塊
smtplib SMTP客戶端模塊
telnetlib Telnet客戶端模塊
urlparse 支持解析URL
xmlrpclib XML-RPC的客戶端支持
可使用Python中的網(wǎng)絡(luò)/互聯(lián)網(wǎng)編程的1些重要的模塊列表.
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 |
請(qǐng)查看上面提到所有庫的合作與FTP,SMTP的POP,IMAP協(xié)議.
最后:
1、建立socket
建立socket對(duì)象需要弄清通訊類型和協(xié)議家族。通訊類型指明了用甚么協(xié)議來傳輸數(shù)據(jù)。協(xié)議的例子包括IPv4、IPv6、IPXSPX、AFP。對(duì)internet通訊,通訊類型基本上都是AF_INET(和IPv4對(duì)應(yīng))。協(xié)議家族1般表示TCP通訊的SOCK_STREAM或表示UDP通訊的SOCK_DGRAM。因此對(duì)TCP通訊,建立1個(gè)socket連接的語句為:
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
對(duì)UDP通訊,建立1個(gè)socket連接的語句為:
s=socket.socket(socket.AF_INET,SOCK_DGRAM)
2、連接socket
連接socket需要提供1個(gè)tuple,包括host(主機(jī)名或IP)和port(遠(yuǎn)程端口),類似代碼為:
s.connect(("www.baidu.com",80)
3、尋覓端口號(hào)
socket庫中利用getservbyname()函數(shù)可以查詢端口號(hào),1般需要兩個(gè)參數(shù):1是協(xié)議名,如http、smtp、pop3等,1個(gè)是端口名,如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地址和端口號(hào),也能夠通過getpeername()顯示遠(yuǎn)程機(jī)器的ip地址和端口號(hào)。
如:在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 低層網(wǎng)絡(luò)接口(每一個(gè) BSD API)
socket.socket(family, type) 創(chuàng)建并返回1個(gè)新的 socket 對(duì)象
socket.getfqdn(name) 將使用點(diǎn)號(hào)分隔的 IP 地址字符串轉(zhuǎn)換成1個(gè)完全的域名
socket.gethostbyname(hostname) 將主機(jī)名解析為1個(gè)使用點(diǎn)號(hào)分隔的 IP 地址字符串
socket.fromfd(fd, family, type) 從現(xiàn)有的文件描寫符創(chuàng)建1個(gè) socket 對(duì)象
Socket 模塊的實(shí)例方法
實(shí)例方法 說明
sock.bind( (adrs, port) ) 將 socket 綁定到1個(gè)地址和端口上
sock.accept() 返回1個(gè)客戶機(jī) socket(帶有客戶機(jī)真?zhèn)€地址信息)
sock.listen(backlog) 將 socket 設(shè)置成監(jiān)聽模式,能夠監(jiān)聽 backlog 外來的連接要求
sock.connect( (adrs, port) ) 將 socket 連接到定義的主機(jī)和端口上
sock.recv( buflen[, flags] ) 從 socket 中接收數(shù)據(jù),最多 buflen 個(gè)字符
sock.recvfrom( buflen[, flags] ) 從 socket 中接收數(shù)據(jù),最多 buflen 個(gè)字符,同時(shí)返回?cái)?shù)據(jù)來源的遠(yuǎn)程主機(jī)和端口號(hào)
sock.send( data[, flags] ) 通過 socket 發(fā)送數(shù)據(jù)
sock.sendto( data[, flags], addr ) 通過 socket 發(fā)送數(shù)據(jù)
sock.close() 關(guān)閉 socket
sock.getsockopt( lvl, optname ) 取得指定 socket 選項(xiàng)的值
sock.setsockopt( lvl, optname, val ) 設(shè)置指定 socket 選項(xiàng)的值
舉例:
>>> 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、處理毛病
關(guān)于毛病異常的處理,主要就是用try、except語句。如將python網(wǎng)絡(luò)編程學(xué)習(xí)筆記(1)中g(shù)opherclient.py進(jìn)行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+"
")
except socket.error,e:
print "數(shù)據(jù)發(fā)送毛病:%s" %e
sys.exit(1)
參考文獻(xiàn):
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