基于python select.select模块通信的实例讲解


Posted in Python onSeptember 21, 2017

要理解select.select模块其实主要就是要理解它的参数, 以及其三个返回值。

select()方法接收并监控3个通信列表, 第一个是所有的输入的data,就是指外部发过来的数据,第2个是监控和接收所有要发出去的data(outgoing data),第3个监控错误信息在网上一直在找这个select.select的参数解释, 但实在是没有, 哎...自己硬着头皮分析了一下。

readable, writable, exceptional = select.select(inputs, outputs, inputs)

第一个参数就是服务器端的socket, 第二个是我们在运行过程中存储的客户端的socket, 第三个存储错误信息。

重点是在返回值, 第一个返回的是可读的list, 第二个存储的是可写的list, 第三个存储的是错误信息的list。

这个也不必深究, 看看代码自己分析下就能有大概理解。

网上所有关于select.select的代码都是差不多的, 但是有些不能运行, 或是不全。我自己重新写了一份能运行的程序, 做了很多注释, 好好看看就能搞懂

服务器端:

# coding: utf-8
import select
import socket
import Queue
from time import sleep


# Create a TCP/IP
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.setblocking(False)

# Bind the socket to the port
server_address = ('localhost', 8090)
print ('starting up on %s port %s' % server_address)
server.bind(server_address)

# Listen for incoming connections
server.listen(5)

# Sockets from which we expect to read
inputs = [server]

# Sockets to which we expect to write
# 处理要发送的消息
outputs = []

# Outgoing message queues (socket: Queue)
message_queues = {}

while inputs:
  # Wait for at least one of the sockets to be ready for processing
  print ('waiting for the next event')
  # 开始select 监听, 对input_list 中的服务器端server 进行监听
  # 一旦调用socket的send, recv函数,将会再次调用此模块
  readable, writable, exceptional = select.select(inputs, outputs, inputs)

  # Handle inputs
  # 循环判断是否有客户端连接进来, 当有客户端连接进来时select 将触发
  for s in readable:
    # 判断当前触发的是不是服务端对象, 当触发的对象是服务端对象时,说明有新客户端连接进来了
    # 表示有新用户来连接
    if s is server:
      # A "readable" socket is ready to accept a connection
      connection, client_address = s.accept()
      print ('connection from', client_address)
      # this is connection not server
      connection.setblocking(0)
      # 将客户端对象也加入到监听的列表中, 当客户端发送消息时 select 将触发
      inputs.append(connection)

      # Give the connection a queue for data we want to send
      # 为连接的客户端单独创建一个消息队列,用来保存客户端发送的消息
      message_queues[connection] = Queue.Queue()
    else:
      # 有老用户发消息, 处理接受
      # 由于客户端连接进来时服务端接收客户端连接请求,将客户端加入到了监听列表中(input_list), 客户端发送消息将触发
      # 所以判断是否是客户端对象触发
      data = s.recv(1024)
      # 客户端未断开
      if data != '':
        # A readable client socket has data
        print ('received "%s" from %s' % (data, s.getpeername()))
        # 将收到的消息放入到相对应的socket客户端的消息队列中
        message_queues[s].put(data)
        # Add output channel for response
        # 将需要进行回复操作socket放到output 列表中, 让select监听
        if s not in outputs:
          outputs.append(s)
      else:
        # 客户端断开了连接, 将客户端的监听从input列表中移除
        # Interpret empty result as closed connection
        print ('closing', client_address)
        # Stop listening for input on the connection
        if s in outputs:
          outputs.remove(s)
        inputs.remove(s)
        s.close()

        # Remove message queue
        # 移除对应socket客户端对象的消息队列
        del message_queues[s]

  # Handle outputs
  # 如果现在没有客户端请求, 也没有客户端发送消息时, 开始对发送消息列表进行处理, 是否需要发送消息
  # 存储哪个客户端发送过消息
  for s in writable:
    try:
      # 如果消息队列中有消息,从消息队列中获取要发送的消息
      message_queue = message_queues.get(s)
      send_data = ''
      if message_queue is not None:
        send_data = message_queue.get_nowait()
      else:
        # 客户端连接断开了
        print "has closed "
    except Queue.Empty:
      # 客户端连接断开了
      print "%s" % (s.getpeername())
      outputs.remove(s)
    else:
      # print "sending %s to %s " % (send_data, s.getpeername)
      # print "send something"
      if message_queue is not None:
        s.send(send_data)
      else:
        print "has closed "
      # del message_queues[s]
      # writable.remove(s)
      # print "Client %s disconnected" % (client_address)

  # # Handle "exceptional conditions"
  # 处理异常的情况
  for s in exceptional:
    print ('exception condition on', s.getpeername())
    # Stop listening for input on the connection
    inputs.remove(s)
    if s in outputs:
      outputs.remove(s)
    s.close()

    # Remove message queue
    del message_queues[s]

  sleep(1)

客户端:

# coding: utf-8
import socket


messages = ['This is the message ', 'It will be sent ', 'in parts ', ]

server_address = ('localhost', 8090)

# Create aTCP/IP socket

socks = [socket.socket(socket.AF_INET, socket.SOCK_STREAM), socket.socket(socket.AF_INET, socket.SOCK_STREAM), ]

# Connect thesocket to the port where the server is listening

print ('connecting to %s port %s' % server_address)
# 连接到服务器
for s in socks:
  s.connect(server_address)

