zoukankan      html  css  js  c++  java
  • Linux select网络模型

    想比较Windows环境下的select,Linux真的是有点不省事,对于select调用之后的readfds,windwos可以直接获取大小并遍历,但是Linux却没有这么人性化,还需要自己添加一个数组,把所有连接服务器的客户端放进去,然后一个一个遍历。

    ////////////////////////////////////////////////////////////////////分割线//////////////////////////////////////////////////////////////////////////////////////////////////////////

    select是用于I/O多路转接的一个系统调用函数。

    在C程序中,该系统调用在 sys/select.h 或 unistd.h中声明,语法如下:

    int select(int nfds, fd_set* readfds, fd_set* writefds, fd_set* errorfds, struct timeval* timeout);
    
    参数描述
    nfds sets的文件描述符的最大值
    readfds fd_set 类型,包含了需要检查是否可读的描述符,输出时表示哪些描述符可读。可为 NULL
    writefds fd_set 类型,包含了需要检查是否可写的描述符,输出时表示哪些描述符可写。可为 NULL
    errorfds fd_set 类型,包含了需要检查是否出错的描述符,输出时表示哪些描述符出错。可为 NULL
    timeout struct timeval 类型的结构体,表示等待检查完成的最长时间。

    注:上述来自维基百科

    ////////////////////////////////////////////////////////////////////分割线//////////////////////////////////////////////////////////////////////////////////////////////////////////

    对于select函数,在Linux环境下需要注意的是第一个参数nfds,因为在linux默认的文件描述符最大值为1024,请参看:

    同时0,1,2分别被输出输入错误占用,所以在当新的客户端来的时候只能是从3开始往上增加。

    同时nfds为所监听的所有文件描述符中,最大的文件描述符+1.

    这点我有点疑惑,所以,如果你也有疑惑,请百度一下。

    接下来就是我写的代码了,使用的是vector存储文件客户端的socket,但是我的代码可能有缺陷和漏洞,你可以参考并修补一下。

    ps:由于qt中不能使用谷歌输入法,只能用ibus,所以我的注释没有中文,同时注释也很少。

    //select
    
    #include <sys/select.h>
    #include <stdio.h>
    #include <string.h>
    #include <unistd.h>
    #include <sys/socket.h>
    #include <sys/types.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #include <vector>
    #include <iostream>
    #include <string.h>
    using namespace std;
    
    #define SERVER_IP "127.0.0.1"
    #define SERVER_PORT 6663
    #define CLIENT_NUM 100
    
    int main(){
    
        int sockCli, sockSer;
        sockaddr_in addrCli, addrSer;
        vector<int> allsock;
    
         //init socket
        sockSer = socket(AF_INET,SOCK_STREAM,0);
        if(sockSer == -1){
            perror("socket init error:");
            return -1;
        }
    
        //init sockaddr_in
        addrSer.sin_port = htons(SERVER_PORT);
        addrSer.sin_family = AF_INET;
        inet_pton(AF_INET,SERVER_IP,&addrSer.sin_addr.s_addr);
    
        //bind
        if( -1 == bind(sockSer,(sockaddr*)&addrSer,sizeof(sockaddr)))
        {
            perror("bind error: ");
            return -1;
        }
    
        if(-1 == listen(sockSer,CLIENT_NUM)){
            perror("listen error: ");
            return -1;
        }
    
        //select
        fd_set readFds, tempReadfds;;
        FD_ZERO(&readFds);
        FD_SET(sockSer,&readFds);
        timeval time;
        time.tv_sec = 0;
        time.tv_usec = 3;
    
        while(1){
    
            FD_ZERO(&tempReadfds);
            memcpy(&tempReadfds,&readFds,sizeof(fd_set));
    
    
            int rect = select(allsock.size()+4,&tempReadfds,NULL,NULL,&time);
            if(rect == -1){
                perror("select error: ");
                return -1;
            }
            else if(rect == 0){
                continue;
            }
            else if(rect > 0){
    
                char buf[1024];
                bzero(buf,sizeof(buf));
                for(long unsigned int i = 0; i < allsock.size();i++){
                    if(FD_ISSET(allsock[i],&tempReadfds)){
                        //client seng msg
                        int n = read(allsock[i],buf,1024);
                        if(n > 0){
                            cout << "client send msg " << buf << endl;
                            for(int i = 0; i < n; i++){
                                buf[i] = toupper(buf[i]);
                            }
                            write(allsock[i],buf,n);
                        }
                        else {
                           cout << "client exit" << endl;
                           FD_CLR(allsock[i],&readFds);
                           vector<int>::iterator it = allsock.begin()+i ;
                           allsock.erase(it);
                           i--;
                        }
                    }
                }
                if(FD_ISSET(sockSer,&tempReadfds)){
                    //new client connect
                    socklen_t len = sizeof(sockaddr);
                    sockCli = accept(sockSer,(sockaddr*)&addrCli,&len);
                    if(sockCli == -1){
                        perror("accept error:");
                        continue;
                    }
                    else{
                        printf("new client's %s has connect, port: %d
    ",
                               inet_ntoa(addrCli.sin_addr),htons(addrCli.sin_port));
                        FD_SET(sockCli,&readFds);
                        FD_SET(sockCli,&tempReadfds);
                        allsock.push_back(sockCli);
                        memset(&addrCli,'0',sizeof(sockaddr));
                        sockCli = 0;
                    }
                }
            }
        }
    }

    客户端请使用nc命令:

  • 相关阅读:
    C++中的头文件和源文件
    串口VMIN VTIME 详解
    lms111,rplidar 方向和起始角
    Nginx访问限制配置
    Nginx请求限制配置
    Nginx模块详解
    Nginx默认配置语法
    Nginx编译参数详解
    Nginx安装目录详解
    Nginx的快速安装
  • 原文地址:https://www.cnblogs.com/jianmoxiansheng-Guo/p/13240123.html
Copyright © 2011-2022 走看看