自己实现多线程的socket,socketserver源码剖析
1,IO多路复用
三种多路复用的机制:select、poll、epoll
用的多的两个:select和epoll
简单的说就是:
1,select和poll所有平台都支持,epoll只有linux支持
2,select效率不高,epoll效率高
3,IO多路复用用来监听socket对象内部是否变化
4,要调用select模块
什么是文件描述符:
当程序打开一个现有文件或者创建一个新文件时,内核向进程返回一个文件描述符。文件描述符的有效范围是 0 到 OPEN_MAX
linux查看OPEN_MAX的方法:ulimit -n。linux默认最大文件描述符为1024,一般可以将它改为65535,可以使用命令ulimit -HSn 65535。也可以保存到/etc/security/ulimit.conf里
python的select函数:
def select(rlist, wlist, elist, timeout=None)->(rl,wl,el)
rlist获取变化的句柄添加到rl中
只要wlist有句柄,都放到wl中
当elist某个句柄发生错误时,放到el中
timeout,如果没有设置超时时间,select一直会卡着,如果设置timeout=1,表示句柄没有变化时,select会卡1秒,一有变化就执行
在socket中
select用来监听sk连接时候的句柄和收发数据的句柄
import socket
import select
sk=socket.socket()
sk.bind(("127.0.0.1",9999))
sk.listen(2)
inputs=[sk]
outputs=[]
msg={}
while True:
rlist,wlist,e=select.select(inputs,outputs,[],1)
print(len(inputs),len(rlist),len(wlist),len(outputs))
'''
只要有连接进来,就接收,只要有收发消息的句柄发生变化,就收消息,
收到消息后可以不直接发送,存到outputs里,wlist==outputs,
只要outputs里有句柄,就交给wlist去循环发送
'''
for r in rlist:
if r==sk:
conn,addr=r.accept()
inputs.append(conn)
else:
try:
rt=r.recv(1024)
outputs.append(r)
print(rt)
msg.setdefault(r, [])
msg[r].append(rt)
except:
inputs.remove(r)
del msg[r]
#上面如果没有数据,这边就一直发数据给客户端,直到客户端接收消息,得到的是一大串
for w in wlist:
for m in msg[w]:
w.sendall(m)
outputs.remove(w) #所以发送完这边要删除句柄,解决了无限发数据的问题
socketserver源码剖析
通过上面的实验得出规律:一开始建立socket对象到listen这几步都没变,直到accept之间在循环使用select检查sk是否变化,如果有新链接进来就accept,之后就能通信了。
import socketserver class MyServer(socketserver.BaseRequestHandler): def handle(self):
# print self.request,self.client_address,self.server
conn = self.request
while True:
recv_data=conn.recv(5) conn.sendall(recv_data) if __name__ == '__main__':
server = socketserver.ThreadingTCPServer(('127.0.0.1',8009),MyServer)
print(server.server_address)
server.serve_forever()
这是socketserver服务器端实现代码
第一步:建立socket对象到listen这几步肯定在创建构造函数的时候已经做掉了。
第二步:因为它是多线程,select查看有sk变动后,每次有连接进来就分配一个线程给sk,然后accept连接
第三步:在accept之后调用socketserver.BaseRequestHandler来收发消息,在调用MySocket的handle,也就是调用BaseRequestHandler的handle
第四步:forever()
ThreadingTCPServer的继承关系:
import socket
import select
import threading def handle(sk):
'''此处发送'''
sk.sendall(bytes("hello",encoding="utf-8")) sk=socket.socket()
sk.bind(("127.0.0.1",9999))
sk.listen(5)
while True:
rlist,w,e=select.select([sk],[],[],1)
for r in rlist:
conn,addr=r.accept()
th=threading.Thread(target=handle,args=(conn,))
th.daemon=False
th.start()
sk.close()
socketserver简化
import socket sk=socket.socket()
sk.connect(("127.0.0.1",9999))
print(sk.recv(1024))
sk.close()
client
自己实现多线程的socket,socketserver源码剖析的更多相关文章
- socketserver 源码剖析:
socketserver 源码剖析[有图有真相]: (一).Socketserver 内部流程调用图: 详解: 1.self.RequestHandlerClass() = MyCla ...
- socketserver源码剖析
作者:人世间链接:https://www.jianshu.com/p/357e436936bf來源:简书简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处 BaseServer 和 B ...
- Java多线程9:ThreadLocal源码剖析
ThreadLocal源码剖析 ThreadLocal其实比较简单,因为类里就三个public方法:set(T value).get().remove().先剖析源码清楚地知道ThreadLocal是 ...
- java多线程17:ThreadLocal源码剖析
ThreadLocal源码剖析 ThreadLocal其实比较简单,因为类里就三个public方法:set(T value).get().remove().先剖析源码清楚地知道ThreadLocal是 ...
- 第二十四篇、socketserver源码剖析
这里选择的是python2.7(python3和2.7的源码基本类似) #!/usr/bin/env python # -*- coding:utf-8 -*- import SocketServer ...
- socket_server源码剖析、python作用域、IO多路复用
本节内容: 课前准备知识: 函数嵌套函数的使用方法: 我们在使用函数嵌套函数的时候,是学习装饰器的时候,出现过,由一个函数返回值是一个函数体情况. 我们在使用函数嵌套函数的时候,最好也这么写. def ...
- python_way day10 python和其他语言的作用域 、 python2.7多继承和3.5多继承的区别 、 socket 和 socketserver源码(支持并发处理socket,多进程,多线程)
python_way day10 1.python的作用域和其他语言的作用域 2.python2.7多继承和3.5多继承的区别 3.socket和socketserver源码(并发处理socket) ...
- python基础-11 socket,IO多路复用,select伪造多线程,select读写分离。socketserver源码分析
Socket socket通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄,应用程序通常通过"套接字"向网络发出请求或者应答网络请求. sock ...
- Python之socketserver源码分析
一.socketserver简介 socketserver是一个创建服务器的框架,封装了许多功能用来处理来自客户端的请求,简化了自己写服务端代码.比如说对于基本的套接字服务器(socket-based ...
随机推荐
- 转载:Hadoop安装教程_单机/伪分布式配置_Hadoop2.6.0/Ubuntu14.04
原文 http://www.powerxing.com/install-hadoop/ 当开始着手实践 Hadoop 时,安装 Hadoop 往往会成为新手的一道门槛.尽管安装其实很简单,书上有写到, ...
- HttpClientUtil [使用apache httpclient模拟http请求]
基于httpclient-4.5.2 模拟http请求 以get/post方式发送json请求,并获取服务器返回的json -------------------------------------- ...
- 百度地图api 标注的图标不显示问题
图中郑州PPT设计制作中心前面应该有一个小的标,但是死活就是不显示. 经过百度搜索和测试,终于解决.应该是页面定义的CSS和百度的冲突了,解决办法如下: 在当前页面中,加入 <style typ ...
- Winfrom 开发小技能
1.放弃进度条.动态进度图片等方式实现用户体验优化方式(主要是优化用户等待体验),建议使用方式? 答:对于From或者Control而言,其提供了Cursor属性设置即可. 例如: this.Curs ...
- BizTalk发布WS-Security的web services
最近做个项目,biztalk跟OTM(Oracle Transportation Management)系统做对接,双方通过web services通讯,这部分是BizTalk发布WS-Securit ...
- c# winform 窗体起始位置 设置
窗体起始位置为顶部中间,WinForm居中显示: ; ; this.StartPosition = FormStartPosition.Manual; //窗体的位置由Location属性决定 thi ...
- Netty服务端与客户端(源码一)
首先,整理NIO进行服务端开发的步骤: (1)创建ServerSocketChannel,配置它为非阻塞模式. (2)绑定监听,配置TCP参数,backlog的大小. (3)创建一个独立的I/O线程, ...
- OAF_开发系列22_实现OAF条形码BarCode
20150717 Created By BaoXinjian
- 13 年的 Bug 调试经验总结
在<Learning From Your Bugs>一文中,我写了关于我是如何追踪我所遇到的一些最有趣的bug.最近,我回顾了我所有的194个条目(从13岁开始),看看有什么经验教训是我可 ...
- 使用Junit对Spring进行单元测试实战小结
Demo代码: @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = "classpath*:/ ...