python使用select监听非阻塞socket遇到的问题

Python下非阻塞式读取键盘输入 在Python编程中,有时需要实时地读取键盘输入,但是正常的输入方式会阻塞程序执行,导致不能及时响应。这时可以使用一些技巧实现非阻塞式获取键盘输入。本文将介绍在Python中如何通过tty和termios模块实现非阻塞读取键盘输入。 阅读详情

昨天学python的select的时候,发现一个非常诡异的事情,到现在也没弄明白,所以在这记录一下

服务端实现了一个简单的echo服务器,相关代码如下:

#coding=utf-8
import select                                                                                                                                
import socket
import Queue
import time
import os
#创建socket 套接字
server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
server.setblocking(False)
#配置参数
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR  , 1)
server_address= ('127.0.0.1',9999)
server.bind(server_address)
server.listen(1000)
inputs = [server]
outputs = []
message_queues = {}
f = open("a.txt","w")
#timeout = 20
while inputs:
    print "waiting for next event"
#    readable , writable , exceptional = select.select(inputs, outputs, inputs, timeout)  最后一个是超时,当前连接要是超过这个时间的话,就会kill
    readable , writable , exceptional = select.select(inputs, outputs, inputs)
                                                                                                                                                        
    # When timeout reached , select return three empty lists
    if not (readable or writable or exceptional) :
        print "Time out ! "
        break;
    for s in readable :
        if s is server:
            #通过inputs查看是否有客户端来
            connection, client_address = s.accept()
            print "    connection from ", client_address
            connection.setblocking(0)
            inputs.append(connection)
            message_queues[connection] = Queue.Queue()
        else:
            print "read"
            data = s.recv(1024)
            if data :
                print " received " , data , "from ",s.getpeername()
                message_queues[s].put(data)
                # Add output channel for response
                if s not in outputs:
                    print 'append outputs', client_address
                    outputs.append(s)
            else:
                #Interpret empty result as closed connection
                print "  closing", client_address
                if s in outputs :
                    print 'remove outputs', client_address
                    outputs.remove(s)
                print 'remove inputs', client_address
                inputs.remove(s)
                s.close()
                #清除队列信息
                print "del message_queues", client_address
                del message_queues[s]
    for s in writable:
        print "write:\t",  s.getpeername()
        try:
            next_msg = message_queues[s].get_nowait()
        except Queue.Empty:
            print " " , s.getpeername() , 'queue empty remove output'
            outputs.remove(s)
        #因为客户端断开会执行outputs.remove(s),这个操作会触发select
        # except KeyError:
        #     print "message_queues[s] removed"
        #     # f.write("%s\n" % len(message_queues))
        else:
            print " sending " , next_msg , " to ", s.getpeername()
            # os.popen('sleep 0.1').read()
            #zhege caozuo yehui chufa select
            s.send(next_msg)
                                                                                                                                                            
    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()
        #清除队列信息
        del message_queues[s]
    print len(outputs)


f.close()
客户端则是通过开启200个线程同时访问服务端,代码:

#!/user/bin/env python
#-*- encoding:utf-8 -*-
import socket
import thread,threading
import time
 
sockIndex = 1
 
def connToServer ():
    global sockIndex
    #创建一个socket连接到127.0.0.1:8081,并发送内容
    conn = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    conn.connect(("127.0.0.1", 9999))
    print "hi,I'm NO."+ str(sockIndex)
    conn.send("hi,I'm NO."+ str(sockIndex))
    # print sockIndex
    sockIndex = sockIndex + 1
    while True:
    #等待服务端返回数据,并输出
        # break
        rev = conn.recv(1024)
        print 'get server msg:' + str(rev)
        break
threads = []
times = 200
#并发
for i in range(0,times):
    t = threading.Thread(target=connToServer())
    threads.append(t)
for i in range(0,times):
    threads[i].start()
for i in range(0,times):
    threads[i].join()

connToServer()

然后发现会报错,错误信息追溯到
Traceback (most recent call last):
  File "select.py", line 62, in <module>
    next_msg = message_queues[s].get_nowait()
