Python学习笔记14:网络编程

文章介绍了Python中的网络编程基础,包括socket模块的简单服务器和客户端实现,urllib和urllib2模块用于打开和获取远程文件的功能,以及SocketServer框架下的服务器实现。此外,还讨论了分叉和线程化处理多个连接,以及使用select和poll实现异步I/O。最后提到了Twisted框架,它是一个基于事件的网络编程库,适合编写复杂的服务器应用。
摘要由CSDN通过智能技术生成

网络编程

几个网络模块

  1. 模块socket
# 简单的服务器
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))

  1. 模块urllib和urllib2

打开远程文件:urlopen

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

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

获取远程文件:urlretrieve

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

清空这样的临时文件:urlcleanup

  1. 其他模块

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

模块描述
asynchat包含补充asyncore的功能(参见第24章)
asyncore异步套接字处理程序(参见第24章)
cgi基本的CGI支持(参见第15章)
CookieCookie对象操作,主要用于服务器
cookielib客户端Cookie支持
email电子邮件(包括MIME)支持
ftplibFTP客户端模块
gopherlibGopher客户端模块
httplibHTTP 客户端模块
imaplibIMAP4客户端模块
mailbox读取多种邮箱格式
mailcap通过mailcap文件访问MIME配置
mhlib访问MH邮箱
nntplibNNTP客户端模块(参见第23章)
poplibPOP客户端模块
robotparser解析Web服务器robot文件
SimpleXMLRPCServer一个简单的XML-RPC服务器(参见第27章)
smtpdSMTP服务器模块
smtplibSMTP客户端模块
telnetlibTelnet客户端模块
urlparse用于解读URL
xmlrpclibXML-RPC客户端支持(参见第27章)

SocketServer

  • 4个基本服务器:TCPServer(支持TCP套接字流)、UDPServer(支持UDP数据报套接字)以及更难懂的UnixStreamServerUnixDatagramServer。
  • 请求处理器:基本请求处理程序类BaseRequestHandler将所有操作都放在一个方法中——服务器调用的方法handle。这个方法可通过属性self.request来访问客户端套接字。可使用StreamRequestHandler类,它包含另外两个属性:self.rfile(用于读取)和self.wfile(用于写入)。
# 基于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()

多个连接

  • 分叉(forking) 占用的资源较多,且在客户端很多时可伸缩性不佳(但只要客户端数量适中,分叉在现代UNIX和Linux系统中的效率很高。如果系统有多个CPU,效率就更高了)
  • 线程化 可能带来同步问题
  • 异步I/O
  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(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()

  1. 使用 select 和 poll 实现异步 I/O

当服务器与客户端通信时,来自客户端的数据可能时断时续

  • 分叉和线程化:一个进程(线程)等待数据时,其他进程(线程)可继续处理其客户端。
  • 异步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 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)

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

PS:你不能使用事件处理策略来向客户端发送数据。这种工作是使用对象self.transport完成的,它包含一个write方法。这个对象还有一个client属性,其中包含客户端的地址(主机名和端口)。

小结

套接字和模块socket:套接字是让程序(进程)能够通信的信息通道,这种通信可能需要通过网络进行。模块socket让你能够在较低的层面访问客户端套接字和服务器套接字。服
务器套接字在指定的地址处监听客户端连接,而客户端套接字直接连接到服务器。

urllib和urllib2:这些模块让你能够从各种服务器读取和下载数据,为此你只需提供指向数据源的URL即可。模块urllib是一种比较简单的实现,而urllib2功能强大、可扩展
性极强。这两个模块都通过诸如urlopen等函数来完成工作。

框架SocketServer:这个框架位于标准库中,包含一系列同步服务器基类,让你能够轻松地编写服务器。它还支持使用CGI的简单Web(HTTP)服务器。如果要同时处理多个连
接,必须使用支持分叉或线程化的混合类。

select和poll:这两个函数让你能够在一组连接中找出为读取和写入准备就绪的连接。这意味着你能够以循环的方式依次为多个连接提供服务,从而营造出同时处理多个连接的
假象。另外,相比于线程化或分叉,虽然使用这两个函数编写的代码要复杂些,但解决
方案的可伸缩性和效率要高得多。

Twisted:这是Twisted Matrix Laboratories开发的一个框架,功能丰富而复杂,支持大多数主要的网络协议。虽然这个框架很大且其中使用的一些成例看起来宛如天书,但其基本用法简单而直观。框架Twisted也是异步的,因此效率和可伸缩性都非常高。对很多自定
义网络应用程序来说,使用Twisted来开发很可能是最佳的选择。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值