select简单示例,有注释
全部都在代码中:
import select
import socket
import queue """
简单的select 实现echo server
个人理解:
select 编程思想,让select去去判断能不能读或能不能写。
如果能读或能写,select就会告知readable或writeable,这时就得让文件句柄去读或写,
在这里是scoket,recv()或scoket.send()去执行实际的操作
"""
server = socket.socket() # 获取一个套接字
server.setblocking(False) # 设置为非阻塞模式
server.bind(('127.0.0.1',9001)) # 绑定ip和端口
server.listen(5) # 启动监听,到这步可以在netstat 看到监听状态,如果没有server.accept()的话,客户端的连接会被拒绝 inputs = [ server ] # 设置输入队列,当server的监听收到客户端连接时,select会认为这个server为可读,就得让server.accpet()去接收客户端连接
# 或者当socket有新的数据发送过来时,select会认为这个socket是可读的,就得去让socket的recv()去接收数据
outputs = [] # 当socket可以发送数据给对端时,select会认定这个socket是
message_queue = {} # 消息队列,key值为socket套接字
n = 0 # 体现while循环了多少次
while inputs: # inputs中是否存在值
print("waiting for connect..., %s"%n)
readable , writeable ,exceptions = select.select(inputs,outputs,inputs) # select就像一个非常强大的监视器,监视各个文件句柄的是否可读可写。 for s in readable: # 循环可读的。
if s is server: # 如果是server套接字
print("server can read...")
conn, addr = s.accept() # 就接收客户端连接
print("welcome (%s,%s) to connect..."%addr)
inputs.append(conn) # 将客户端套连接接字放入inputs,而不是马上接收或发生数据。
# s.setblocking(False) else: # 如果不是server套接字
print("a scoket can read:" ,s.getpeername()) # 只有当有数据发送过来时才会把那个套接字放在readable里
try:
data = s.recv(1024) # 就表明客户端连接套接字收到了客户端发送来的数据
except Exception as e: # 客户端进程被强制关闭,导致客户端发送rst包。 ConnectionResetError
print(e)
inputs.remove(s) # 如果客户端退出,就讲这个套接字从inputs中移除
if s in outputs: # 如果这个套接字存在于outputs中,也将这个套接字从outputs中移除,因为客户端都关闭了
# 还将这个套接字放在outputs中没有了,发不了数据了啊。
outputs.remove(s)
s.close() # 记得关闭这个套接字
break # 这里要break,因为s.recv(1024)异常了,data根本就没有被定义,下面的if data就会报错。 if data: # 如果有数据
print("recv from %s:%s"%(s.getpeername(),data.decode()))
message_queue[s] = queue.Queue() # 将收到的数据放入消息队列中
message_queue[s].put(data)
outputs.append(s) # 因为是echo server,所有有道数据后就得原有返回数据,但是这里不立即返回,而是交由select.
else:
print("the client (%s,%s) is closed "%s.getpeername()) # 如果data为空,表示客户端正常关闭连接,客户端发送了fin.
if s in outputs: # 客户端关闭了,这个套接字也就没必要放在outputs和inputs中了
outputs.remove(s)
inputs.remove(s)
del message_queue[s] # 消息队列也可以清除
s.close() # 关闭套接字 for s in writeable: # 如果可写,“好像ouputs有连接的套接字 存在就是可写的。”
try:
data = message_queue[s].get_nowait() # 获取要发送的消息
except queue.Empty: # 消息队列为空也是可写的。
print("outpt queue for (%s,%s) in empty"%s.getpeername())
outputs.remove(s) # 因为是echo server,所以消息队列为空时,说明已经回应了数据给对端,就不用一直去判断这个套接字是否可写了。
# s.close() # 没有数据可发送并不代表要关闭socket
else:
print("send data to client (%s,%s)"%s.getpeername())
s.send(data)
# outputs.remove(s) # 发送完一条数据后,其实不能将他移除,因为有可能对端非常迅速的发了多条消息过来,而服务器一条消息都还没来得及回复,
# 服务器的消息将会都放在队列中等待发送,所以这里的让队列为空时在把套接字从outputs中移除。 for s in exceptions: # 如果发生错误
print("expect happend on (%s,%s)"%s.getpeername())
inputs.remove(s) # 将这个套接字从inouts,outputs中移除
if s in outputs:
outputs.remove(s)
s.close() # 连接要关闭
del message_queue[s] # 消息队列也要关闭
n += 1 # 看看while循环可多少次
waiting for connect..., 0
server can read...
welcome (127.0.0.1,3137) to connect...
waiting for connect..., 1
server can read...
welcome (127.0.0.1,3138) to connect...
waiting for connect..., 2
a scoket can read: ('127.0.0.1', 3137) # 这里说明第一个客户端套接字在readable里,下面也没看到第二个客户端在readable里直到第二个客户端发送数据过来,也就是说select只是把可读的返回给了readable里。
recv from ('127.0.0.1', 3137):this is the 1st client
waiting for connect..., 3
send data to client (127.0.0.1,3137)
waiting for connect..., 4
outpt queue for (127.0.0.1,3137) in empty
waiting for connect..., 5
a scoket can read: ('127.0.0.1', 3138)
recv from ('127.0.0.1', 3138):this is the 2nd client
waiting for connect..., 6
send data to client (127.0.0.1,3138)
waiting for connect..., 7
outpt queue for (127.0.0.1,3138) in empty
waiting for connect..., 8
a scoket can read: ('127.0.0.1', 3138)
recv from ('127.0.0.1', 3138):2nd haha
waiting for connect..., 9
send data to client (127.0.0.1,3138)
waiting for connect..., 10
outpt queue for (127.0.0.1,3138) in empty
waiting for connect..., 11
a scoket can read: ('127.0.0.1', 3137)
recv from ('127.0.0.1', 3137):1st hello
waiting for connect..., 12
send data to client (127.0.0.1,3137)
waiting for connect..., 13
outpt queue for (127.0.0.1,3137) in empty
waiting for connect..., 14
a scoket can read: ('127.0.0.1', 3138)
recv from ('127.0.0.1', 3138):2nd wiil killed by os
waiting for connect..., 15
send data to client (127.0.0.1,3138)
waiting for connect..., 16
outpt queue for (127.0.0.1,3138) in empty
waiting for connect..., 17
a scoket can read: ('127.0.0.1', 3138)
[WinError 10054] 远程主机强迫关闭了一个现有的连接。
waiting for connect..., 18
a scoket can read: ('127.0.0.1', 3137)
recv from ('127.0.0.1', 3137):1st wiil closed by socket.close()
waiting for connect..., 19
send data to client (127.0.0.1,3137)
waiting for connect..., 20
outpt queue for (127.0.0.1,3137) in empty
waiting for connect..., 21
a scoket can read: ('127.0.0.1', 3137)
the client (127.0.0.1,3137) is closed
waiting for connect..., 22
客户端:
import socket s = socket.socket()
s.connect(('127.0.0.1',9001)) while True:
data = input(">> ").strip()
if data == "":
continue
if data == "q":
s.close()
break
s.send(bytes(data,encoding="utf-8"))
data = s.recv(1024)
print("recv:",data.decode())
select简单示例,有注释的更多相关文章
- web 框架的本质及自定义web框架 模板渲染jinja2 mvc 和 mtv框架 Django框架的下载安装 基于Django实现的一个简单示例
Django基础一之web框架的本质 本节目录 一 web框架的本质及自定义web框架 二 模板渲染JinJa2 三 MVC和MTV框架 四 Django的下载安装 五 基于Django实现的一个简单 ...
- HTML-003-模拟IDE代码展开收起功能简单示例
当先我们在日常的编程开发工作中使用编程工具(例如 Eclipse.Sublime 等等)都有相应的代码折叠展开功能,如下图所示,极大的方便了我们的编码工作.
- Mybatis的简单示例
首先新建一个JavaWeb项目并导入mybatis依赖的jar包,同时Mybatis是对数据库的操作所以我们需要在数据库中新建一个表user用来演示. 新建完表之后我们还需要建立相对应的实体类User ...
- Nodejs学习笔记(十五)--- Node.js + Koa2 构建网站简单示例
目录 前言 搭建项目及其它准备工作 创建数据库 创建Koa2项目 安装项目其它需要包 清除冗余文件并重新规划项目目录 配置文件 规划示例路由,并新建相关文件 实现数据访问和业务逻辑相关方法 编写mys ...
- [转]Nodejs学习笔记(十五)--- Node.js + Koa2 构建网站简单示例
本文转自:https://www.cnblogs.com/zhongweiv/p/nodejs_koa2_webapp.html 目录 前言 搭建项目及其它准备工作 创建数据库 创建Koa2项目 安装 ...
- SignalR代理对象异常:Uncaught TypeError: Cannot read property 'client' of undefined 推出的结论 SignalR 简单示例 通过三个DEMO学会SignalR的三种实现方式 SignalR推送框架两个项目永久连接通讯使用 SignalR 集线器简单实例2 用SignalR创建实时永久长连接异步网络应用程序
SignalR代理对象异常:Uncaught TypeError: Cannot read property 'client' of undefined 推出的结论 异常汇总:http://www ...
- Lombok(1.14.8)的简单示例
分享自: http://blog.csdn.net/huey2672/article/details/42240985 Lombok是一种Java™实用工具,可用来帮助开发人员消除Java的冗长,尤其 ...
- java读取ACCESS数据库的简单示例
java读取ACCESS数据库的简单示例 虽然简单,对初学者来说,如果没有一段可以成功执行的代码供参考,还真难调试 先用ACCESS建一个数据库 DB1.MDB,里面有一表"table1&q ...
- Nodejs学习笔记(十五)—Node.js + Koa2 构建网站简单示例
前言 前面一有写到一篇Node.js+Express构建网站简单示例:http://www.cnblogs.com/zhongweiv/p/nodejs_express_webapp.html 这篇还 ...
随机推荐
- 下载特定区域内街景照片数据 | Download Street View Photos within Selected Region
作者:姜虹,刘子煜,王玥瑶,杨安琪,天靖居士 街景图片可以通过api下载,但需要提供参数,参数中的poiid.panoid.location可以用来确定位置或全景图片的ID以确定对应的街景图片.优先级 ...
- 转 XlsReadWriteII 的博文(自留参考)
如何使用XlsReadWriteII在Delphi中读取Excel文件 XLSReadWriteII v5.20.01a for Delphi XE5 x32下载地址: http://download ...
- svm的第一个实例
用的数据集是uci机器学习库的数据 ‘iris.data’ from sklearn import svm import csv from sklearn.model_selection import ...
- 关于spring xml文件中的xmlns,xsi:schemaLocation
链接:https://blog.csdn.net/u010571844/article/details/50767151 使用spring也有一段时间了,配置文件也见了不少了,但是发现配置文件的bea ...
- uoj #298. 【CTSC2017】网络
#298. [CTSC2017]网络 一个一般的网络系统可以被描述成一张无向连通图.图上的每个节点为一个服务器,连接服务器与服务器的数据线则看作图上的一条边,边权为该数据线的长度.两个服务器之间的通讯 ...
- 洛谷P4009 汽车加油行驶问题(分层最短路)
传送门 说好的网络流24题呢……上次是状压dp,这次怎么又最短路了…… 不过倒是用这题好好学了一下分层图最短路 把每一个位置$(x,y)$,油量剩余$k$表示为一个状态,然后转化成一个$n$进制数,这 ...
- logging、hashlib、collections模块
一.hashlib模块(加密模块) 1.什么叫hash:hash是一种算法(3.x里代替了md5模块和sha模块,主要提供 SHA1, SHA224, SHA256, SHA384, SHA512 , ...
- get与post中文乱码问题
Jsp默认的字符编码格式是iso-8859-1 因为post方法与get方法传递参数的方式不一样,所以有不同的解决方法. 一.post乱码解决方法: 1.设置请求和响应的编码方式 //设置请求的编码格 ...
- [转]An STL compliant sorted vector-源码示例
原文地址:http://www.codeproject.com/Articles/3217/An-STL-compliant-sorted-vector 最近在看sorted vectored的一些东 ...
- 使用vue-cli脚手架搭建项目,保存编译时出现的代码检查错误(ESLint)
一.问题 出现这么写错误是什么原因呢?相信很多小白都会像我一样,第一次接触时有点二丈和尚摸不着头脑.其实是在你用vue-cli脚手架构建项目时用了ESLint代码检查工具,如下图 那么什么是ESLin ...