io多路复用___select

本文详细探讨了IO多路复用的概念,重点解析了select系统调用的工作原理及其在处理多个描述符时的效率。通过实例分析,阐述了如何使用select进行并发I/O操作,并讨论了其在高并发场景下的优缺点和适用范围。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

#include<stdio.h>
#include<stdlib.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<unistd.h>
#include<string.h>

#define SIZE 30


int tcp_socket(int port);

int main(int argc,char *argv[])
{
	if(argc != 2)
	{
		printf("+ port\n");
		return 1;
	}
	int sock = tcp_socket( atoi(argv[1]) );
	if (sock == -1)
	{
		printf("socket error\n");
		return 1;
	}
	int r;

	fd_set reads,temp;//reads为文件描述符集合,temp为临时集合
	socklen_t len;
	int fd_max,i;
	struct timeval timeout;//时间结构体
	char buf[SIZE];

	FD_ZERO(&reads);//清空reads集合
	FD_SET(sock,&reads); //监听描述符sock加入集合reads
	fd_max=sock; //文件描述符数量为sock,sock数值为3,因为012为stdin,stdout,stderr
	struct sockaddr_in cli_addr;

	while(1)
	{
		temp=reads;//temp临时存储集合,因为如果reads某个位置有变化,
		// 原来为1的位置都变为0,但发生变化的文件描述符不变,所以要临时保存集合

		timeout.tv_sec=5; //设置超时时间5s
		timeout.tv_usec=0;
		printf("fd_max = %d\n", fd_max);
		r=select(fd_max+1, &temp, NULL, NULL, &timeout);  //调用select函数,对临时集合temp监听
		if(r == -1)
			break;
		else if(r == 0)	//返回0,超时
		{
			printf("time out! 5s\n");
		    continue;
		}
		else
		{
			for(i = 3; i < fd_max+1; i++) //从下标为3的集合位置开始
			{
				if(FD_ISSET(i,&temp))//如果这个位置有变化
				{
					if(i == sock)//有新客户端加入
					{
						len=sizeof(cli_addr);
						int cli_sock=accept(sock,(struct sockaddr*)&cli_addr,&len);
						if(cli_sock == -1)
							continue;
						FD_SET(cli_sock,&reads);//在reads集合加入新文件描述符
						if(fd_max < cli_sock)
							fd_max=cli_sock;  //如果最大数量有变
						printf("new client fd=%d\n",cli_sock);
					}
					else{//有客户消息发送
					
						memset(buf,0,SIZE);
						r=read(i,buf,SIZE-1);
						if(r == 0) //客户端断开链接
						{
							FD_CLR(i,&reads);////在reads集合删除文件描述符
							close(i);
							printf("closed client fd:%d\n",i);
						}
						else if(r > 0){
							//printf("client %d:",i);
							write(i,buf,r);//写回客户端
							buf[r]='\0';
							printf("recv from client %d: %s\n",i,buf);
						}
						else {

							printf("read error\n");
							exit(1);
						}

					}
				}
			}
		}

	}
	close(sock);
	//printf("%d\n",sock);
	return 0;
}



		
int tcp_socket(int port){
	int sock;
	struct sockaddr_in addr;
	memset(&addr,0,sizeof addr);
	addr.sin_family=AF_INET;
	addr.sin_addr.s_addr=htonl(INADDR_ANY);
	addr.sin_port=htons(port);

	sock=socket(AF_INET,SOCK_STREAM,0);
	//在bind前,设置端口复用
    const int on=1;
    if (setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&on,sizeof on))
    {
        printf("setsockopt\n");
        return -1;
    }
	int r = bind(sock,(struct sockaddr*)&addr,sizeof(addr));
	if(r == -1)
		return -1;
	r=listen(sock,10);
	if(r == -1)
		return -1;
	return sock;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值