KeyError: <socket._socketobject object at 0x7f09cf823910>
我自己用本办法print打印信息,发现正常情况下send消息后,会再次触发select的output,再次去读queue中的信息,直到空为止。
但是由于来的连接太快,第一次send后没来得及第二次send就来新连接了。等处理完新连接,又处理之前没来得处理的读queue,但这时候已经被删了,所以就报错了。然后加了个except后就没问题了。但是我发现一个问题,就是客户端使用线程并发连接的时候,我发现recv会直接返回空,然后下面的逻辑判断中认为断开了链接,就关掉了socket,但是紧接着又触发了select,这个时候才接受到recv的数据,如果客户端只发起一两个socket连接就正常的

waiting for next event
    connection from  ('127.0.0.1', 51852)
read
  closing ('127.0.0.1', 51852)
remove inputs ('127.0.0.1', 51852)
del message_queues ('127.0.0.1', 51852)
0
waiting for next event
read
 received  hi,I'm NO.106 from  ('127.0.0.1', 51852)
append outputs ('127.0.0.1', 51852)
1
waiting for next event
write:	
 sending  hi,I'm NO.106  to  ('127.0.0.1', 51852)
1
waiting for next event
write:	
  ('127.0.0.1', 51852) queue empty remove output
0

查资料说python的非阻塞socket在recv的时候如果没收到消息,会立马抛出异常,但是这里又没有抛出异常,所以应该不是这个原因,可是看代码和执行过程,确实没有抛出异常,而是直接往下执行了,然后发现没数据,就关闭了socket,触发了select,然后读取到了数据。可是这个逻辑也有问题,(参照上面的逻辑)因为第一次进来就把message_queues里面的队列给删了,然而在后面获取message_queues[s]的时候没有出现异常,可是上面keyerror又不知道怎么解释了。


唉,感觉好乱啊,完全不知道这是什么情况


本人出于个人兴趣,创建了一个个人公众号,每天筛选国外网友发现的有趣的事情推送到公众号,欢迎关注!


Python系列 之 socket模块 - 非阻塞模式 Python socket模块学习socket模块学习非阻塞模式select模块selectors模块 socket模块学习 非阻塞模式 socket的默认情况下是阻塞模式:socket.accept()方法在没有接受到连接之前不能处理已经建立连接的其他操作,以及在recv()方法或者其他接受数据的方法时候都是阻塞的,如果没有接受到数据就会一直处于阻塞状态,来等待接受数据,这种情况只有通过开启新的进程或者线程来解决来自不同客户端的连接请求或者接受数据;socket可以支持非阻塞的模式;可以使用以下两种方法来 阅读详情

相关推荐

【LLM】ms-Swift框架下SFT与GRPO协同优化的高效训练策略

本文深入探讨了ms-Swift框架下监督微调(SFT)与群组相对策略优化(GRPO)的协同训练策略,提升大型语言模型(LLM)的性能与效率。通过创新的架构设计和两阶段训练流程,结合GRPO的群组奖励估计与动态基线调整技术,显著优化了数学推理等任务的准确率。文章还分享了计算资源高效利用和参数调优的实战经验,为LLM训练提供了实用指导。

green的博客 994

python3socket非阻塞_Python—网络通信编程之tcp非阻塞通信(socketserver)

服务端代码import socketserver# 定义一个类class MyServer(socketserver.BaseRequestHandler):# 如果handle方法出现报错,则会进行跳过.但是setup方法和finish方法无论如何都会进行执行的.def setup(self):print("首先执行setup")def handle(self):print("然后执行handl...

weixin_39805734的博客 518

ABAP传输自定义IDOC实例

首先确定出站方和入站方,本例中我使用150作为发送方将200作为接收方。 发送端系统配置 进入tcode-SALE,点击定义逻辑系统,这里我定义D01CLNT150为发送端, D01CLNT200为接收端 2,将逻辑系统分配给对应的client 3,进入tcode-WE31,创建IDOC开发段(segment)这里可以按照实际需求创建想要传输的结构,为求简单我创建了ZKNA1并选取了几个客户主数据的字段作为示例 4,进入tcode-WE30,创建Idoc Ty...

Nathan的博客 4077

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

基于python select.select模块通信的实例讲解 要理解select.select模块其实主要就是要理解它的参数, 以及其三个返回值。 select()方法接收并监控3个通信列表, 第一个是所有的输入的data,就是指外部发过来的数据,第2个是监控和接收所有要发出去的data(outgoing data),第3个监控错误信息在网上一直在找这个select.select的参...

