网络编程
1. 网络编程基础模块
-
socket模块
-
网络编程中基本组件就是嵌套字(socket),嵌套字基本上就是两个端点的程序之间的“信息通道”。python中嵌套字主要使用socket模块。
-
嵌套字包括服务端嵌套字和客户端嵌套字,服务端在创建嵌套字等待连接,客户端通过ip和端口连接服务端
-
一个嵌套字就是socket模块中socket类的一个实例,实例化时需要3个参数,对于普通嵌套字,不需要提供任何参数
参数 默认值 可选值 第一个参数地址族 socket.AF_INET AF_UNIX 第二个参数流 socket.SOCK_STREAM socket.SOCK_DGRAM - 数据报 第三个参数协议 0 -
实例化一个socket后,服务端使用bind绑定主机地址和端口,在调用listen方法开始监听,客户端则使用connect方法连接到服务器,connect方法中使用的地址与服务器bind方法中的地址相同。
-
listen方法只有一个参数,服务器未处理的连接的长度(即允许排队等待的连接数目)。
-
一个地址就是格式为(host, port)的元组,服务端可以使用socket.gethostname得到当前的主机名
-
服务端开始监听后接收客户端的连接,使用accept方法来完成,accept方式是阻塞式的,连接建立后返回一个(client, address)的元组,client是客户端嵌套字,address是地址元组。
-
嵌套字传输数据是使用send和recv方法,recv使用所需的最大字节数参数来接收数据,send使用字符串参数发送数据
-
-
urllib和urlib2
-
urllib有基础的功能,urllib2包括了http验证或cookie等功能
# urllib使用 >>> from urllib import urlopen >>> webpage = urlopen('http://www.python.org') #urlopen返回的是一个类文件对象,支持close,read,readline和readlines >>> import re >>> text = webpage.read() >>> m = re.search('<a href="([^"]+)" .*?>about</a>', text, re.IGNORECASE) >>> m.group(1) '/about' #获取远程文件urlretrieve, 返回一个元组(filename, headers) urlretrieve('http://www.python.org', r'c:\python_webpage.html')
-
-
其他模块
模块 描述 asynchat asyncore的增强版 asyncore 异步嵌套字处理程序 cgi 基本的CGI支持 Cookie Cookie对象操作,主要用于服务器 Cookielib 客户端Cookie支持 email E-mail消息支持(包括MIME) ftplib Ftp客户端模块 gopherlib gopher客户端模块 httplib HTTP客户端模块 imaplib IMAP4客户端 mailbox 读取几种邮箱的格式 mailcap 通过mailcap文件访问MIME配置 -
SocketServer模块
-
SocketServer模块是标准库中很多服务器框架的几次,增加了服务端socket的特定功能
-
SocketServer封装了4个类,针对TCP的TCPServer,针对UDP的UDPServer,以及UnixStreamServer和unixDatagramServer
# SocketServer使用方法 # 编写使用SocketServer框架的服务,大部分代码放在一个请求处理程序中(request handler) # 每当服务器收到一个请求,就会实例化一个请求处理程序,并各种处理方法(handler method)会在处理请求时被调用 #socket_server_demo.py class Handler(StreamRequestHandler): def handle(self): addr = self.request.getpeername() print 'Got connection from', addr self.wfile.write('Thank you for connecting') def socket_server_demo(): #host = socket.gethostname() server = TCPServer(('', 1234), Handler) server.serve_forever() if __name__ == "__main__": #main() socket_server_demo() #socket_client.py import socket def main(): s = socket.socket() host = socket.gethostname() port = 1234 s.connect((host, port)) print s.recv(1024) if __name__ == "__main__": main()
-
2. 同时多个连接
- 分叉(forking)
- 线程(threading)
- 异步I/O(asynchronous)
# forking为linux/unix上的技术,fork一个进程时,基本上是负载它,属于多进程技术,windows上不支持
#! /bin/sh
# -*- coding: utf-8 -*-
# file name: socket_server_mixin
import time
from SocketServer import TCPServer, ForkingMixIn, StreamRequestHandler
from SocketServer import ThreadingMixIn
class ServerForking(ForkingMixIn, TCPServer):
pass
class ServerThreading(ThreadingMixIn, TCPServer):
pass
class Handler(StreamRequestHandler):
def handle(self):
addr = self.request.getpeername()
print 'Got connection form', addr
print 'waiting for 10s'
time.sleep(10)
self.wfile.write('Thank you for connecting')
if __name__ == "__main__":
#forking方式
s = ServerForking(('', 1234), Handler)
# threading方式
#s = ServerThreading(('', 1234), Handler)
s.serve_forever()
# 3. 异步I/O,异步I/O的基础是select/poll函数,来自select模块,poll伸缩性很好,但只能用于unix系统
# select函数需要3个序列参数,分别是输入,输出,异常,序列是文件描述符整数或者有返回这样整数的fileno参数,第4个参数是单位为秒的超时时间,如果没有给seelect会阻塞,如果为0那么就给出一个连续的poll,返回长度为3的元组
#! /bin/sh
# -*- coding: utf-8 -*-
# file name: socket_server_select.py
import socket
import 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, [], [], 1)
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
# 1. pool函数,调用是返回一个poll对象,使用poll对象register方法注册一个文件描述符或带有fileno的对象,注册后可以使用unregister方法移除,注册后调用poll方法(带有可选的的超时时间参数)并得到(fd, event)元组,fd是文件描述符,event事件,event为位掩码,不同的事件是select模块的常量
def socket_poll():
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 == 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
事件名 | 描述 |
---|---|
POLLIN | 读取来自文件描述符的数据 |
POLLPRI | 读取来自文件描述符的紧急数据 |
POLLOUT | 文件描述符已经准备好数据,写入时不会发生阻塞 |
POLLERR | 与文件描述符有关的错误情况 |
POLLHUP | 挂起,连接丢失 |
POLLNVAL | 无效请求,连接没有打开 |
3. Twisted
#! /usr/bin/python
# -*- coding: utf-8 -*-
#file name: socket_server_twisted.py
import socket
from twisted.internet import reactor
from twisted.internet.protocol import Protocol, Factory
from twisted.protocols.basic import LineReceiver
class SimpleLogger(Protocol):
def connectionMade(self):
print 'get connection from', self.transport.client
def connectionLost(self, reason):
print self.transport.client, 'disconnected'
def dataReceived(self, data):
print data
class SimpleLineLogger(LineReceiver):
def connectionMade(self):
print '[Line recevier]', 'get connection from', self.transport.client
self.sendLine('welcome to %s' % socket.gethostname())
self.setLineMode()
def connectionLost(self, reason):
print '[Line recevier]', self.transport.client, 'disconnected'
def lineReceived(self, line):
print '[Line recevier]', line
#def dataReceived(self, data):
# print '[Data recevier]', data
factory = Factory()
#factory.protocol = SimpleLogger
factory.protocol = SimpleLineLogger
reactor.listenTCP(1234, factory)
reactor.run()
#! /user/bin/python
# -*- coding: utf-8 -*-
# file name: socket_client.py
import socket
def main():
s = socket.socket()
#s.setblocking(False)
#print 'default timeout', s.getdefaulttimeout()
#s.setdefaulttimeout(1)
#host = socket.gethostname()
host = "192.168.1.198"
port = 1234
rlt = s.connect((host, port))
#print rlt
print 'Hello %s, %s\n' % s.getsockname()
s.send('Hello %s, %s\r\n' % s.getsockname())
print s.recv(1024),
if __name__ == "__main__":
main()