文章目录
前言
selec 和 pselect 可以同时监控多个多个文件描述符(I/O复用),包括STDIN,STDOU,socket 文件描述符等。等待一个或多个文件描述符状态变为准备状态(事件驱动)。
提示:本文所有代码只是测试用例,作为学习记录,请勿在项目代码中直接使用。
一、优缺点?
优点: 可以监控多个文件描述符。监控文件描述符较少的情况下,效率很高。
缺点:1. 每次调用select 都要需要把fd集合从用户态拷贝到内核态。性能损失
2. 每次调用select都要要遍历从内核传递过的fd。
3. 文件描述数量大小为1024。可以更改头文件typesizes.h 中 __FD_SETSIZE 宏大小更改.
二、测试代码
本测试是测试多客户端请求select服务端性能及问题,多个线程分别发送一定数量的包,服务端状态及接受状况。
1.服务端
#include <sys/select.h>
#include <stdio.h>
#include <time.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <sys/types.h>
#include <vector>
#include <iostream>
#include <errno.h>
#include <string.h>
#include <atomic>
void setFdNoblock(int fd)
{
fcntl(fd, O_NONBLOCK);
}
int main()
{
std::vector<int> setlist;
//setlinebuf(STDIN_FILENO);
fd_set sets;
FD_ZERO(&sets);
struct sockaddr_in sa;
sa.sin_family = AF_INET;
sa.sin_addr.s_addr = INADDR_ANY;
sa.sin_port = htons(12550);
int st = socket(AF_INET, SOCK_STREAM, 0);
if (st == -1)
{
printf("create socket error %s.\r\n", strerror(errno));
exit(-1);
}
if (bind(st, (struct sockaddr *)&sa, sizeof(sa)) == -1)
{
printf("bind socket error %s.\n", strerror(errno));
exit(-1);
}
if(listen(st, 1023) == -1)
{
printf("listen socket error %s.\n", strerror(errno));
exit(-1);
}
volatile std::atomic<int> count(0);
int maxfd = st;
std::cout<<"server start."<<std::endl;
int loopcount = 0;
while (true)
{
loopcount++;
FD_SET(st, &sets);
for (auto i : setlist)
{
FD_SET(i, &sets);
}
int ocfd = select(maxfd + 1, &sets, NULL, NULL, NULL);
if (FD_ISSET(st, &sets))
{
struct sockaddr_in client;
socklen_t scsize = sizeof(client);
int clientfd = accept(st, (struct sockaddr *)&client, &scsize);
std::cout<<"client connect["<<inet_ntoa(client.sin_addr)<<"] connet."<<std::endl;
fcntl(clientfd,F_SETFL,O_NONBLOCK);
setlist.push_back(clientfd);
if (maxfd < clientfd)
{
maxfd = clientfd;
}
}
for (int i = 0; i < ocfd; i++)
{
for (auto i : setlist)
{
if (FD_ISSET(i, &