python功能模块详述_Python学习笔记_第十四章:网络编程

Python的网络编程解决方案:

Python内有很多针对常见网络协议的库

用Python很容易写出处理各种协议格式的代码(Python非常擅长于处理字节流的各种模式)

如果想了解更多Python中的网络编程,推荐:Jphn Goerzen 的 The Foundations of Python Network Programming

少数几个网络设计模块

socket模块

网络编程最基本的就是套接字(socket),它可以说是两个端点程序之间的“信息通道”,Python大部分模块隐藏了套接字的基本细节,不直接和套接字交互。

套接字分:服务器套接字、客户端套接字

可以通过实例化socket模块的socket类来获得一个套接字,需要3个参数,第一个是地址簇:默认为socket.AF_INET,第二个是流:默认为socket.SOCK_STREAM,第三个是使用的协议:默认为0,对于一个普通的套接字不需要任何参数。

获得套接字后可以通过bind方法绑定到一个地址,再调用listen方法去监听,listen方法的唯一参数为服务器未处理连接的长度。

服务器开始监听后就可以通过使用accept方法来接受客户端的连接,这个方法是阻塞的,直到有客户端连接,连接后其返回值为元祖(client, address),服务器处理完一个连接后,再次调用accept来等待下一个连接。

以上描述的服务器编程为阻塞或同步网络编程

套接字对象有两个方法:send和recv

在Linux或UNIX系统中,需要有系统管理员权限才能使用1024以下的端口。这些地域1024的端口被标准服务占用,如:80用于web

一个小型服务器:

import socket

s = socket.socket()

host = socket.gethostname()

print host

prot = 1234

s.bind((host, prot))

s.listen(5)

while True:

c, address = s.accept()

print 'Got connection form', address

c.send('Thank you for connect')

print c.recv(1024)

c.close()

一个小型客户端:

import socket

s = socket.socket()

host = socket.gethostname()

port = 1234

s.connect((host, port))

print s.recv(1024)

s.send('hello server')

urlib和urllib2模块的内容

在能用的各个网络库中,最强大的就数urlib和urllib2了,通过他们调用网络文件如调本地,几乎可以把任何URL指向的东西作为程序的输入。可以想象下将它们和re模块结合的效果。

这俩的功能相近,但urlib2更好点,如果只是简单的下载urlib就够了,如果需要HTTP验证或cookie,或者要为自己的协议编写扩展,那就urlib2更好了。

1.打开远程文件

>>> from urllib import urlopen

>>> webpage = urlopen('www.baidu.com')

>>> webpage = urlopen('http://www.baidu.com')

>>> webpage

2.获取远程文件

>>> from urllib import urlretrieve

>>> urlretrieve('http://www.python.org', 'C:\U')

>>> urlretrieve('http://www.python.org', r'C:\Users\hcs\Desktop\python_webpage.html')

('C:\\Users\\hcs\\Desktop\\python_webpage.html', )

以上,如果不指定保存位置,文件就会保存在零时位置,要清理,可以调用urlcleanup函数。

一些功能

处理读取和下载文件,urllib来提供了些函数操作URL本身:

函数

描述

quote(string[, safe])

返回一个字符串,其中所有URL特殊字符都被URL友好的字符代替

quote_plus(string[, safe])

和quote功能差不多,但用+代替空格

unquote(string)

和quote相反

unquote_plus(string)

和unquote_plus相反

urlencode(query[, doseq])

将映射或者包含两个元素的元组的序列转换为URL格式的字符串,这种字符串可以用于CGI查询

其他模块

标准库中一些和网络相关的模块

模块

描述

asynchat

asyncore的增强版(从更高层次处理异步IO的框架)

asyncore

……

cgi

通用网关接口

Cookie

Cookie对象操作,主要用于服务器

cookielib

客户端cookie支持

email

email消息支持

ftplib

FTP客户端模块

gopherlib

gopher客户端模块(Internet提供的采用菜单式驱动的信息查询工具,采用C/S)

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,所有的这些服务器框架都为基础服务器增加了特定的功能。

