linux多路转接select---服务器代码

一、linux多路转接select---服务器代码

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

int main(int argc,const char* argv[])
{
    if(argc<2)
    {
        printf("please input ./a.out port\n");
        return 0;
    }
    int port=atoi(argv[1]);//argv[1],从命令行输入端口号
    //1、socket创建套接字
    int lfd=socket(AF_INET,SOCK_STREAM,0);
    if(lfd==-1)
    {
        perror("socket error");
        return -1;
    }

    //2、bind绑定端口号,ip
    struct sockaddr_in ser_addr;//创建结构体存储使用协议,ip地址、端口号
    ser_addr.sin_family=AF_INET;//ipv协议
    ser_addr.sin_port=htons(port);//设置端口
    ser_addr.sin_addr.s_addr=htonl(INADDR_ANY);//监听本机所有ip
    int ret=bind(lfd,(struct sockaddr*)&ser_addr,sizeof(ser_addr));
    if(ret==-1)
    {
        perror("bind error");
        return -1;
    }
    //3、listen监听
    listen(lfd,128);

    //4、创建文件描述符表,并初始化,将监听的lfd加入到读集合中
    fd_set readfds,tempfds;
    FD_ZERO(&readfds);
    FD_SET(lfd,&readfds);

    int maxfd=lfd;//记录文件描述符集中当前最大的文件描述符
    //5、循环委托内核检测
    struct sockaddr_in cli_addr;
    socklen_t cli_addr_len=sizeof(cli_addr);
    while(1)
    {
        tempfds=readfds;
        int num=select(maxfd+1,&tempfds,NULL,NULL,NULL);//第三个NULL,永久阻塞
        if(num==-1)
        {
            perror("select error");
            exit(1);
        }
        if(FD_ISSET(lfd,&tempfds))//有新的连接请求,select退出阻塞,清空tempfds中没有连接请求的文件描述符;FD_ISSET检测lfd文件描述符是否在tempfds文件描述符集中
        {

            int cfd=accept(lfd,(struct sockaddr*)&cli_addr,&cli_addr_len);//接收连接
            if(cfd==-1)
            {
                perror("accept error");
                exit(1);
            }
            //将cfd加入到文件描述符集readfds中
            FD_SET(cfd,&readfds);
            //更新最大的文件描述符
            maxfd=maxfd>cfd?maxfd:cfd;
            
            //打印新连接的客户端ip和port号
            char ip[16];
            memset(ip,0,sizeof(ip));
            const char* addr_dst=inet_ntop(AF_INET,&cli_addr.sin_addr.s_addr,ip,sizeof(ip));//将客户端IP转换为字符串形式存储到ip中
            printf("client IP:%s,port:%d,connect sucessful\n",addr_dst,ntohs(cli_addr.sin_port));//将端口号从网络字节顺序转换到本机字节顺序(无符号短整型)

        }
        //循环判断客户端时候发送数据
        for(int i=lfd+1;i<=maxfd;++i)
        {
            if(FD_ISSET(i,&tempfds))//如果客户端发送数据
            {
                char buf[1024];
                //读数据
                memset(buf,0,sizeof(buf));
                int n=read(i,buf,sizeof(buf));
                if(n<0)
                {
                    printf("read error");
                    exit(1);
                }else if(n==0)
                {
                    printf("client disconnect\n");
                    close(i);
                    FD_CLR(i,&readfds);
                }else{
                    printf("recv buf:%s\n",buf);

                    //写数据
                    write(i,buf,sizeof(buf));
                }

            }

        }


    }
    close(lfd);

    return 0;
}

 

注:select多路转接的意义,以及解题思路后续补上(见谅)

 

二、运行截图

1、服务器运行截图

 

 

 

2、客户端A、B运行截图

 

 

 

 

 

注:192.127.50.128是我电脑的ip地址,你可以用ifconfig查看自己电脑的ip地址,然后替换

127.0.0.1是本机的回送地址,一般用于测试使用

nc命令+ip(本机回收ip或电脑ip)+端口号可以模拟客户端用于测试

 

一入编程深似海、多学多查多动手

 

posted @ 2021-01-26 19:08  阿斯顿之意  阅读(139)  评论(0)    收藏  举报