设为首页 收藏本站
查看: 903|回复: 0

[经验分享] 12、Python-网络编程

[复制链接]

尚未签到

发表于 2015-4-25 09:37:47 | 显示全部楼层 |阅读模式
  1、套接字
1.1 socket模块
套接字是网络编程中的一个基本组件,一般包括服务器端套接字和客户端套接字。
  创建服务器端过程如下:



1 import socket
2
3 s = socket.socket()
4
5 host = socket.gethostname()
6 port = 1234
7 try:
8     s.bind((host, port))
9 except Exception, e:
10     print e
11     s.close()
12
13 s.listen(5)
14 while True:
15     c, addr = s.accept()
16     print 'Got connection from', addr
17     c.send('Thank you for connecting')
18 c.close()
  创建客户端过程如下:



1 import socket, time
2
3 s = socket.socket()
4
5 host = socket.gethostname()
6 port = 1234
7
8 s.connect((host, port))
9 print s.recv(1024)
10 while True:
11     command = 'hello\n'
12     s.send(command)
13 time.sleep(1)
  该过程的通讯方式是一问一答的形式,所以又称为阻塞或者同步网络编程。
1.2 SocketServer和它的朋友们
  SocketServer模块是标准库中很多服务器框架的基础,这些服务器框架包括BaseHTTPServer、SimpleHTTPServer、CGIHTTPServer、SimpleXMLRPCServer和DocXMLRPCServer,所有的这些服务器框架都为基础服务器增加了特定的功能。
  SocketServer包含4个基本的类:针对TCP套接字流的TCPServer;针对UDP数据报套接字的UDPServer;以及针对性不强的UnixStreamServer和UnixDatagramServer。
  在使用SocketServer服务器框架时,每当服务器收到一个请求,就会实例化一个请求处理程序,并且它的各种处理方法(handler methods)会在处理请求时被调用。基本的BaseRequestHandler类把所有的操作都放到了处理器的一个叫做handle的方法中,这个方法会被服务器调用。然后在这个方法内就可以访问属性self.request中的客户端套接字。如果使用的是流(TCPServer),那么可以使用StreamRequestHandler类,创建它的两个属性,self.rfile(用于读取)和self.wfile(用于写入)。



1 from SocketServer import TCPServer, StreamRequestHandler
2
3 class Handler(StreamRequestHandler):
4
5     def handle(self):
6         addr = self.request.getpeername()
7        
8         print 'Got connection from', addr
9         self.wfile.write('Thank you for connecting')
10 server = TCPServer(('', 1234), Handler)
11 server.serve_forever()
  2、多连接
  同时可以有多个客户机连接服务端进行请求处理。有3个主要的方法能实现这个目的:分叉(forking)、线程(threading)以及异步I/O(asynchronous I/O)。它们有各自的缺点:分叉占资源,如果有太多的客户端时,分叉不能很好地分叉;线程处理能导致同步问题。
  什么是分叉:当分叉一个进程(一个运行的程序)时,基本上是复制了它,并且分叉后的两个进程都从当前的执行点继续运行,并且每个进程都有自己的内存副本(比如变量)。一个进程(原来的那个)成为父进程,另一个(复制的)成为子进程。因为分叉的进程是并行运行的,客户端之间不必相互等待。但分叉有点消耗资源(每个分叉出来的进程都需要自己的内存),这就存在了另一个选择:线程。
  什么是线程:线程是轻量级的进程或子进程,所有的线程都存在于相同的(真正的)进程中,共享内存。资源消耗的下降伴随着一个缺陷:因为线程共享内存,所以必须确保它们的变量不会冲突,或者是在同一时间修改同一内容,这就会造成混乱。
使用SocketServer框架创建分叉或者线程服务器太简单了,几乎不需要解释。注意,Windows不支持分叉。
使用分叉技术的服务器:



