第14章 网络编程
1.几个网络模块
1.模块socket
网络编程中的一个基本组件是socket(套接字)。
socket基本上是一个信息通道,两端各有一个程序。
套接字分为两类:服务器套接字和客户端套接字。
创建服务器套接字后,让它等待连接请求的到来。
客户端套接字只需连接,完成任务后断开连接。
套接字是模块socket中socket类的实例。
实例化套接字最多指定3参数:
地址族(默认为socket.AF_INET):
流套接字(socket.SOCK_STREAM,默认)/数据包套接字(socket.SOCK_DGRAM)
协议(默认0)
创建普通套接字无需提供参数。
服务器套接字先调用方法 bind,再调用方法 listen来监听方法bind指定的地址。
#地址是一个格式为(host,port)的元组。host是主机名,port是端口号。
方法 listen提供一个参数--待办任务清单的长度
服务器套接字开始监听后,就可接受(accept)客户端连接了。方法accept将阻断(等待) 直到客户端连接到来,返回一个(client, address)的元组,client是客户端套接字,address是地址。
为传输数据,套接字提供了2个方法:
send(发送):提供字符串
recv(接收):指定最多接收多少个字节的数据(1024是个不错的选择)
实例:
#服务器
import socket
s = socket.socket()
host = socket.gethostname()
port = 1234
s.bind((host,port))
s.listen()
while True:
c, addr = s.accept()
print('Got connection from', addr)
#注意下面这个字符串前加b转换成bytes
c.send(b'Thank you for connecting')
c.close()
#客户端
import socket
s = socket.socket()
host = socket.gethostname()
port = 1234
s.connect((host,port))
print(s.recv(1024))
2.模块urllib 和 urllib2
通过网络访问文件,可以使用URL(统一资源定位符)、
常见的应用是下载网页,提取信息。
1.打开远程文件
from urllib.request import urlopen
webpage = urlopen('http://www.python.org')
webpage将包含一个类似于文件的对象。支持文件的方法:close,readline,readlines等。
2.获取远程文件
urlretrieve返回一个格式为(filename,headers)的元组,filename是本地文件的名称,headers是一些文件相关的信息,如果给下载的文件指定名字,传入第二个参数。
from urllib.request import urlretrieve
urlretrieve('http://www.python.org','C:\\python_webpage.html')
3.其他模块(略)
2.SocketServer
创建服务器
SocketServer包含4个基本的服务器:
TCPServer,UDPServer,UnixStreamServer,UnixDatagramServer
使用模块SocketServer编写服务器时,大部分代码都位于请求处理器中。基本请求处理程序类BaseRequestHandler将所有的操作都放在一个方法中--服务器调用的方法handle。这个方法可通过属性self.request来访问客户端套接字。如果处理流,可使用StreamRequestHandler类,它有另外两个属性:self.rfile(读取)和self.wfile(写入)
实例:
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()
3.多个连接
处理多个连接的主要方式有3种:分叉(forking)、线程化和异步I/O。
分叉是一个Unix术语。对进程进行分叉时,基本上是复制它,得到两个进程都将从当前位置开始继续往下执行,且每个进程都有自己的内存副本。原进程是父进程,复制的进程是子进程。 在分叉服务器中,对每个客户端连接都通过分叉创建一个子进程,父进程继续监听,子进程处理客户端请求。请求结束,子进程退出。
线程是轻量级进程(子进程),都位于同一个进程中并共享内存。
1.使用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')
server = TCPServer(('', 1234), Handler)
server.serve_forever()
线程化服务器
from socketserver import TCPServer, ThreadingMinIn, 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')
sever = Server(('' ,1234), Handler)
server.serve_forever()
2.使用select和poll(UNIX)实现异步I/O
函数select接受3个参数和1个可选参数。
前3个参数为序列,第4个参数为超时时间(单位为秒)
这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)
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)
4.Twisted
Twisted 是一个事件驱动的python网络框架。
...