weixin_30415113的博客 138

用C#完成最小二乘法拟合平面方程,再计算点到面的距离

【代码】用C#完成最小二乘法拟合平面方程,再计算点到面的距离。

MechMaster 647

STM32F030F4P6 ADC多通道定时器触发DMA搬运

主函数中等待转换完成的标志位,然后打印出来。ADC回调函数中将数值赋值给变量。配置定时器1s读一次。

qq_24426625的博客 1355

python连续输入直到回车退出_python – 通过按Enter键而不阻塞退出while循环.我该如何改进这种方法?...

所以我一直在读一下如何通过用户按下回车键退出while循环,我想出了以下内容:import sys, select, osswitch = 1i = 1while switch == 1:os.system('cls' if os.name == 'nt' else 'clear')print "I'm doing stuff. Press Enter to stop me!"print iwhi...

weixin_39693438的博客 734

【读书笔记】Verilog的亚稳态现象和跨时钟域处理方法

文章目录 一、亚稳态 (1)跨时钟域的亚稳态现象 (2)亚稳态的多径传输 二、跨时钟域处理 2.1 单bit信号跨时钟域处理 (1)单径两级触发器同步器 (2)相位控制 (3)多径与多级寄存器同步链 (4)组合逻辑信号的同步化 (5)快时钟域信号的同步化 2.2 多bit信号的跨时钟域处理 (1)异步FIFO (2)双口RAM.........

毕淑敏曾说过:“我不相信命运,我只相信自己的手;我不相信手掌上的纹路,但我相信手指加上手掌的力量”。在这个快节奏的社会,只有自己能力不足才会被卷,踏踏实实沉下心来学一些技术,及时记录,方便以后复盘。 2万+

socket python 收 发 队列 线程,Python套接字接收/发送多线程

I am writing a Python program where in the main thread I am continuously (in a loop) receiving data through a TCP socket, using the recv function. In a callback function, I am sending data through the...

weixin_42498892的博客 128

《多模态融合改进》目录一览 | 专栏介绍 :全网 第一份 完整的多模态改进教程,提供《多模态模型改进完整项目包》-开箱即用

在大家订阅专栏后,便可获得多模态模型改进完整项目包-开箱即用,方便简单

Limiiiing的博客 1万+

十四种逻辑器件综合对比——《器件手册--逻辑器件》

逻辑器件是数字电路中最基本的逻辑单元,用于实现基本的逻辑运算,如与、或、非、异或等。逻辑门根据输入信号的组合产生相应的输出信号。与门:只有当所有输入信号都为高电平时,输出才为高电平。或门:只要有一个输入信号为高电平,输出就为高电平。非门:输出信号与输入信号相反。异或门:当两个输入信号不同时,输出为高电平;相同则输出为低电平。用于对输入信号进行反相操作,即将高电平转换为低电平,低电平转换为高电平。常用于信号的反相处理和逻辑电平的转换。

XU157303764的博客 2029

epoll实现服务器多进程多任务问答机制

#coding=utf-8 import socket import re import select import threading import multiprocessing import gevent from gevent import monkey monkey.patch_all() # 遇到阻塞自动切换协程,程序启动时执行monkey.patch_all()解决 def service_client(new_socket, request): '''为这个客户...

weixin_42219287的博客 222

SPMI协议学习总结

SPMI(System Power Management Interface)是由MIPI(Mobile Industry Processor Interface)联盟定义的一种硬件接口标准,它主要用于移动设备中,连接SoC(System on Chip)处理器系统的集成电源控制器与一个或多个电源管理IC(PMIC),以实现精确的电源管理

歌颂苦难的行为是无耻的; 1082

使用select实现非阻塞socket | dbafree首页

使用select实现非阻塞socket | dbafree首页 使用select实现非阻塞socket | dbafree首页在linux,perl,python上都存在select系统调用。下面这两个python程序,可以用来学习和调试select操作。参考至:h...

137

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

python中select用法_Python select模块简单使用

select()的机制中提供一fd_set的数据结构,实际上是一long类型的数组, 每一个数组元素都能与一打开的文件句柄(不管是Socket句柄,还是其他文件或命名管道或设备句柄)建立联系,建立联系的工作由程序员完成, 当调用select()时,由内核根据IO状态修改fd_set的内容,由此来通知执行了select()的进程哪一Socket或文件可读或可写。主要用于Socket通信当中。总结:s...

