select实现并发服务器

#include "Network.h"
 
#define MAX_FD 10
 
int main(int argc, const char **argv)
{
    int fd = -1, newfd = -1, ret;
    struct sockaddr_in server_addr;
    int i = 0;
    char buf[BUFSIZ];
 
    /*1、创建套接字*/
    if((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
    {
        perror("socket");
        return -1;
    }
 
    /*2、填充网络信息结构体*/
    bzero(&server_addr, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(SERVER_PORT);
 
    //优化:允许任意IP地址的客户端连接
    server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
 
    /*3、绑定=====将名称分配给套接字*/
    if(bind(fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0)
    {
        perror("bind");
        return -1;
    }
 
    /*4、监听=====把主动套接字转换为被动套接字*/
    if(listen(fd, 5) < 0)
    {
        perror("listen");
        return -1;
    }
 
    printf("***Server start success***\n");
    
    
    fd_set rset, temps;
    int num;
    struct sockaddr_in client_addr;
    socklen_t AddrLen = sizeof(client_addr);
    char ipv4_addr[16];
    
    int fd_all[MAX_FD]; //保存所有描述符,用于select调用后,判断哪个可读
    memset(fd_all, -1, sizeof(fd_all));
    fd_all[0] = fd;     //第一个为监听套接字
 
    FD_ZERO(&rset);     //清零
    FD_SET(fd, &rset);  //监听套接字fd加进集合,监视fd
 
    int maxfd = fd_all[0];  //监听的最大套接字
 
    /*
        5、用Select函数,达到I/O多路复用,一个服务器支持多个客户端
    */
    while(1)
    {
        temps = rset;    //因为无事件发生的fd会被清空,需要重新复制
 
        if((num = select(maxfd + 1, &temps, NULL, NULL, NULL)) < 0)
        {
            perror("select");
            return -1;
        }
        if(num < 0)
        {
            perror("select");
            return -1;
        }
        if(num == 0)
        {
            printf("timeout\n");
        }
 
        if(FD_ISSET(fd, &temps))      //监听套接字如果可读,就说明有新客户端连接进来了
        {
                /* 
                    6、接受=====阻塞等待客户端连接 
                */
                if((newfd = accept(fd, (struct sockaddr *)&client_addr, &AddrLen)) < 0)
                {
                    perror("accept");
                    close(fd);
                    return -1;
                }
                //客户端连接成功后在服务器端打印出来
                if(!inet_ntop(AF_INET, (void *)&client_addr.sin_addr.s_addr, ipv4_addr, sizeof(client_addr)))
                {
                    perror("ionet_ntop");
                    close(newfd);
                    close(fd);
                    return -1;
                }
 
                printf("Client [%s:%d] connected!\n", ipv4_addr, htons(client_addr.sin_port));
 
                /* 将新连接套接字加入进fd_all集合 和 rset集合 */
                for(i = 0;i <= MAX_FD; i++)
                {
                    if(fd_all[i] == -1)
                    {
                        fd_all[i] = newfd;
                        printf("client fd_all[%d] join in.\n", i);
                        break;
                    }
                    else
                    {
                        continue;
                    }
                }
                
                if(newfd == FD_SETSIZE)
                {
                    printf("error: too many client newfd\n");
                    return -1;
                }
                if(newfd > -1 && newfd < FD_SETSIZE)
                {
                    FD_SET(newfd, &rset);
                }
                
 
                if(maxfd < newfd)
                {
                    maxfd = newfd;  //更新maxfd
                }
            }
    
        /*
            7、读写数据,并且将数据返回给客户端
            循环判断哪个文件描述符
        */
        for(int i = 1;i < maxfd; i++)
        {
            if(FD_ISSET(fd_all[i], &temps))
            {
                bzero(buf, BUFSIZ);
 
                do {
                    ret = read(fd_all[i], buf, BUFSIZ-1);
                }while(ret < 0 && EINTR == errno);
 
                if(ret < 0)
                {
                    perror("read");
                    return -1;
                }
 
                if(!ret)    //客户端退出,关闭套接字,并从监听集合清除
                {
                    FD_CLR(fd_all[i], &rset);
                    close(fd_all[i]);
                    fd_all[i] = -1;
                    
                    continue;
                }   
 
                if(!strncasecmp(buf, "quit", 4))
                {
                    printf("Client all_fd[%d] has left!\n", i);
                    continue;
                }
 
                printf("[Server]Receive data: %s\n",buf);
            }
        }
    }
 
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值