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源码剖析的更多相关文章

  1. socketserver 源码剖析:

    socketserver 源码剖析[有图有真相]: (一).Socketserver 内部流程调用图:        详解:  1.self.RequestHandlerClass() = MyCla ...

  2. socketserver源码剖析

    作者:人世间链接:https://www.jianshu.com/p/357e436936bf來源:简书简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处 BaseServer 和 B ...

  3. Java多线程9:ThreadLocal源码剖析

    ThreadLocal源码剖析 ThreadLocal其实比较简单,因为类里就三个public方法:set(T value).get().remove().先剖析源码清楚地知道ThreadLocal是 ...

  4. java多线程17:ThreadLocal源码剖析

    ThreadLocal源码剖析 ThreadLocal其实比较简单,因为类里就三个public方法:set(T value).get().remove().先剖析源码清楚地知道ThreadLocal是 ...

  5. 第二十四篇、socketserver源码剖析

    这里选择的是python2.7(python3和2.7的源码基本类似) #!/usr/bin/env python # -*- coding:utf-8 -*- import SocketServer ...

  6. socket_server源码剖析、python作用域、IO多路复用

    本节内容: 课前准备知识: 函数嵌套函数的使用方法: 我们在使用函数嵌套函数的时候,是学习装饰器的时候,出现过,由一个函数返回值是一个函数体情况. 我们在使用函数嵌套函数的时候,最好也这么写. def ...

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

  8. python基础-11 socket,IO多路复用,select伪造多线程,select读写分离。socketserver源码分析

    Socket socket通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄,应用程序通常通过"套接字"向网络发出请求或者应答网络请求. sock ...

  9. Python之socketserver源码分析

    一.socketserver简介 socketserver是一个创建服务器的框架,封装了许多功能用来处理来自客户端的请求,简化了自己写服务端代码.比如说对于基本的套接字服务器(socket-based ...

随机推荐

  1. yii框架中的一些小细节配置问题

    1.查看运行时间'db'=>array(      'connectionString' => 'mysql:host=localhost;dbname=shop',      'emul ...

  2. java 线程安全 synchronized

    一.线程安全问题: 并发编程的原则:设计并发编程的目的是为了使程序获得更高的执行效率,但绝不能出现数据一致性(数据准确)问题,如果并发程序连最基本的执行结果准确性都无法保证,那并发编程就没有任何意义. ...

  3. Centos6.5 设置Tomcat8 service服务实现自启动和服务管理

    Centos6.5 设置Tomcat8 service服务实现自启动和服务管理 将tomcat设置成像apache,nginx一样. 用serviec xxxx start/stop/restart ...

  4. [Linux] - CentOS中文乱码解决办法

    CentOS 7 终端中文乱码解决办法: 1.使用vim编辑locale.config文件: vim /etc/locale.conf 2.将LANG="en_US.UTF-8"修 ...

  5. SQL:实现流水账的收入、支出、本期余额

    有多组数据,分别是收入,支出,余额,它们的关系是:本期余额=上次余额+收入-支出 /* 测试数据: Create Table tbl([日期] smalldatetime,[收入] int ,[支出] ...

  6. HTML中strong与b,em与i标签的区别

    先看效果 <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <titl ...

  7. 解决“动软代码生成器在SqlServer中会将唯一索引识别为主键"的Bug

    动软代码生成器在SqlServer中,生成的代码会将唯一索引错误地识别为主键, 反编译源代码后,发现其中的SQL条件有误,现修复此Bug. 修复方法:将附件中的”Maticsoft.DbObjects ...

  8. Redis执行Lua脚本的情况

    第一个测试: 往Redis里面存入1000个Hash,每个Hash里面有100个元素(Key 0-99,值是Key^2). PHP代码,执行33s左右 <?php $redis = new Re ...

  9. mybatis实战教程(mybatis in action)之四:实现关联数据的查询

    有了前面几章的基础,对一些简单的应用是可以处理的,但在实际项目中,经常是关联表的查询,比如最常见到的多对一,一对多等.这些查询是如何处理的呢,这一讲就讲这个问题.我们首先创建一个Article 这个表 ...

  10. 使用nvm安装node

    安装nvm curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.32.1/install.sh | bash 安装node nvm ...