SocketServer包括四个基本的类:针对TCP流式套接字的TCPServer;针对UDP数据报套接字的UDPServer;以及针对性不强的UnixStreamServer和UnixDatagramServer。后三个不常用。

前面小型服务器的SocketServer版本:

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

print self.rfile.read()

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

server.serve_forever()

它能和前面小型客户端协同工作

Python参考库(http://python.org/doc/lib/module-SocketServer.html)和John Goerzen的The Foundations of Python Network Programming可以找到关于SocketServer的更多信息。

多个连接

前面的服务器解决方案都是同步的:即一次只能连接一个客户机并处理,为了实现异步可以有三种方法:分叉(forking)、线程(threading)以及异步I/O,分叉在现代UNIX和Linux系统很高效,但是windows不支持分叉。

通过SocketServer服务器使用混入类很容易派生进程和线程。

避免线程和分叉的另外一种方法是转换到Stackless Python(http://stackless.com),一个为了能够在不同的上下文之间快速、方便切换而设计的Python版本。,它支持一个叫做微线程的类线程的并行形式。

使用Socket Server进行分叉和线程处理

使用分叉技术的服务器(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')

self.rfile.read()

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

self.rfile.read()

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

server.serve_forever()

不知道为啥,两种方式实现的效果一样,都不太正常

带有select和poll的异步I/O

这种处理方式只处理在给定的时间内真正要进行通信的客户端,不需要一直监听,只需要监听一会,然后把它放到其他客户端的后面。这个功能的基础是select,如果poll可用,也可以是它,这两个函数都来自select模块。poll只能在UNIX中使用。

select有三个必选的序列参数,还有一个可选的以秒为单位的超时时间作为第四个参数。三个序列为文件描述符整数或者带有可以产生这样整数的fileno方法的对象,这些都是我们等待连接的对象。

三个序列分别用于:输入、输出、异常情况,select函数的输出为三个序列,分别对应这三种输入参数序列的一个活动子集

序列能包含文件对象(在windows中行不通)或者套接字。

简单的select服务器

import socket, select

s = socket.socket()

addr = socket.gethostname()

s.bind((addr, 1234))

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:

disconnected = True

if disconnected:

print r.getpeername(), 'disconnected'

inputs.remove(r)

else:

print data

poll方法返回的元组(fd, event)中event的类型(select模块中的polling时间常量类型)有:

事件名

描述

POLLIN

读取来自文件描述符的数据

POLLPRI

读取来自文件描述符的紧急数据

POLLOUT

文件描述符已经准备好数据,写入时不会发生阻塞

POLLERR

与文件描述符有关的错误情况

POLLHUP

挂起,连接丢失

POLLNVAL

无效请求,连接没有打开

使用poll代替select的代码(只有在UNIX有用)

import select, socket

s = socket.socket()

addr = socket.gethostname()

port = 1234

s.bind((addr, port))

s.listen(5)

fdmap = {s.fileno() : s}

p = select.poll()

p.register(s)

while True:

events = p.poll()

for fd, event in events:

if fd == s.fileno():

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网络框架,它能和几个常见的GUI工具包(Tk, GTK, Qt, wxWidget)协同工作。它相当丰富,支持web服务器、客户机、SSH2、SMTP、POP3、IMAP4、AIM、ICQ、IRC、MSN、Jabber、NNTP和DNS等等。

下载和安装Twisted

windows直接登录网址http://twistedmatrix.com下载Python版本对应的Windows安装程序就好

其他系统:如果有包管理器(APT、RPM、DPKG、Portage、Fink、MacPorts)那么可以用它们直接安装,如果没有用包管理器,则需要下载档案文件,用tar命令解压缩后运行Distutils脚本:python setup.py install

编写Twisted服务器

Twited使用一个事件甚至多个基于事件的方法,要编写基本的服务器就要实现处理比如:新客户端连接、数据到达以及一个客户端断开连接等事件的事件处理程序。下面是个例子:

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

上面的服务器程序每行之输出了个字符,为了能实现每次输出一行,twisted.protocols.basic模块中包含一个有用的预定义协议,是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 dataReceived(self, line):

print line,

factory = Factory()

factory.protocol = SimpleLogger

reactor.listenTCP(1234, factory)

reactor.run()

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值