Linux环境下select并发服务器

摘要

在linux环境下多路复用模型一共有三种,分别是select、poll、epoll。本文主要记录select模型实现网络socket服务器多路并发的相关要点和知识。在写这篇文章之前,已经使用多进程和多线程实现服务器多路并发。多进程和多线程多线程对于内核的负担和内存的开销都是巨大的,原因是内核都会为新来的客户端创建新进程和新线程,会导致内核的工作效率降低。select的最大优势在于它可以在一个线程中同时处理多个socket的IO请求。

select工作机制

  • Linux下select调用的过程:
    用户层应用程序调用select(),底层调用poll();
    核心层调用sys_select() ------> do_select();

  • select首先循环遍历fd_set里面的文件描述符对应的驱动程序的poll函数,每个设备驱动poll函数会将调用select的用户进程插入到对应资源的等待队列中,然后poll函数返回bitmask告诉当前哪些资源可用,当遍历完fd_set文件描述集后如果有资源可读或可写,则返回可读或可写资源的文件描述个数,没有就进入睡眠状态,直到有资源利用时才唤醒。

  • select返回时,会把fd_set描述符集中没有发生事件的描述符清空,所以一般写程序时会定义一个数组暂存文件描述符,第二次select监测时再加入fd_set描述符集。

  • 在Linux内核有个参数__FD_SETSIZE定义了每个FD_SET的句柄个数中,这也意味着select所用到的FD_SET是有限的,也正是这个原因select()默认只能同时处理1024个客户端的连接请求:

    c /linux/posix_types.h: #define __FD_SETSIZE 1024

在这里插入图片描述

实现select服务器并发的函数总结

1、一个重要函数
int select(int max_fd, fd_set *readset, fd_set *writeset, fd_set *exceptset, struct timeval *timeout);

参数解析:

  • max_fd:指待测试的fd的总个数,值等于最大描述符+1(select监测的文件描述从0开始的)。
  • readset:监测可读,不监测设置为NULL。
  • writeset:监测可写,不监测设置为NULL。
  • exceptset:监测异常,不监测设置为NULL。
  • timeout:设置select的超时时间,如果设置为NULL则永不超时;

2、两个结构体
(1)、struct fd_set:可以理解为一个集合,这个集合中存放的是文件描述符。
(2)、struct timeval:时间值。


    struct timeval  
    {  
        time_t tv_sec;//second  
        time_t tv_usec;//minisecond  
    };  

3、四个宏定义

  • FD_CLR(inr fd,fd_set* set);用来清除set中相关fd 的位

  • FD_ISSET(int fd,fd_set *set);用来测试set中相关fd 的位是否为真

  • FD_SET(int fd,fd_set *set);用来设置set中相关fd的位

  • FD_ZERO(fd_set *set);用来清除set的全部位

程序流程图

在这里插入图片描述

实现代码

这里只贴出server_main.c,更多代码:

select服务器端:点击查看

客户端:点击查看

server_main.c

#include "server.h"


int main(int argc,char **argv)
{

	int		server_port;
	int		sockfd 	= -1;
	int		clienfd	= -1;
	int		re_val 	= -1;


	//参数解析
	re_val = argument_parse(argc, argv, &server_port);
	if(re_val < 0)
	{
		printf("参数解析错误!\n");
		exit(0);
	}

	//套接字初始化
	re_val = socket_init(server_port,&sockfd);
	if(re_val < 0)
	{
		printf("套接字初始化错误!\n");
	}

	//select服务器开始工作
	server_select_create(sockfd);	

	return 0;
}

测试

第一次测试:出现乱码
在这里插入图片描述解决方案:数据处理之前未清空数据缓冲区——memset(buf,0,sizeof(buf));

第二次测试:成功

在这里插入图片描述 clienfd[4]:代表第一个客户端连接上来
clienfd[5]:代表第二个客户端连接上来

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章