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

要理解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模块通信的实例讲解就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • Python创建对称矩阵的方法示例【基于numpy模块】

    本文实例讲述了Python创建对称矩阵的方法.分享给大家供大家参考,具体如下: 对称(实对称)矩阵也即: step 1:创建一个方阵 >>> import numpy as np >>> X = np.random.rand(5**2).reshape(5, 5) >>> X array([[ 0.26984148, 0.25408384, 0.12428487, 0.0194565 , 0.91287708], [ 0.31837673, 0.354

  • Python使用文件锁实现进程间同步功能【基于fcntl模块】

    本文实例讲述了Python使用文件锁实现进程间同步功能.分享给大家供大家参考,具体如下: 简介 在实际应用中,会出现这种应用场景:希望shell下执行的脚本对某些竞争资源提供保护,避免出现冲突.本文将通过fcntl模块的文件整体上锁机制来实现这种进程间同步功能. fcntl系统函数介绍 Linux系统提供了文件整体上锁(flock)和更细粒度的记录上锁(fcntl)功能,底层功能均可由fcntl函数实现. 首先来了解记录上锁.记录上锁是读写锁的一种扩展类型,它可用于有亲缘关系或无亲缘关系的进程间

  • Python中使用hashlib模块处理算法的教程

    Python的hashlib提供了常见的摘要算法,如MD5,SHA1等等. 什么是摘要算法呢?摘要算法又称哈希算法.散列算法.它通过一个函数,把任意长度的数据转换为一个长度固定的数据串(通常用16进制的字符串表示). 举个例子,你写了一篇文章,内容是一个字符串'how to use python hashlib - by Michael',并附上这篇文章的摘要是'2d73d4f15c0db7f5ecb321b6a65e5d6d'.如果有人篡改了你的文章,并发表为'how to use pytho

  • Python基于time模块求程序运行时间的方法

    本文实例讲述了Python基于time模块求程序运行时间的方法.分享给大家供大家参考,具体如下: 要记录程序的运行时间可以利用Unix系统中,1970.1.1到现在的时间的毫秒数,这个时间戳轻松完成. 方法是程序开始的时候取一次存入一个变量,在程序结束之后取一次再存入一个变量,与程序开始的时间戳相减则可以求出. Python中取这个时间戳的方法为引入time类之后,使用time.time();就能够拿出来.也就是Java中的System.currentTimeMillis(). 由于Python

  • python3使用requests模块爬取页面内容的实战演练

    1.安装pip 我的个人桌面系统用的linuxmint,系统默认没有安装pip,考虑到后面安装requests模块使用pip,所以我这里第一步先安装pip. $ sudo apt install python-pip 安装成功,查看PIP版本: $ pip -V 2.安装requests模块 这里我是通过pip方式进行安装: $ pip install requests 运行import requests,如果没提示错误,那说明已经安装成功了! 检验是否安装成功 3.安装beautifulsou

  • python模块之time模块(实例讲解)

    time 表示时间的三种形式 时间戳(timestamp) :通常来说,时间戳表示的是从1970年1月1日00:00:00开始按秒计算的偏移量.我们运行"type(time.time())",返回的是float类型. 格式化的时间字符串(Format String): '1999-12-06' 时间格式化符号 ''' %y 两位数的年份表示(00-99) %Y 四位数的年份表示(000-9999) %m 月份(01-12) %d 月内中的一天(0-31) %H 24小时制小时数(0-2

  • python中hashlib模块用法示例

    我们以前介绍过一篇Python加密的文章:Python 加密的实例详解.今天我们看看python中hashlib模块用法示例,具体如下. hashlib hashlib主要提供字符加密功能,将md5和sha模块整合到了一起,支持md5,sha1, sha224, sha256, sha384, sha512等算法 具体应用 #!/usr/bin/env python # -*- coding: UTF-8 -*- #pyversion:python3.5 #owner:fuzj import h

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

    要理解select.select模块其实主要就是要理解它的参数, 以及其三个返回值. select()方法接收并监控3个通信列表, 第一个是所有的输入的data,就是指外部发过来的数据,第2个是监控和接收所有要发出去的data(outgoing data),第3个监控错误信息在网上一直在找这个select.select的参数解释, 但实在是没有, 哎...自己硬着头皮分析了一下. readable, writable, exceptional = select.select(inputs, ou

  • 基于python requests库中的代理实例讲解

    直接上代码: #request代理(proxy) """ 1.启动代理服务器Heroku,相当于aliyun 2.在主机1080端口启动Socks 服务 3.将请求转发到1080端口 4.获取相应资源 首先要安装包pip install 'requests[socksv5]' """ import requests #定义一个代理服务器,所有的http及https都走socks5的协议,sock5相当于http协议,它是在会话层 #把它转到本机的

  • 基于Python中numpy数组的合并实例讲解

    Python中numpy数组的合并有很多方法,如 - np.append() - np.concatenate() - np.stack() - np.hstack() - np.vstack() - np.dstack() 其中最泛用的是第一个和第二个.第一个可读性好,比较灵活,但是占内存大.第二个则没有内存占用大的问题. 方法一--append parameters introduction arr 待合并的数组的复制(特别主页是复制,所以要多耗费很多内存) values 用来合并到上述数组

  • 对python中基于tcp协议的通信(数据传输)实例讲解

    阅读目录 tcp协议:流式协议(以数据流的形式通信传输).安全协议(收发信息都需收到确认信息才能完成收发,是一种双向通道的通信) tcp协议在OSI七层协议中属于传输层,它上承用户层的数据收发,下启网络层.数据链路层.物理层.可以说很多安全数据的传输通信都是基于tcp协议进行的. 为了让tcp通信更加方便需要引入一个socket模块(将网络层.数据链路层.物理层封装的模块),我们只要调用模块中的相关接口就能实现传输层下面的繁琐操作. 简单的tcp协议通信模板:(需要一个服务端和一个客户端) 服务

  • 基于python中pygame模块的Linux下安装过程(详解)

    一.使用pip安装Python包 大多数较新的Python版本都自带pip,因此首先可检查系统是否已经安装了pip.在Python3中,pip有时被称为pip3. 1.在Linux和OS X系统中检查是否安装了pip 打开一个终端窗口,并执行如下命令: Python2.7中: zhuzhu@zhuzhu-K53SJ:~$ pip --version pip 8.1.1 from /usr/lib/python2.7/dist-packages (python 2.7) Python3.X中: z

  • 基于Python socket的端口扫描程序实例代码

    本文研究的主要是Python的端口扫描程序,具体实例代码如下. 先来看看第一个端口扫描程序代码,获取本机的IP和端口号: import socket def get_my_ip(): try: csock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) csock.connect(('8.8.8.8', 80)) (addr, port) = csock.getsockname() csock.close() return addr,port

  • 基于python if 判断选择结构的实例详解

    代码执行结构为顺序结构.选择结构.循环结构. python判断选择结构[if] if 判断条件 #进行判断条件满足之后执行下方语句 执行语句 elif 判断条件 #在不满足上面所有条件基础上进行条件筛选匹配之后执行下方语句 执行语句 else #再不满足上面所有的添加下执行下方语句 执行语句 下面举一个简单的例子,看兜里有多少钱来决定吃什么饭. douliqian=2 if douliqian>200: print("小龙虾走起!!0.0") elif douliqian>

  • layui问题之模拟select点击事件的实例讲解

    一.问题 不操作页面,实现模拟select的事件,即,自动出现下拉框,自动点击下拉框的值,select文本框的值随之改变 二.经过 刚开始查看layui官方文档,发现仅仅只是有select监听事件,即: form.on('select(filter)', function(data){ console.log(data.elem); //得到select原始DOM对象 console.log(data.value); //得到被选中的值 }); 但是,这个事件需要操作页面,不可取. 三.结果 查

  • 基于python判断目录或者文件代码实例

    这篇文章主要介绍了基于python判断目录或者文件代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 1. 判断目录是否存在 'isdir',删除目录时只有该目录为空才可以 'rmdir' import os if(os.path.isdir('D:/Python_workspace/spyder_space/test_各种功能/哈哈哈哈')): #判断目录是否存在 print('yes') os.rmdir('D:/Python_work

  • 基于python调用psutil模块过程解析

    这篇文章主要介绍了基于python调用psutils模块过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 用Python来编写脚本简化日常的运维工作是Python的一个重要用途.在Linux下,有许多系统命令可以让我们时刻监控系统运行的状态,如ps,top,free等等.要获取这些系统信息,Python可以通过subprocess模块调用并获取结果.但这样做显得很麻烦,尤其是要写很多解析代码. 在Python中获取系统信息的另一个好办法是

随机推荐