《Python基础教程》学习笔记(14网络)

14. 网络编程

14.1 少数几个网络设计模块

14.1.1 socket模块

一个套接字就是一个socket模块中的socket类的实例。它的实例化需要3个参数:

  • 第1个参数是地址族(默认:socket.AF_INET);
  • 第2个参数是流(默认:socket.SOCK_STREAM)或数据报(socket.SOCK_DGRAM)套接字;
  • 第3个参数是使用的协议(默认0)。

服务器端套接字使用bind方法后,再调用listen方法去监听给定的地址。一个地址就是一个格式为(host, port)的元组。

客户端套接字使用connect方法连接到服务器在connect方法中使用的地址与bind方法中的地址相同。

listen方法只有一个参数,即服务器未处理的连接的长度(即允许排队等待的连接数目,这些连接在停止接收之前等待接收)。

服务器端开始监听后,使用accept方法接受客户端的连接。该方法会阻塞直到客户端连接,然后返回(client, address)的元组,client是一个客户端套接字,address是一个前面解释过的地址。

套接字有两个方法:send和recv(用于接收),用于传输数据。

# 服务器端
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)

14.1.2 urllib和urllib2模块

打开远程文件

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

# localfile = urlopen('file:C:\\somefile.txt')

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

下例:想要提取前面打开的Python页中 “About” 连接的(相对)URL

import re
text = webpage.read()
m = re.search('<a href="([^"]+)" .*?>about</a>', text, re.IGNORECASE
m.group(1)

获取远程文件

如果想下载文件并在本地存储一个文件的副本,可以使用urlretrieve,它返回一个元组(filename, headers),filename是本地文件的名字(由urllib自动创建),headers包含一些远程文件的信息。

# 第二个参数为下载后的文件名,如果没指定,则会存放在临时的位置,用open函数可以打开它。
# 要清理临时文件,可以调用urlcleanup函数。
urlretrieve('http://www.python.org', 'C:\\python_webpage.html')

14.1.3 其他模块

模块描述
asynchatasyncore的增强版本
asyncore异步套接字处理程序
cgi基本的CGI支持
CookieCookie对象操作,主要用于服务器
cookielib客户端cookie支持
emailE-mail消息支持(包括MIME)
ftplibFTP客户端模块
gopherlibgopher客户端模块
httplibHTTP客户端模块
imaplibIMAP4客户端模块
mailbox读取集中邮箱的格式
mailcap通过mailcap文件访问MIME配置
mhlib访问MH邮箱
nntplibNNTP客户端
poplibPOP客户端
robotparser支持解析Web服务器的robot文件
SimpleXMLRPCServer一个简单的XML-RPC服务器
smtpdSMTP服务器
smtplibSMTP客户端
telnetlibTelnet客户端
urlparse支持解释URL
xmlrpclibXML-RPC的客户端支持

14.2 SocketServer

SocketServer模块是标准库中很多服务器框架的基础,这些服务器框架包括BaseHTTPServer、SimpleHTTPServer、CGIHTTPServer、SimpleXMLRPCServer和DocXMLRPCServer。

SocketServer包含4个基本的类:

  • 针对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.rfile用户读,self.wfile用户写入
        self.wfile.write('Thank you for connecting')
server = TCPServer(('', 1234), Handler)
server.serve_forever()

14.3 多连接

以上讨论的都是同步的。下面同时处理多个连接。

有3中主要的方法能实现这个目的:分叉(forking)、线程(threading)以及异步IO(asynchronous I/O)。

14.3.1 使用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(ThreadingMinIn, 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()

14.3.2 带有select和poll的异步I/O

select函数需要3个序列作为它的必选参数,此外还有一个可选的以秒为单位的超时时间作为第4个参数。

示例:使用了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

select模块中的polling事件常量

事件名描述
POLLIN读取来自文件描述符的数据
POLLPRI读取来自文件描述符的紧急数据
POLLOUT文件描述符已经准备好数据,写入时不会发生阻塞
POLLERR与文件描述符有关的错误情况
POLLHUP挂起,连接丢失
POLLNVAL无效请求,连接没有打开

示例:使用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()
# 注册一个文件描述符(或带有fileno方法的对象)
p.register(s)
while True:
    events = p.poll()
    # fd是文件描述符,event则告诉发生了什么,是一个位掩码(见上表)
    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

14.4 Twisted

Twisted是一个事件驱动的Python网络矿建。支持Web服务器、客户机、SSH2、SMTP、POP3、IMAP4、AIM、ICQ、IRC、MSN、Jabber、NNTP和DNS等等。

14.4.1 下载并安装

官网点击下载。

# 运行Distutils脚本安装
python setup.py install

14.4.2 编写Twisted服务器

使用Twisted的简单服务器

from twisted.internet from 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'

    # 通过dataReceived处理来自客户端的数据
    # 使用对象self.transport把数据发回到客户端,
    # 这个对象有一个write方法,也有一个包含客户机地址的client属性
    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'

    # 只要收到了一整行就调用事件处理程序lineReceived
    def lineReceived(self, line):
        print line

factory = Factory()
factory.protocol = SimpleLogger

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

14.5 本章的新函数

函数描述
urllib.urlopen(url[, data[, proxies]])通过URL打开一个类文件对象
urllib.rulretrieve(url[, fname[, hook[, data]]])通过URL下载一个文件
urllib.quote(string[, safe])引用特定的URL字符
urllib.quote_plus(string[, safe])和quote相同,但是将空格引用为+
urllib.unquote(string)和quote相反
urllib.unquote_plus(string)和quote_plus相反
urllib.urlencode(query[, doseq])在CGI请求中使用的编码映射
select.select(iseq, oseq, eseq[, timeout])找出准备好读/写的套接字
select.poll()为polling套接字创建一个poll对象
reactor.listenTCP(port, factory)Twisted函数,监听连接
reactor.run()Twisted函数,主服务器循环
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值