Select (IO多路复用)

Select

select(maxfd+1,&rset,&wset,&eset,timeval* tv)

select函数成功返回时会将未准备好的描述符位清零

​ fd_set就是比特位的设置

​ 五个参数分别: 1.fd_set的长度 2.关注哪些fd_set集合收到数据(recv) 3.关注哪些fd_set集合能写(send) 4.关注哪些fd_set 集合有错误 5.多长时间select轮询一次io

流程:

fd_set  fdread;//一个io的数组,如果有数据来对应io下标(即socket)的数组就置1,无数据则置0
FD_ZERO(&fdread);//置空
FD_SET(sockfd,&fdread);//将fdread的对应比特位置为1
timeval tv;
tv.tv_sec=5;//5s
tv.tv_usec=0;
while(1)
{
	int selection=select(socked+1,&fread,NULL,NULL,&tv);//返回多少个io 
	if(!selection||!FD_ISSET(sockfd,&fdread))//判断io是否为零或者sockfd是否存在于fdread(即对应fd_set是否被置为1)
	{
		break;
	}else
	{
		memset(buffer,0,BUFFERSIZE);
		int len=recv(sockfd,buffer,BUFFERSIZE,0);//可能出现一次recv无法接收全部包,因此需要定义一个变量接收全部的recv
	}
}
#include<iostream>
#include<list>
#include<memory>
#if defined(__linux__)
#include<unistd.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#define closesocket close
#else
#include<WinSock2.h>
#define socklen_t int
#endif
#include<functional>
using namespace std;
#pragma comment(lib,"ws2_32.lib")
int main()
{
#if defined(__WIN32)
    WSADATA ws;
    WSAStartup(MAKEWORD(2, 2), &ws);
#endif
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    sockaddr_in sin;
    sin.sin_family = AF_INET;
    sin.sin_addr.s_addr = htonl(INADDR_ANY);
    sin.sin_port = htons(9999);
    int ret = ::bind(sockfd, (sockaddr*)&sin, sizeof(sin));
    if ( ret == -1)
    {
        cout << "绑定失败" << endl;
    }
    listen(sockfd, 10);
    fd_set rfd,wfd,rset,wset;
    FD_ZERO(&rfd);
    FD_SET(sockfd, &rfd);
    FD_ZERO(&wfd);
    FD_SET(sockfd, &wfd);
    int maxfd = sockfd;
    char buf[1024] = { 0 };
    int len = 0;
    while (1)
    {
        rset = rfd;
        wset = wfd;
        int nready = select(maxfd + 1, &rset, &wset, NULL, NULL);
#if 1
        if (FD_ISSET(sockfd, &rset))
        {
            sockaddr_in clsin;
            socklen_t len=sizeof(clsin);
            int clientfd = accept(sockfd, (sockaddr*)&clsin,&len );
            if (clientfd != -1)cout << "连接成功" << endl;
            FD_SET(clientfd, &rfd);
            maxfd = max(maxfd, clientfd);
            send(clientfd, "yes", 4, 0);
        }
        for (int i = sockfd + 1; i <= maxfd; i++)
        {
            if (FD_ISSET(i, &rset)) {
                len = recv(i, buf, sizeof(buf), 0);
                if (len == 0) {
                    closesocket(i);
                    FD_CLR(i, &rfd);
                }
                else if (len > 0)
                {
                    cout << buf << endl;
                    FD_SET(i, &wfd);
                }
            }
            else if (FD_ISSET(i, &wset)) {
                send(i, buf, len, 0);
                //FD_SET(i, &rfd);
                FD_CLR(i, &wfd);
            }
        }
#endif // 0
        
    }
    return 0;
}

fcntl.h

设置阻塞头文件 fcntl.h

Linux设置非阻塞fcntl(socket,F_SETFL,O_NONBLOCK)

windows设置非阻塞

int flag = 1;//flag为0阻塞,flag为1非阻塞
ioctlsocket(sockfd, FIONBIO, (unsigned long*)&flag);

文章参考与<零声教育>的C/C++linux服务器高级架构系统教程学习:Linux服务器高级架构师

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值