weixin_30444697的博客 7602

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

python非阻塞输入_Python中使用select模块实现非阻塞的IO

Socket的英文原义是“孔”或“插座”。作为BSD UNIX的进程通信机制,取后一种意思。通常也称作”套接字”,用于描述IP地址和端口,是一个通信链的句柄。在Internet上的主机一般运行了多个服务软件,同时提供几种服务。每种服务都打开一个Socket,并绑定到一个端口上,不同的端口对应于不同的服务。Socket正如其英文原意那样,像一个多孔插座。一台主机犹如布满各种插座的房间,每个插座有一个...

weixin_39723010的博客 399

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

〖Python〗-- socket + select 实现构建异步非阻塞模块

【socket + select 实现构建异步非阻塞模块】 对于异步IO请求的本质则是【非阻塞Socket】+【IO多路复用】,那我们是否可以自定义异步IO模块,作为客户端,用于发送请求呢?答案那是肯定的! 补充说明:select可操作任何对象,但对象内必须是有fileno方法,可以看作是一个数值,给系统提供(文件句柄),其内部执行的是socket对象fileno方法的返回值! 自...

dmzzb82846的专栏 265

python中select用法_Python select()使用方法

Python的select()方法直接调用操作系统的IO接口,它监控sockets,open files, andpipes(所有带fileno()方法的文件句柄)何时变成readable 和writeable,或者通信错误,select()使得同时监控多个连接变的简单,并且这比写一个长循环来等待和监控多客户端连接要高效,因为select直接通过操作系统提供的C的网络接口进行操作,而不是通过Pyt...

weixin_39842918的博客 5565

python中select怎么用

Python的select()方法直接调用操作系统的IO接口,它监控sockets,open files, and pipes(所有带fileno()方法的文件句柄)何时变成readable 和writeable, 或者通信错误,select()使得同时监控多个连接变的简单,并且这比写一个长循环来等待和监控多客户端连接要高效,因为select直接通过操作系统提供的C的网络接口进行操作,而不是通过Python的解释器。下面是此程序的主循环,调用select()时会阻塞和等待直到新的连接和数据进来。

hakesashou的博客 1532

[python3.3]Python异步Socket编程【TCP】

参考: http://www.cnblogs.com/snailrun/p/3805188.html

JoeBlackZQQ的专栏 1万+

python监听多个udp端口_尝试实现非阻塞python-udp多端口获取wierd异常

我试图实现一个非阻塞的pythonudp服务器,它监听多个端口。在我在这个Stackover posting中找到了一些代码,并将其修改为监听多个套接字,到目前为止,非常好。在我的代码如下。在#!/usr/bin/pythonimport selectimport socketports_list=[7777,7778]def make_socket(number):sock = socket.s...

weixin_39778150的博客 1096

Python -【Socket select】基本使用介绍

Python -【Socket Socket select】基本使用介绍

Mr_WoLong 1668

在python中编写socket服务端模块(一):使用select

本文介绍使用select编写socket服务端模块。 服务器端程序代码: import socket import select import Queue server=('10.0.2.15',21345) #SOCK_STREAM(流套接字)、SOCK_DGRAM(数据报文套接字)、AF_INET(IPv4) sock=socket.socket(socket.AF_INET,so

tdmyl的专栏 2197

python 高并发 select socket_Python selectors实现socket并发

importsocket, loggingimportselect, errnologger= logging.getLogger("network-server")defInitLog():logger.setLevel(logging.DEBUG)fh= logging.FileHandler("network-server.log")fh.setLevel(logging.DEBUG)ch=...

weixin_39901203的博客 267

websocket 与 socket 非阻塞通信

记录一下 import select import socket import threading from flask import Flask from flask_sockets import Sockets from gevent import pywsgi from geventwebsocket.handler import WebSocketHandler app = Flask(__name__) sockets = Sockets(app) class Config(obj.

没有撤退可言. 1618
上一篇: How To Create a SSL Certificate on Apache for Ubuntu 14.04
下一篇: python多线程join方法导致不能接收信号
ECHOutopia
博客等级 码龄14年 11粉丝 29原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值