自己实现多线程的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 ...
随机推荐
- javascript操控浏览器
测试环境为Chrome浏览器47.0.2526.106 m 测试窗口为F12->Console 跳转网页 // 跳转到百度 window.location.href = "https: ...
- ios 利用airprint实现无线打印(配合普通打印机)
很多时候,我们不可能为了一个打印功能而去替换打印机,来支持无线打印. 找了很久,终于找到了一种解决方案,来适应大多数没有带wifi功能的打印机支持无线打印. 前提: 有wifi路由器:因为手机要打印, ...
- IOS开发之--NSPredicate
我把常用的NSPredicate使用场景整理了一下 官方参考: https://developer.apple.com/library/mac/#documentation/Cocoa/Refer ...
- Shiro简单配置
注:这里只介绍Spring配置模式. 因为官方例子虽然中有更加简洁的ini配置形式,但是使用ini配置无法与spring整合.而且两种配置方法一样,只是格式不一样. 涉及的jar包 核心包shiro- ...
- android APK 文件的生成过程
步骤: 1. 用 aapt工具生成R文件aapt package -m -J gen目录 -M AndroidManifest.xml -S res目录 -I 编译版本sdk的android ...
- 优化定时器NSTimer-runloop使用
参考文档:http://www.cnblogs.com/junhuawang/p/4647559.html - (void)viewDidLoad { [super viewDidLoad]; ...
- JS获取上个月(转)
1.yyyy-mm-dd获取上个月 function getUpMonth(t){ var tarr = t.split('-'); var year = tarr[0]; //获取当前日期的年 va ...
- 在ANSYS WORKBENCH中使用APDL命令的例子
如何在workbench中使用command? 如何在ansys workbench中插入apdl? 如何在ansys workbench中使用复杂载荷? 答案在APDL,他可以实现函数化的载荷,如岁 ...
- php删除目录下的所有文件和目录
<?php /** * 递归实现删除目录下的所有的文件和文件夹 * @param $dir 要删除的目录 * @param bool $deleteRootToo 是否删除根目录 默认不删除 h ...
- 【VB6】打印机设置页边距
Printer.ScaleLeft = - Printer.ScaleTop = - Printer.CurrentX = Printer.CurrentY = '一些打印操作 Printer.End ...