美文网首页
Linux网络编程

Linux网络编程

作者: MagicalGuy | 来源:发表于2018-11-23 18:11 被阅读0次

    TCP

    service.c
    服务端

    #include <stdlib.h>
    #include <sys/types.h>
    #include <stdio.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <string.h>
    int main(void)
    {
        int sfp,nfp;
        struct sockaddr_in s_add,c_add;
        int sin_size;
        unsigned short portnum=0x8888;
        char buff[100]={0};
    
        printf("Hello,welcome to my server !\r\n");
        sfp = socket(AF_INET, SOCK_STREAM, 0);
        if(-1 == sfp)
        {
            printf("socket fail ! \r\n");
            return -1;
        }
        printf("socket ok !\r\n");
    
        bzero(&s_add,sizeof(struct sockaddr_in));
        s_add.sin_family=AF_INET;
        s_add.sin_addr.s_addr=htonl(INADDR_ANY);
        s_add.sin_port=htons(portnum);
    
        if(-1 == bind(sfp,(struct sockaddr *)(&s_add), sizeof(struct sockaddr)))
        {
            printf("bind fail !\r\n");
            return -1;
        }
        printf("bind ok !\r\n");
    
        if(-1 == listen(sfp,5))
        {
            printf("listen fail !\r\n");
            return -1;
        }
        printf("listen ok\r\n");
        while(1)
        {
            sin_size = sizeof(struct sockaddr_in);
    
            nfp = accept(sfp, (struct sockaddr *)(&c_add), &sin_size);
            if(-1 == nfp)
            {
                printf("accept fail !\r\n");
                return -1;
            }
            read(nfp,buff,100);
            printf("received:%s\n", buff);
    
            if(-1 == write(nfp,buff,strlen(buff)+1))
            {
                printf("write fail!\r\n");
                return -1;
            }
            printf("write ok!\r\n");
            close(nfp);
        }
        close(sfp);
        return 0;
    }
    

    makefile:

    server:server.o
        gcc -o server server.o
    server.o:server.c
        gcc -c server.c -o server.o
    clean:
        rm -f *.o server
    

    =====================
    客户端
    client.c

    #include <stdlib.h>
    #include <sys/types.h>
    #include <stdio.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <string.h>
    
    int main(void)
    {
        int cfd;
        int recbytes;
        int sin_size;
        char buffer[1024]={0};   
        struct sockaddr_in s_add,c_add;
        unsigned short portnum=0x8888; 
        printf("Hello,welcome to client !\r\n");
    
        cfd = socket(AF_INET, SOCK_STREAM, 0);
        if(-1 == cfd)
        {
            printf("socket fail ! \r\n");
            return -1;
        }
        printf("socket ok !\r\n");
    
        bzero(&s_add,sizeof(struct sockaddr_in));
        s_add.sin_family=AF_INET;
        s_add.sin_addr.s_addr= inet_addr("127.0.0.1");
        s_add.sin_port=htons(portnum);
        printf("s_addr = %#x ,port : %#x\r\n",s_add.sin_addr.s_addr,s_add.sin_port);
    
        if(-1 == connect(cfd,(struct sockaddr *)(&s_add), sizeof(struct sockaddr)))
        {
            printf("connect fail !\r\n");
            return -1;
        }
        printf("connect ok !\r\n");
        write(cfd,"hello tcp socket", strlen("hello tcp socket")+1);
    
        if(-1 == (recbytes = read(cfd,buffer,1024)))
        {
            printf("read data fail !\r\n");
            return -1;
        }
        printf("read ok\r\nREC:\r\n");
        buffer[recbytes]='\0';
        printf("%s\r\n",buffer);
        getchar();
        close(cfd);
        return 0;
    }
    

    makefile:

    client:client.o
        gcc -o client client.o
    client.o:client.c
        gcc -c client.c -o client.o
    clean:
        rm -f *.o client
    

    UDP

    a端
    a.c

    #include <stdio.h>
    #include <stdlib.h>
    
    #include <string.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #include <netdb.h>
    #include <unistd.h>
    
    int port=6789;
    int main(int argc, char** argv) 
    {
        int fd; //套接口描述字
        int i=0;
        char buf[80];
        struct sockaddr_in address;//处理网络通信的地址
    
        bzero(&address,sizeof(address));
        address.sin_family=AF_INET;
        address.sin_addr.s_addr=inet_addr("127.0.0.1");//这里不一样
        address.sin_port=htons(port);
    
        //创建一个 UDP socket
    
        fd=socket(AF_INET,SOCK_DGRAM,0);//IPV4 SOCK_DGRAM 数据报套接字(UDP协议)
    
        for(i=0;i<20;i++)
        {
            /*
            * sprintf(s, "%8d%8d", 123, 4567); //产生:" 123 4567" 
            * 将格式化后到 字符串存放到s当中
            */
            sprintf(buf,"hello udp socket %d",i);
    
            /*int PASCAL FAR sendto( SOCKET s, const char FAR* buf, int len, int flags,const struct sockaddr FAR* to, int tolen);  
            * s:一个标识套接口的描述字。 
            * buf:包含待发送数据的缓冲区。  
            * len:buf缓冲区中数据的长度。 
            * flags:调用方式标志位。  
            * to:(可选)指针,指向目的套接口的地址。 
            * tolen:to所指地址的长度。 
               */
            sendto(fd,buf,sizeof(buf),0,(struct sockaddr *)&address,sizeof(address));
            sleep(1);
        }
    
        sprintf(buf,"stop");
        sendto(fd,buf,sizeof(buf),0,(struct sockaddr *)&address,sizeof(address));//发送stop 命令
        close(fd);
        printf("Messages Sent,terminating\n");
    
        exit(0);
    
        return (EXIT_SUCCESS);
    }
    

    makefile:

    client:a.o
        gcc -o client a.o
    a.o:a.c
        gcc -c a.c -o a.o
    clean:
        rm -f *.o client
    

    =========================
    b端
    b.c

    #include <stdio.h>
    #include <stdlib.h>
    
    #include <string.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #include <netdb.h>
    
    int port=6789;
    
    int main(int argc, char** argv) 
    {
    
        int sin_len;
        char message[256];
    
        int fd;
        struct sockaddr_in sin;
        printf("Waiting for data from sender \n");
    
        bzero(&sin,sizeof(sin));
        sin.sin_family=AF_INET;
        sin.sin_addr.s_addr=htonl(INADDR_ANY);
        sin.sin_port=htons(port);
        sin_len=sizeof(sin);
    
        fd=socket(AF_INET,SOCK_DGRAM,0);
        bind(fd,(struct sockaddr *)&sin,sizeof(sin));
    
        while(1)
        {
            recvfrom(fd,message,sizeof(message),0,(struct sockaddr *)&sin,&sin_len);
            printf("Response from server:%s\n",message);
            if(strncmp(message,"stop",4) == 0)//接受到的消息为 “stop”
            {
    
                printf("Sender has told me to end the connection\n");
                break;
            }
        }
    
        close(fd);
        exit(0);
    
        return (EXIT_SUCCESS);
    }
    

    makefile:

    server:b.o
        gcc -o server b.o
    b.o:b.c
        gcc -c b.c -o b.o
    clean:
        rm -f *.o server
    

    服务端select模型

    服务器端
    main.cpp

    #include <stdio.h>
    #include <sys/types.h>
    #include <unistd.h>
    #include <sys/stat.h> 
    #include <sys/time.h>
    #include <time.h>
    #include <signal.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #include <errno.h>
    #include <string.h>
    #include <stdlib.h>
    
    using namespace std;
    bool g_bwillexit = false;
    typedef struct _CmdParam
    {
        char type;
        char quename[128];
        char conntype;
        
    }CmdParam, *PCmdParam;
    
    typedef struct _CmdReply
    {
        char reply[20];
    }CmdReply;
    
    #define MYPORT 1234    // the port users will be connecting to
    #define BACKLOG 1500    // how many pending connections queue will hold
    #define BUF_SIZE 1024 
    
    int fd_A[BACKLOG];    // 客户端连接套接字数组accepted connection fd
    int conn_amount;    // current connection amount
    
    int  writen(int s, char *buff, int len)
    { 
            
        int nLeft,idx, ret;   
        nLeft = len;   
        idx = 0;
        ret = 0;
    
        while(nLeft>0)
        {   
                    if ((ret=send(s, &buff[idx], nLeft,0))== -1)
                    {
                            break;
                    } 
                    nLeft -= ret;   
                    idx += ret;
        }
        return idx;
    }
    
    int  readn(int s,char *buf,int len)
    {
     
             int nRev = 0, recvCount = 0;
             int length = len;
    
             if(buf == NULL)
              return 0;
    
            while(length>0)
             {
                      nRev = recv(s,buf+recvCount,length, 0);
                      if(nRev == -1  || nRev == 0)
                      {
                              break;
                      }
                      length -= nRev;
                      recvCount += nRev;
             }
     
             return recvCount;
    }
    
    static void  GetMyProcPath(char *buff)
    {
       char exec_name [1024] = {0};
       readlink ("/proc/self/exe", exec_name, 1024); 
       char *pSlash = strrchr(exec_name, '/');
       *pSlash = '\0';
       strcpy(buff, exec_name);
       return;
    }
    
    
    int main(int argc, char *argv[])
    {
        int sock_fd, new_fd;  // listen on sock_fd, new connection on new_fd
        struct sockaddr_in server_addr;    // server address information
        struct sockaddr_in client_addr; // connector's address information
        socklen_t sin_size;
        int yes = 1;
        char buf[BUF_SIZE];
        int ret;
        int i;
    
    
        if ((sock_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
        {
            printf("socket\n");
            exit(1);
        }
    
        if (setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1)
        {
            printf("setsockopt\n");
            exit(1);
        }
        
        server_addr.sin_family = AF_INET;         // host byte order
        server_addr.sin_port = htons(MYPORT);     // short, network byte order
        server_addr.sin_addr.s_addr = INADDR_ANY; // automatically fill with my IP
        memset(server_addr.sin_zero, '\0', sizeof(server_addr.sin_zero));
    
        if (bind(sock_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) 
        {
            printf("bind error\n");
            exit(1);
        }
    
        if (listen(sock_fd, BACKLOG) == -1)
        {
            printf("listen\n");
            exit(1);
        }
    
        printf("listen port %d\n", MYPORT);
    
        fd_set fdsr;
        int maxsock;
        struct timeval tv;
    
        conn_amount = 0;
        sin_size = sizeof(client_addr);
        maxsock = sock_fd;
        while (g_bwillexit == false)
        {
            // initialize file descriptor set
            FD_ZERO(&fdsr);
            FD_SET(sock_fd, &fdsr);
    
            // timeout setting
            tv.tv_sec = 30;
            tv.tv_usec = 0;
    
            // add active connection to fd set
            for (i = 0; i < BACKLOG; i++)
            {
                if (fd_A[i] != 0)
                {
                    FD_SET(fd_A[i], &fdsr);//fd_set fdsr;里面记录了每个客户端的套接字
                }
            }
    
            ret = select(maxsock + 1, &fdsr, NULL, NULL, &tv);//开始通过fdsr对每个套接字进行监听
            if (ret < 0)
            {
                printf("select error\n");
                break;
            }
             else if (ret == 0)
            {
                printf("timeout\n");
                continue;
            }
    
            // check every fd in the set
            // 处理已有的连接通信的,收发数据和断开连接
            for (i = 0; i < conn_amount; i++)
            {
                if (FD_ISSET(fd_A[i], &fdsr))//某个客户端套接字有响应
                {
                    CmdParam cmd ={0};
                    ret = readn(fd_A[i], (char *)&cmd, sizeof(cmd));
                    if (ret <= 0)
                    {   // client close
                        printf("client[%d] close\n", i);
                        close(fd_A[i]);
                        FD_CLR(fd_A[i], &fdsr);
                        fd_A[i] = fd_A[conn_amount-1];
                        fd_A[conn_amount-1]=0;
                        conn_amount--;
                    }
                    else
                    {   // receive data
                        printf("read:%d byetes\n", ret);
                        if (cmd.type == 'c' && (cmd.conntype == 's' || cmd.conntype=='l'))
                        {
                            printf("c and (s or l) command received\n");
                            CmdReply reply = {0};
                            strcpy(reply.reply, "ok!");
                            writen(fd_A[i], (char *)&reply, sizeof(reply));
                        }
                        else  if (cmd.type == 'c')
                        {
                            printf("c command received\n");
                            CmdReply reply = {0};
                            strcpy(reply.reply, "ok!");
                            writen(fd_A[i], (char *)&reply, sizeof(reply));
                        }
                        else if (cmd.type == 'q')
                        {
                            printf("q command received\n");     
                        }
                        else
                        {
                            printf("unknown command received\n");
                            CmdReply reply = {0};
                            strcpy(reply.reply, "unknown cmd");
                            writen(fd_A[i], (char *)&reply, sizeof(reply));
                        }
                  }
              }
         }
    
         // check whether a new connection comes
         // 接受处理新的客户端连接
         if (FD_ISSET(sock_fd, &fdsr))//sock_fd belongs to server
         {
                new_fd = accept(sock_fd, (struct sockaddr *)&client_addr, &sin_size);
                if (new_fd <= 0)
                {
                    printf("accept error\n");
                    continue;
                }
    
                // add to fd queue
                if (conn_amount < BACKLOG)
                {
                    fd_A[conn_amount++] = new_fd;
                    printf("new connection client[%d] %s:%d\n", conn_amount,
                            inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
                    if (new_fd > maxsock)
                        maxsock = new_fd;
                }
                else
                {
                    printf("max connections arrive, exit\n");
                    CmdReply reply = {0};
                    strcpy(reply.reply, "reject");
                    writen(new_fd, (char *)&reply, sizeof(reply));
                    close(new_fd);
                }
            }
       }
      // close other connections
      for (i = 0; i < BACKLOG; i++)
      {
            if (fd_A[i] != 0)
            {
                close(fd_A[i]);
            }
      }
      return 0;
      
    }
    

    makefile:

    overpasspull_server:main.o
        g++ -g -o  overpasspull_server main.o
    main.o:main.cpp
        g++ -g -c main.cpp -o main.o
    clean:
        rm -f *.o overpass
    

    =======================
    客户端
    main.cpp

    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/types.h>
    #include <unistd.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #include <string.h>
    
    #define MYPORT 1234    // the port users will be connecting to
    
    #define BACKLOG 5     // how many pending connections queue will hold
    #define BUF_SIZE 200
    
    int  writen(int s, char *buff, int len)
    { 
            
        int nLeft,idx, ret;   
        nLeft = len;   
        idx = 0;
        ret = 0;
    
        while(nLeft>0)
        {   
                    if ((ret=send(s, &buff[idx], nLeft,0))== -1)
                    {
                            break;
                    } 
                    nLeft -= ret;   
                    idx += ret;
        }
        return idx;
    }
    
    int  readn(int s,char *buf,int len)
    {
     
             int nRev = 0, recvCount = 0;
             int length = len;
    
             if(buf == NULL)
              return 0;
    
            while(length>0)
             {
                      nRev = recv(s,buf+recvCount,length, 0);
                      if(nRev == -1  || nRev == 0)
                      {
                              break;
                      }
                      length -= nRev;
                      recvCount += nRev;
             }
     
             return recvCount;
    }
    
    #define MYPORT 1234
    typedef struct _CmdParam
    {
            char type;
            char quename[128];
            char conntype;
    
    }CmdParam, *PCmdParam;
    typedef struct _CmdReply
    {
            char reply[20];
    }CmdReply; 
    
    int main(int argc, char *argv[])
    {
    
        int sockfd,sock_dt; 
        printf("#####################################################\n"); 
        printf("socket test      by pafone   19th,April,2009\n"); 
        printf("#####################################################\n"); 
        struct sockaddr_in my_addr;//local ip info 
        struct sockaddr_in dest_addr; //destnation ip info 
    
        //int destport = atoi(argv[2]); 
        if(-1 == (sockfd = socket(AF_INET,SOCK_STREAM,0)) ) 
        { 
            printf("error in create socket\n"); 
            exit(0); 
        } 
        dest_addr.sin_family = AF_INET; 
        dest_addr.sin_port = htons(MYPORT); 
        dest_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); 
        //bzero(&dest_addr.sin_zero,0,8); 
        memset(&dest_addr.sin_zero,0,8); 
        //connect 
        if(-1 == connect(sockfd,(struct sockaddr*)&dest_addr,sizeof(struct sockaddr))) 
        { 
            printf("connect error\n"); 
            exit(0); 
        } 
        int n_send_len; 
        CmdParam cmd ={0};
        cmd.type = 'c';
        //strcpy(cmd.queueip, "10.200.193.169");
        strcpy(cmd.quename, "message_stream");
        //cmd.conntype = 's';
        cmd.conntype = 's';
        //strcpy(cmd.queueport, "3371");
        n_send_len = writen(sockfd, (char *)&cmd, sizeof(cmd));
        printf("%d bytes sent\n",n_send_len); 
        sleep(5);
    
        CmdReply reply = {0};
    
        int n_read_len = readn(sockfd, (char *)&reply, sizeof(reply));
        if (n_read_len)
        {
            printf("reply:%s, length:%d\n", reply.reply, n_read_len);
        }
        sleep(5);
        memset(&cmd, 0, sizeof(cmd));
        cmd.type = 'q';
        writen(sockfd, (char *)&cmd, sizeof(cmd));
        
        close(sockfd); 
        
        return 0;
    }
    

    makefile:

    overpasspull_client:main.o
        g++ -g -o  overpasspull_client main.o
    main.o:main.cpp
        g++ -g -c main.cpp -o main.o
    clean:
        rm -f *.o overpass
    

    服务端epoll模型

    服务端
    server.c

    #include <stdio.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #include <stdlib.h>
    #include <string.h>
    #include <sys/epoll.h>
    
    #define BUFFER_SIZE 40
    #define MAX_EVENTS 10
    
    int main(int argc, char * argv[])
    {
        int server_sockfd;//服务器端套接字
        int client_sockfd;//客户端套接字
        int len;
        struct sockaddr_in my_addr;  //服务器网络地址结构体
        struct sockaddr_in remote_addr; //客户端网络地址结构体
        int sin_size;
        char buf[BUFFER_SIZE];  //数据传送的缓冲区
        memset (&my_addr ,0,sizeof(my_addr)); //数据初始化--清零
        my_addr.sin_family=AF_INET; //设置为IP通信
        my_addr.sin_addr.s_addr=INADDR_ANY;// 服务器IP地址--允许连接到所有本地地址上
        my_addr.sin_port=htons(8000); //服务器端口号
        //创建服务器端套接字--IPv4协议,面向连接通信,TCP协议
        if((server sockfd=socket(PF_INET, SOCK_STREAM,0))<0)
        {
            perror("socket");return 1 ;
        }
        //将套接字绑定到服务器的网络地址上
        if (bind(server_sockfd, (struct sockaddr *)&my_addr ,sizeof(struct sockaddr))<0)
        {
            perror("bind");
            return 1;
        }
        //监听连接请求--监听队列长度为5
        listen(server_sockfd,5);
        sin_size=sizeof(struct sockaddr_in) ;
        //创建一个epoll句柄
        int epoll_fd;
        epoll_fd=epoll_create (MAX_EVENTS);
        if(epoll_fd==-1)
        {
            perror("epoll_create failed");
            exit(EXIT_FAILURE) ;
        }
        struct epoll_event ev;//epoll事件结构体
        struct epoll_event events [MAX_EVENTS];//事件监听队列
        ev.events=EPOLLIN;
        ev.data.fd=server_sockfd;
        //向epoll注册server_sockfd监听事件
        if(epoll_ctl(epoll_fd, EPOLL_CTL_ADD,server_sockfd,&ev)==-1)
        {
    
          perror("epll_ctl:server_sockfd register failed");
          exit(EXIT_FAILURE);
        }
        int nfds;//epoll监听事件发生的个数
        while(1)
        {
            //等待事件发生
            nfds=epoll_wait(epoll_fd,events ,MAX_EVENTS,-1);
            if(nfds==-1)
            {
                printf("start epoll_wait failed\n");
                break;
            }
            int i;
            for(i=0;i<nfds;i++)
            {
                //客户端有新的连接请求
                if(events[i].data.fd==server_sockfd)
                {
                    //等待客户端连接请求到达
                    if((client_sockfd=accept(server_sockfd, (struct sockaddr * )&remote_addr ,&sin_size))<0)
                    {
                        printf("accept client_sockfd failed\n");
                        exit(EXIT_FAILURE);
                    }
                    //向epoll注册client_sockfd监听事件
                    ev.events=EPOLLIN;
                    ev.data.fd=client_sockfd;
                    if(epoll_ctl(epoll_fd, EPOLL_CTL_ADD,client_sockfd,&ev)==-1)
                    {
                        printf("epoll_ctl:client_sockfd register failed\n");
                        exit(EXIT_FAILURE);
                        printf("accept client %s\n",inet_ntoa(remote_addr.sin_addr));
                    }
                    //客户端有数据发送过来
                    else
                    {
                        client_sockfd=events[i].data.fd;
                        len=recv(client_sockfd , buf , BUFFER_SIZE,0);
                        if(len<=0)
                        {
                            ev.events=EPOLLIN;
                            ev.data.fd=client_sockfd;
                            epoll_ctl(epoll_fd,EPOLL_CTL_DEL,client_sockfd ,&ev);
                            close(client_sockfd);
                            printf("client exit %d\n" ,client_sockfd);
                            break;
                        }
                        printf("receive from client:%s\n" ,buf) ;
                        send(client_spckfd,buf, BUFFER_SIZE,0);
                    }
                }
            }
            return 0;
        }
    

    =============================
    客户端
    client.c

    #include <stdio.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #include <string.h>
    #include <stdlib.h>
    
    #define BUFFER_SIZE 40
    
    int main(int argc, char *argv[]){
        int client_sockfd;int len;
        struct sockaddr_in remote_addr; //服务器端网络地址结构体
        char buf[BUFFER_SIZE]; // 数据传送的缓冲区
        memset(&remote_addr ,θ ,sizeof(remote_addr)); //数据初始化--清零
        remote_addr.sin_family=AF_INET; //设置为IP通信
        remote_addr.sin_addr.s_addr=inet_addr("127.0.0.1");// 服务器IP地址
        remote_addr.sin_port=htons(8000); //服务器端口号
        //创建客户端套接字--IPv4协议,面向连接通信,TCP协议
        if((client_sockfd=socket(PF_INET , SOCK_STREAM,0))<0)
            {
                perror("client socket creation failed");
                exit(EXIT_FAILURE);
            }
        //将套接字绑定到服务器的网络地址上
        if(connect(client_sockfd, (struct sockaddr *)&remote_addr , sizeof(struct sockaddr))<0)
        {
            perror ("connect to server failed");
            exit(EXIT_FAILURE);
        }
    
        //循环监听服务器请求
        while(1)
            {
            printf("Please input the message:");
            scanf("%s" ,buf);
            //exit
            if(strcmp(buf,"exit")==0)
                {
                break;
                }
                send(client_sockfd, buf , BUFFER_SIZE,0);
                //接收服务端信息
                len=recv(client_sockfd, buf , BUFFER_SIZE,0);
                printf("receive from server :%s\n",buf);
                if(len<0)
                {
                    perror("receive from server failed");
                    exit(EXIT_FAILURE);
                }
            }
            close(client_sockfd);//关闭套接字
            return 0;
    }
    

    makefile:

    .PHONY:all
    all:server client
    server:
        gcc server.c -o server
        gcc client.c -o client
    clean:
        rm -f server client
    

    Select与POLL区别

    Select与POLL,EPOLL都是C种同步的10多路复用模型实现机制,它们的区别为:
    1.select的句柄数目受限,在linux/posix_types.h头 文件有这样的声明: #define __FD_SETSIZE 1024表示select最多同时监听1024个fd(64位机默认是2048)。而epoll没有,它的限制是最大的打开文件句柄数目。select需要维护一个用来存放大量fd的数据结构,这样会使得用户空间和内核空间在传递该结构时复制开销大。

    2.epoll不会随着FD的数目增长而降低效率,select采用轮询的方式扫描文件描述符,fd数量越多,性能越差; epoll维护 了一个队列,直接看队列是不是空就可以了。epoll只会对“活跃”的socket进行操作。这是因为在内核实现中epoll是根据每个fd上面的callback函数实现的,那么只有活跃socket才会主动去调用callback函数(把这个句柄加入队列)

    3.无论是select,poll还是epoll都需要内核把FD消息通知给用户空间,epoll使用mmap减少复制开销,加速内核与用户空间的消息传递。

    4.poll本质上和select没有区别,它将用户传入的数组拷贝到内核空间,然后查询每个fd对应的设备状态,但没有最大连接数限制(基于链表来存储的)

    相关文章

      网友评论

          本文标题:Linux网络编程

          本文链接:https://www.haomeiwen.com/subject/bzzjqqtx.html