1 from SocketServer import TCPServer, ForkingMixIn, StreamRequestHandler
2
3 class Server(ForkingMixIn, TCPServer): pass
4
5 class Handler(StreamRequestHandler):
6
7     def handle(self):
8         addr = self.request.getpeername()
9         print 'Got connection from', addr
10         self.wfile.write('Thank you for connecting')
11
12 server = Server(('', 1234), Handler)
13 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()
    什么是异步I/O:当一个服务器与一个客户端通信时,来自客户端的数据可能是不连续的。如果使用分叉或线程处理,那就不是问题。当一个程序在等待数据,另一个并行的程序可以继续处理它们自己的客户端。另外的处理方法是只处理在给定时间内真正要进行通信的客户端。
  这是asyncore/asynchat框架采用的方法,这种功能的基础是select函数,如果poll函数可用,那也可以是它,这两个函数都来自select模块。其中poll函数的伸缩性要更好,但只能用在UNIX系统中。
  Select函数有3个序列作为它的必选参数,还有一个可选的超时时间作为第4个参数。这3个序列是套接字文件描述符,用于输入、输出以及异常情况。如果没有给定超时时间,select会阻塞,处于等待状态,直到一个文件描述符已经为行动做好了准备;如果给定超时时间,select最多阻塞给定的超时时间;如果给定的超时时间是0,select就不阻塞。Select的返回值是3个序列,一个长度为3的元组,每个代表相应参数的一个活动子集。



1 import socket, select
2
3 s = socket.socket()
4
5 host = socket.gethostname()
6 port = 1234
7 s.bind((host, port))
8
9 s.listen(5)
10 inputs =
11 while True:
12     rs, ws, es = select.select(inputs, [], [])
13     for r in rs:
14         if r is s:
15             c, addr = s.accept()
16             print 'Got connection from', addr
17             inputs.append(c)
18         else:
19             try:
20                 data = r.recv(1024)
21                 disconnected = not data
22             except socket.error:
23                 disconnected = True
24             if disconnected:
25                 print r.getpeername(), 'disconnected'
26                 inputs.remove(r)
27             else:
28                 print data
  poll方法使用起来比select简单。在调用poll时,会得到一个poll对象。然后使用poll对象的register方法注册一个文件描述符(或者是带有fileno方法的对象)。注册后可以使用unregister方法移除注册的对象。注册完套接字对象之后可以调用poll方法(带有一个可选的超时时间参数)并得到一个(fd, event)格式列表(可能是空的),其中fd是文件描述符,event则告诉你发生了什么。event对象是一个位掩码,可以使用按位与操作来判断事件的类型.
select模块中的polling事件常量
事件名         描述
POLLIN       读取来自文件描述符的数据
POLLPRI       读取来自文件描述符的紧急数据
POLLOUT      文件描述符已经准备好数据,写入时不会发生阻塞
POLLERR        与文件描述符有关的错误情况
POLLHUP     挂起,连接丢失
POLLNVAL   无效请求,连接没有打开



1 import socket, select
2
3 s = socket.socket()
4
5 host = socket.gethostname()
6 port = 1234
7 s.bind((host, port))
8
9 fdmap = {s.fileno(): s}
10
11 s.listen(5)
12 p = select.poll()
13 p.register(s)
14 while True:
15     events = p.poll()
16     for fd, event in events:
17         if fdmap[fd] is s:
18             c, addr = s.accept()
19             print 'Got connection from', addr
20             p.register(c)
21             fdmap[c.fileno()] = c
22         elif event & select.POLLIN:
23             data = fdmap[fd].recv(1024)
24             if not data: # No data -- connection closed
25                 print fdmap[fd].getpeername(), 'disconnected'
26                 p.unregister(fd)
27                 del fdmap[fd]
28             else:
29                 print data
  

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-60453-1-1.html 上篇帖子: 分享python 函数返回值 下篇帖子: 建立eclipse+PyDev+Python+NumPy+SciPy的环境
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表