for index, message in enumerate(messages):
  # Send messages on both sockets
  for s in socks:
    print ('%s: sending "%s"' % (s.getsockname(), message + str(index)))
    s.send(bytes(message + str(index)).decode('utf-8'))
  # Read responses on both sockets

for s in socks:
  data = s.recv(1024)
  print ('%s: received "%s"' % (s.getsockname(), data))
  if data != "":
    print ('closingsocket', s.getsockname())
    s.close()

写代码过程中遇到了两个问题, 一是如何判断客户端已经关闭了socket连接, 后来自己分析了下, 如果关闭了客户端socket, 那么此时服务器端接收到的data就是'', 加个这个判断。二是如果服务器端关闭了socket, 一旦在调用socket的相关方法都会报错, 不管socket是不是用不同的容器存储的(意思是说list_1存储了socket1, list_2存储了socket1, 我关闭了socket1, 两者都不能在调用这个socket了)

服务器端:

基于python select.select模块通信的实例讲解

客户端:

基于python select.select模块通信的实例讲解

以上这篇基于python select.select模块通信的实例讲解就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Python 相关文章推荐
简单的连接MySQL与Python的Bottle框架的方法
Apr 30 Python
Python实现批量将word转html并将html内容发布至网站的方法
Jul 14 Python
使用Python生成随机密码的示例分享
Feb 18 Python
用Python将mysql数据导出成json的方法
Aug 21 Python
对python requests的content和text方法的区别详解
Oct 11 Python
python多进程控制学习小结
Oct 31 Python
基于Python实现用户管理系统
Feb 26 Python
关于windows下Tensorflow和pytorch安装教程
Feb 04 Python
python加密解密库cryptography使用openSSL生成的密匙加密解密
Feb 11 Python
实现ECharts双Y轴左右刻度线一致的例子
May 16 Python
用python实现前向分词最大匹配算法的示例代码
Aug 06 Python
Python字符串对齐、删除字符串不需要的内容以及格式化打印字符
Jan 23 Python
Python实现小数转化为百分数的格式化输出方法示例
Sep 20 #Python
Python实现字符串格式化输出的方法详解
Sep 20 #Python
Python+Selenium+PIL+Tesseract自动识别验证码进行一键登录
Sep 20 #Python
python select.select模块通信全过程解析
Sep 20 #Python
基于python的字节编译详解
Sep 20 #Python
MySQL适配器PyMySQL详解
Sep 20 #Python
Python字符串格式化的方法(两种)
Sep 19 #Python
You might like
上传文件先创建目录 再上传到目录里面去
2010/12/29 PHP
比较时间段一与时间段二是否有交集的php函数
2011/05/31 PHP
PHP读取配置文件类实例(可读取ini,yaml,xml等)
2015/07/28 PHP
解读PHP中的垃圾回收机制
2015/08/10 PHP
PHP如何通过AJAX方式实现登录功能
2015/11/23 PHP
PHP上传图片、删除图片简单实例
2016/11/12 PHP
PHP vsprintf()函数格式化字符串操作原理解析
2020/07/14 PHP
javascript 放大镜效果js组件 qsoft.PopBigImage.v0.35 加入了chrome支持
2009/04/07 Javascript
jQuery第三课 修改元素属性及内容的代码
2010/03/14 Javascript
js点击更换背景颜色或图片的实例代码
2013/06/25 Javascript
判断是否安装flash player及当前版本的JS代码
2013/08/08 Javascript
利用毫秒减值计算时长的js代码
2013/09/22 Javascript
jquery获取div距离窗口和父级dv的距离示例
2013/10/10 Javascript
如何实现chrome浏览器关闭页面时弹出“确定要离开此面吗?”
2015/03/05 Javascript
Vue2.0利用 v-model 实现组件props双向绑定的优美解决方案
2017/03/13 Javascript
vue-cli项目如何使用vue-resource获取本地的json数据(模拟服务端返回数据)
2017/08/04 Javascript
vue父组件向子组件传递多个数据的实例
2018/03/01 Javascript
利用weixin-java-miniapp生成小程序码并直接返回图片文件流的方法
2019/03/29 Javascript
解决layui富文本编辑器图片上传无法回显的问题
2019/09/18 Javascript
在vue中使用防抖和节流,防止重复点击或重复上拉加载实例
2019/11/13 Javascript
微信小程序表单验证WxValidate的使用
2019/11/27 Javascript
Python实现的Excel文件读写类
2015/07/30 Python
Python数据结构与算法之列表(链表,linked list)简单实现
2017/10/30 Python
Python多进程并发与多线程并发编程实例总结
2018/02/08 Python
Django中使用Celery的教程详解
2018/08/24 Python
Python常用的json标准库
2019/02/19 Python
django中ORM模型常用的字段的使用方法
2019/03/05 Python
Python实现最大子序和的方法示例
2019/07/05 Python
python操作docx写入内容,并控制文本的字体颜色
2020/02/13 Python
HTML5实现Notification API桌面通知功能
2016/03/02 HTML / CSS
村庄环境整治方案
2014/05/15 职场文书
2014年为民办实事工作总结
2014/12/20 职场文书
客服专员岗位职责
2015/02/10 职场文书
2015年医院护理部工作总结
2015/04/23 职场文书
2016年教师学习廉政准则心得体会
2016/01/20 职场文书
仅用几行Python代码就能复制她的U盘文件?
2021/06/26 Python