温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

如何使用socket的select模型

发布时间:2021-12-18 14:46:15 阅读:149 作者:iii 栏目:大数据
开发者测试专用服务器限时活动,0元免费领,库存有限,领完即止! 点击查看>>

本篇内容主要讲解“如何使用socket的select模型”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“如何使用socket的select模型”吧!

Select模型在windows下和linux下都可以使用,更高级的epoll模型只能在linux下使用。

在开始select之前,先纠正一个错误,MsgContainer中的__check_head函数应当改为下面的样子:

def __check_head(self):    if self.msg_len == 0 and len(self.msgpond) > 5:        self.__get_msg_len()    self.__get_msg()

这个错误竟然没有人反馈,可见,大家只是看一看,都没有实际验证或使用。。。。。

select模型其实很好理解,我们给它三个数组,数组里存放的是socket,每一次的select,模型会从这三个数组中分别挑出来可读的,可写的,发生异常的socket,并分别放入到三个数组中,这样,应用层遍历这三个数组,做相应的操作。看代码:

#coding=utf-8import selectimport socketimport sysfrom MsgContainer import MsgContainerdef start_server(port):    HOST='0.0.0.0'    PORT=port    server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)    #server.setblocking(False)    server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR  , 1)    server.bind((HOST,PORT))   #套接字绑定的IP与端口    server.listen(10)           #开始TCP监听    inputs = [server]           #存放需要被检测可读的socket    outputs = []                #存放需要被检测可写的socket    message_queues = {}         #存储可发送的数据    while inputs:        readable , writable , exceptional = select.select(inputs, outputs, inputs)        # 可读        for s in readable:            if s is server:                connection, client_address = s.accept()                inputs.append(connection)                message_queues[connection] = MsgContainer()            else:                data = s.recv(3)        #故意设置的这么小                if data :                    message_queues[s].add_data(data)                    #已经从这个socket当中收到数据,如果你想写,那么就将其加入到outputs中,等到select模型检查它是否可写                    if s not in outputs:                        outputs.append(s)                else:                    #收到为空的数据,意味着对方已经断开连接,需要做清理工作                    if s in outputs :                        outputs.remove(s)                    inputs.remove(s)                    s.close()                    del message_queues[s]        #可写        for w in writable:            #此处一定要判断w是否真的可写,有可能w既在readable中,也在writable中,而读到的数据是空,这样其实是关闭了连接            if not w in message_queues:                continue            mc = message_queues[w]            msgs = mc.get_all_msg()            print msgs            for msg in msgs:                msg = mc.pack_msg(msg)                w.send(msg)            mc.clear_msg()            outputs.remove(w)        # 异常        for s in exceptional:            inputs.remove(s)            if s in outputs:                outputs.remove(s)            s.close()            del message_queues[s]if __name__ == '__main__':    if len(sys.argv) == 2:        port = int(sys.argv[1])        start_server(port)    else:        print u'请输入端口号'

这里就几个你可能疑惑的问题做重点讲解。

发现一个可读的socket时,如何去接收数据呢?此前我提供的例子,都是在wihle循环里不停的读取,在select模型中,仍然可以这样使用,但是要注意,需要把socket设置为非阻塞的,这样才能从while循环中退出来。本篇的例子没有使用while循环,而是每次读取3个字节的数据,如果对方发过来的数据长度是9,那么第一次读取后,接收缓冲区里还有6个字节的数据可读,在下一次select操作过程中,这个socket仍然会被放入到readtable中,这样,就可以继续读剩下的数据了。

       在遍历writable数组时,一定要判断该socket是不是真的可写。我在实际测试中发现了这样的情况,一个socket既在readtable中也在writable中,但在读的时候,数据是空,对方关闭了连接,此时在去写数据,就会发生错误,所以我通过对message_queues做了一个简单的检查来判断socket是不是真的可写。

在每一次写操作执行后,都从socket从writable中删除,这样做的原因很简单,该写的数据已经写完了,如果不删除,下一次select操作时,又会把他放入到writable中,可是现在已经没有数据需要写了啊,这样做没有意义,只会浪费select操作的时间,因为它要遍历outputs中的每一个socket,判断他们是否可写以决定是否将其放入到writtable中。

       在exceptional中,是发生错误和异常的socket,有了这个数组,就在也不用操心错误和异常了,不然程序写起来非常的复杂,有了统一的管理,发生错误后的清理工作将变得非常简单。

到此,相信大家对“如何使用socket的select模型”有了更深的了解,不妨来实际操作一番吧!这里是亿速云网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

亿速云「云服务器」,即开即用、新一代英特尔至强铂金CPU、三副本存储NVMe SSD云盘,价格低至29元/月。点击查看>>

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

原文链接:https://my.oschina.net/u/4632317/blog/4538803

AI

开发者交流群×