网络编程

少数几个网络设计模块

socket模块

网络编程中一个基本组件就是套接字(socket)——两个端点的程序之间的“信息通道”。程序通过网络连接,通过套接字相互发送信息。
套接字包括两个:服务器套接字和客户机套接字。在创建一个服务器套接字后,让它在某个网络地址处(IP地址和端口的组合)监听,直到有客户端套接字连接。连接完成后,两者就可以进行交互了。
服务器端套接字使用bind方法后,再调用listen方法去监听某个特定的地址。客户端套接字使用connect方法连接到服务器,在connect方法中使用的地址与服务器在bind方法中的地址相同。

一个小型服务器

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()

一个小型客户机

import socket

s = socket.socket()

host = socket.gethostname()
port = 1234

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

urllib和urllib2模块

在能使用的各种网络函数库中,功能最强大的可能是urllib和urllib2了。通过它们在网络上访问文件,就好像访问本地电脑上的文件一样。通过一个简单的函数调用,几乎可以把任何URL所指向的东西用作程序输入。

打开远程文件

可以像打开本地文件一样打开远程文件,不同之处是只能使用只读模式。使用来自urllib模块的urlopen:

>>> from urllib import urlopen
>>> webpage = urlopen('http://www.python.org')

urlopen返回的类文件对象支持close、read、readline和readlines方法,当然也支持迭代。

获取远程文件

urllib为你下载文件并在本地文件中储存一个文件的副本——urlretrieve。

urlretrieve('http://www.python.org', 'C://python_webpage.html')
清理临时文件使用urlcleanup

其他模块

模块 描述
asynchat asyncore的增强版本
asyncore 异步套接字处理程序
cgi 基本的CGI支持
Cookie 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服务器
smtpd SMTP服务器端模块
smtplib SMTP客户端模块
telnetlib Telnet客户端模块
urlparse 支持解释URL
xmlrpclib XML-RPC的客户端支持

SocketServer和它的朋友们

SocketServer模块是标准库中很多服务器框架的基础——这些服务器包括BaseHTTPServer、SimpleHTTPServer、CGIHTTPServer、SimpleXMLRPCServer和DocXMLRPCServer,所有这些服务器框架都为基础服务器增加了特定的功能。

多个连接

分叉、线程、异步I/O连接

使用SocketServer进行分叉和线程处理

使用分叉技术

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 = Server(('', 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 = Server(('', 1234), Handler)
server.serve_forever()

带有select和poll的异步I/O

使用了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
            inputs.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的简单服务器

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 fdmap[fd] is s:
            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: # No data -- connection closed
                print fdmap[fd].getpeername(), 'disconnected'
                p.unregister(fd)
                del fdmap[fd]
            else:
                print data

Twisted

Twisted是一个事件驱动的Python网络框架,原来是为网络游戏开发的,现在被所有类型的网络软件使用。

下载安装Twisted

编写Twisted服务器

使用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.protocols.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()

小结

套接字和socket模块
urllib和urllib2
SocketServer框架
select和poll
Twisted

推荐阅读更多精彩内容