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]:代表第二個客戶端連接上來

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