python學習筆記(網絡編程)

Python 內置封裝了不少常見的網絡協議的庫,所以Python成爲了一個強大的網絡編程工具,這裏是對Python的網絡方面編程的一個簡單描述。html

在標準庫中有不少網絡設計相關的模塊,除了那些明確處理網絡事務的模塊外,還有不少模塊也是是和網絡相關的,下面是幾個經常使用的網絡設計模塊:python

socket模塊

socket 模塊是網絡編程中的基礎組件。socket 主要的做用就是做爲兩個程序之間的「通訊信道」,不一樣進程(不一樣主機)能夠經過socket相互發送信息,以達到網絡通訊的目的。socket 包括兩個部分:服務端和客戶端。服務端監聽端口號,等待客戶端發送的消息;而客戶端在須要發送信息是,鏈接服務端,將信息發送出去便可。下面是一個簡單的同步網絡編程的簡單示例:react

一個小型服務器:web

#Socket Server
import socket

s=socket.socket()

host=socket.gethostname()
port=1234
s.bind((host,port))

s.listen(5)
while True:
    c,addr=s.accept()
    print 'Got connection from',addr
    c.send('Thank you for connecting')
    c.close()
    

一個小型客戶端:編程

#Socket Client
import socket

s=socket.socket()

host=socket.gethostname()
port=1234

s.connect((host,port))
print s.recv(1024)

運行時,請將對應的端口(這裏是1234)添加到防火牆的InBound和OutBound的規則中。windows

 

urllib和urllib2模塊

urllib 和 urllib2 是Python標準庫中最強的的網絡工做庫。經過這兩個庫所提供的上層接口,使咱們能夠像讀取本地文件同樣讀取網絡上的文件。並且 urllib2 並非 urllib 的升級版本(應該是一種補充),兩者是不可相互替代的。服務器

經過使用 urllib 的 urlopen 函數能夠很容易的打開遠程的文件,以下:cookie

>>> from urllib import urlopen
>>> webpage=urlopen('http://www.baidu.com')
>>> text=webpage.readline(36)
>>> print text
<!DOCTYPE html><!--STATUS OK--><html
>>> 

也能夠經過在經過在路徑的前面添加 file: 來訪問本地文件:網絡

>>> from urllib import urlopen
>>> webpage=urlopen(r'file:f:\python\myDemo\game.txt')
>>> txt=webpage.read()
>>> print txt
蛋蛋 1 10 10


>>> 

你還能夠經過 urllib 提供的 urlretrieve函數,來直接保存遠程文件副本:多線程

>>> from urllib import urlretrieve
>>> webpage=urlretrieve('http://www.baidu.com','f:\python\myDemo\webpage.html')
>>> print type(webpage)
<type 'tuple'>
>>> 

其餘模塊:

除了 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的客戶端支持  

 SocketServer

SocketServer模塊是標準庫中不少其餘服務器框架的基礎,這些服務器框架包括:BaseHTTPServer、SimpleHTTPServer、CGIHTTPServer、SimpleXMLRPCServer和DocXMLRPCServer,這些服務框架都是在基礎框架上增長了特定的功能。SocketServer包含了4個基本的類:

  • TCPServer,針對TCP的Socket
  • UDPServer,針對UDP數據報的Socket
  • UnixStreamServer
  • UnixDatagramServer

下面是一個基於SocketServer的簡單Socket Server端示例:

from SocketServer import TCPServer,StreamRequestHandler

class Handler(StreamRequestHandler):
    def handle(self):
        addr=self.request.getpeername()
        print 'Got connection from',addr
        self.wfile.write('Thank you for connecting')

server=TCPServer(('',1234),handler)
server.serve_forever()

多鏈接

通常狀況下Socket中的Client端經常不止一個,想要使Socket Server端能同時處理多個Client的鏈接通常由三種主要的方法:

  • 分叉(forking)(windows 不支持)
  • 線程(threading)
  • 異步I/O(asynchronous I/O)

使用分叉

分叉(fork)是一個UNIX術語;當分叉一個進程(一個運行的程序)時,基本上時複製了它,而且分叉後的兩個進程都從當前執行的點繼續運行,而且每一個進程都有本身的內存副本。一個進程(開始的那個)成爲另外一個進程的(複製的,也就是子進程)的父進程。在一個使用分叉的服務器中,每一個客戶端鏈接都利用分叉建立一個子進程。父進程繼續監聽鏈接,同時子進程處理客戶端。當客戶端的請求結束時,子進程退出。分叉的進程是並行執行的,客戶端直接沒必要相互等待。分叉的缺點是比較耗費資源(每一個分叉出來的進程都須要本身的內存)。下面是一個使用分叉建立Socket服務端的示例(使用了分叉(fork),Windows系統不支持):

