【并发服务器】高并发服务器模型select实现服务器和客户端通信

select函数

函数原型:
int select(int nfds, fd_set *readfds, fd_set *writefds,fd_set *exceptfds, struct timeval *timeout);

【参数列表】:

nfds:监听的所有文件描述符的最大描述符+1(内核采取轮询的方式);
readfds:读文件描述监听集合;
writefds:写文件描述符集合;
exceptfds:异常文件描述符集合;
timeout:大于0:设置监听超时时长;NULL:阻塞监听;0:非阻塞监听;

【返回值】:

大于0:所欲监听集合中,满足对应时间的总数
0:没有满足的
-1:出错error

【注意】:

第二个、第三个、第四个参数的类型为fd_set ,内核为操作这种集合定义了四个函数:

void FD_CLR(int fd,fd_set * set);    //将一个文件描述符从集合中移除

void FD_SET(int fd,fd_set * set);    //将监听的文件描述符,添加到监听集合中

void FD_ZERO(fd_set * set)    //清空一个文件描述符集合

int FD_ISSET(int fd,fd_set * set);    //判断一个文件描述符是否在一个集合中,返回值:在1,不在0

【示例】:

server.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#define N 5

int Initserver()
{
//创建网络套接字
    int serfd=socket(AF_INET,SOCK_STREAM,0);
    if(-1==serfd)
    {
        perror("socket failed\n\r");
        return -1;
    }
    printf("套接字创建成功\n\r");
//绑定服务器ip地址和端口号
    struct sockaddr_in seraddr;
    memset(&seraddr,0,sizeof(seraddr));
    seraddr.sin_port=htons(9999);
    seraddr.sin_family=AF_INET;
    seraddr.sin_addr.s_addr=inet_addr("192.168.43.26");
    socklen_t addrlen=sizeof(seraddr);
    int ret=bind(serfd,(struct sockaddr *)&seraddr,addrlen);
    if(ret<0)
    {
        perror("bind failed\n\r");
        close(serfd);
        return -1;
    }
    printf("ip地址和端口号绑定成功\r\n");
//设置服务器为监听模式
    ret=listen(serfd,N);
    if(ret<0)
    {
        perror("listen failed\r\n");
        close(serfd);
        return -1;
    }
    printf("服务器设置为监听模式成功\r\n");
    
    return serfd;    
}

int main()
{
    int serfd=Initserver();
    fd_set rfds;	//创建读文件集合,因为是服务器,所以只需要读就可以了
    FD_ZERO(&rfds);	//清空集合
    FD_SET(serfd,&rfds);	//将我们的套接字描述符,放到读文件集合中
    int maxFd=serfd;	//首先我们将我们创建的套接字描述符最为基量最大,后续开始比较

    while(1)
    {   
        fd_set tmprfds=rfds;	//定义了一个中间变量读文件集合

        int ret=select(maxFd+1,&tmprfds,NULL,NULL,NULL);
        if(ret<0)
        {   
            perror("select failed\r\n");
            close(serfd);
            return -1;
        }
        int i=0;
        for(i=0;i<maxFd+1;i++)
        {
            if(FD_ISSET(i,&tmprfds))
            {   
                if(serfd==i)
                {                   
                    struct sockaddr_in cliaddr;
                    memset(&cliaddr,0,sizeof(cliaddr));
                    socklen_t cliaddrlen=sizeof(cliaddr);
                    int confd= accept(serfd,(struct sockaddr *)&cliaddr,&cliaddrlen);
                    if(confd<0)
                    {
                        perror("accept failed\r\n");
                        close(serfd);
                        return -1;
                    }
                    printf("建立连接成功\r\n");
                    printf("ip地址是:%s,端口号是%u\r\n",inet_ntoa(cliaddr.sin_addr),ntohs(cliaddr.sin_port));
                    FD_SET(confd,&rfds);
                    if(confd>maxFd)
                    {
                        maxFd=confd;
                    }
                }
            }
        }
    }
return 0;
}
client.c
#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <netinet/in.h>

int main()
{
//创建套接字
    int cli_sock=socket(AF_INET,SOCK_STREAM,0);
    if(cli_sock<0)
    {
        perror("socket failed\n");
        return -1;
    }
    puts("socket success\n");
//客户端可以不绑定ip地址和端口号,系统自动分配
    puts("系统自动分配ip地址和端口号\n");
    struct sockaddr_in ser_addr={0};
    socklen_t addrlen=sizeof(ser_addr);
    ser_addr.sin_family=AF_INET;
    ser_addr.sin_addr.s_addr=inet_addr("192.168.43.26");
    ser_addr.sin_port=htons(9999);
    if(connect(cli_sock,(struct sockaddr *)&ser_addr,addrlen)<-1)
    {
        perror("connect failed\n");
        return -1;
        close(cli_sock);
    }
    puts("connect success\n");


    close(cli_sock);
    return 0;
}

【结果】:
在这里插入图片描述
select是一个阻塞函数,代码只演示了IO多路复用创建的并发服务器,大家可以参考,具体的代码,可以借鉴https://blog.csdn.net/weixin_44228194/article/details/99301004,里面是完整代码。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值