首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >3.同时管理多个socket的简单方法-select处理

3.同时管理多个socket的简单方法-select处理

作者头像
灰子学技术
发布2020-10-30 14:42:38
2.8K0
发布2020-10-30 14:42:38
举报

本篇是第三篇,主要用来讲解作为服务器的机器是如何管理多个socket的客户端连接的,毕竟recv只能监视单个socket。

一、背景介绍

在此之前,我们先来看下"操作系统是如何区分网络收到的数据是属于那一个socket的?"

答案:socket与端口号是一一对应的,操作系统会维护端口号到socket的索引结构,以快速读取,所以操作系统可以很方便的找到收到的网络数据属于那一个socket。

基于前面第2篇的知识,如果我们能够做到传递一个socket的列表,并且能够做到在socket列表没有数据的时候挂起进程,只要有一个socket有数据就唤醒这个进程貌似就可以解决这个问题。而这个也恰恰就是select的实现思路。

二、select介绍

我们通过使用select的代码来分析select的过程

int s = socket(AF_INET, SOCK_STREAM, 0);  
bind(s, ...)
listen(s, ...)

int fds[] =  // 用于存放需要监听的socket

while(1){ // 死循环,利用操作系统的进程阻塞和唤醒来工作
    int n = select(..., fds, ...) // 传入fds
    for(int i=0; i < fds.count; i++){ // 唤醒进程之后,遍历所有的socket
        if(FD_ISSET(fds[i], ...)){ // 利用FD_ISSET来判断对应的socket是否有数据
            // fds[i]的数据处理
        }
    }

1.调用select之后,操作系统把进程A分别加入这三个socket的等待队列中。

2.当任何一个socket收到数据后,中断程序将唤起进程。下图展示了sock2接收到了数据的处理流程。

3.所谓唤起进程,就是将进程从所有的等待队列中移除,加入到工作队列里面。

当进程A被唤醒后,它知道至少有一个socket接收了数据。程序只需遍历一遍socket列表,就可以得到就绪的socket。

三、select的不足之处

其一,每次调用select都需要将进程加入到所有监视socket的等待队列,每次唤醒都需要从每个队列中移除。这里涉及了两次遍历,而且每次都要将整个fds列表传递给内核,有一定的开销。正是因为遍历操作开销大,出于效率的考量,才会规定select的最大监视数量,默认只能监视1024个socket。

其二,进程被唤醒后,程序并不知道哪些socket收到数据,还需要遍历一次。

补充说明:本节只解释了select的一种情形。当程序调用select时,内核会先遍历一遍socket,如果有一个以上的socket接收缓冲区有数据,那么select直接返回,不会阻塞。这也是为什么select的返回值有可能大于1的原因之一。如果没有socket有数据,进程才会阻塞。

参考文档:

https://zhuanlan.zhihu.com/p/64138532

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-10-12,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 灰子学技术 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档