from SocketServer import TCPServer,ForkingMixIn,StreamRequestHandler

class Server(ForkingMixIn,TCPServer):pass
class Handler(StreamRequestHandler):
    def handle(self):
        addr=self.request.getpeername()
        print 'Got connection from',addr
        self.wfile.write('Thank you for connecting')

server=TCPServer(('',1234),handler)
server.serve_forever()

使用線程

線程是輕量級的進程或子進程,全部的線程都存在於相同的進程(一個運行的程序)中,且共享內存。雖然使用多線程相對於分叉佔用的資源較少,可是因爲共享內存,全部必須要確保它們的變量不會衝突,或者是同一時間修改同一內容,這樣會形成混亂。這些問題能夠歸結爲同步問題。下面是使用多線程的一個簡單示例:

from SocketServer import TCPServer,ThreadingMixIn,StreamRequestHandler

class Server(ThreadingMixIn,TCPServer):pass
class Handler(StreamRequestHandler):
    def handle(self):
        addr=self.request.getpeername()
        print 'Got connection from',addr
        self.wfile.write('Thank you for connecting')

server=TCPServer(('',1234),handler)
server.serve_forever()

 帶有 select 和 poll 的異步I/O

在Python中的異步I/O的基礎就是 select 模塊的 select 函數。標準庫中的 asyncore 和 asynchat 模塊對它們進行了進一步的包裝,能夠從更高層次來處理異步I/O。poll 函數和 select 函數同樣,也屬於 select 模塊,這兩個函數的功能基本同樣,相對而言 poll 的伸縮性更好,但其職能在UNIX系統使用使用。

select 函數須要3個序列做爲它的必選參數(輸入、輸出、異常狀況),第四個參數是可選的,表示以秒爲單位的超時時間。下面是一個使用select 的簡單示例:

import socket,select

s=socket.socket()

host=socket.gethostname()
port=1234
s.bind((host,port))

s.listen(5)
inputs=[s]
while True:
    rs,ws,es=select.select(inputs,[],[])
    for r in rs:
        if r is s:
            c,addr=s.accept()
            print 'Got connection from ',addr
            imputs.append(c)
        else:
            try:
                data=r.recv(1024)
                disconnected=not data
            except socket.error:
                disconnected=True

            if disconnected:
                print r.getpeername(),'disconnected'
                inputs.remove(r)
            else:
                print data

poll 方法比 select 使用起來簡單,下面的時候就是上面示例的 poll 版本:

import socket,select

s=socket.socket()

host=socket.gethostname()
port=1234
s.bind((host,port))

fdmap={s.fileno():s}

s.listen(5)
p=select.poll()
p.register(s)
while True:
    events=p.poll()
    for fd,event in events:
        if fd in fdmap:
            c,addr=s.accept()
            print 'Got connection from ',addr
            p.register(c)
            fdmap[c.fileno()]=c
        elif event & select.POLLIN:
            data=fdmap[fd].recv(1024)
            if not data:
                print fdmap[fd].getpeername(),'disconnected'
                p.unregister(fd)
                del fdmap[fd]            
            else:
                print data

Twisted

Twisted是用Python實現的基於事件驅動的網絡引擎框架。

(參考資料:http://blog.csdn.net/hanhuili/article/details/9389433)。

下載和安裝

windows下,能夠直接下載安裝進行安裝 https://twistedmatrix.com/trac/wiki/Downloads        

到此彷佛安裝成功了,但在使用twisted時,即引入twisted時, 如:from twisted.internet.protocol import Protocol,ClientFactory

運行時會提示 ImportError: Twisted requires zope.interface 3.6.0 or later: no module named

因此還須要安裝zope包,直接下載安裝便可

https://pypi.python.org/pypi/zope.interface#downloads

使用twisted

from twisted.internet import reactor
from twisted.internet.protocol import Protocol,Factory

class SimpleLogger(Protocol):
    def connectionMade(self):
        print 'Got connection from',self.transport.client

    def connectionLost(self,reason):
        print self.transport.client,'disconnected'

    def dataReceived(self,data):
        print data

factory=Factory()
factory.protocol=SimpleLogger

reactor.listenTCP(1234,factory)
reactor.run()

使用LineReceiver協議改進的記錄服務器:

from twisted.internet import reactor
from twisted.internet.protocol import Factory
from twisted.protocol.basic import LineReceiver

class SimpleLogger(LineReceiver):
    def connectionMade(self):
        print 'Got connection from',self.transport.client

    def connectionLost(self,reason):
        print self.transport.client,'disconnected'

    def lineReceived(self,line):
        print line

factory=Factory()
factory.protocol=SimpleLogger

reactor.listenTCP(1234,factory)
reactor.run()
相關文章
相關標籤/搜索