zoukankan      html  css  js  c++  java
  • Linux 网络编程九(select应用--大并发处理)

    //网络编程服务端
    /*
     * 备注:因为客户端代码、辅助方法代码和epoll相同,所以select只展示服务器端代码
     */
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    #include <errno.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <arpa/inet.h>//htons()函数头文件
    #include <netinet/in.h>//inet_addr()头文件
    #include <fcntl.h>
    #include <sys/select.h>
    #include <time.h>
    #include "pub.h"
    
    #define MAXSOCKET 1024
    
    int main(int arg, char *args[])
    {
        if (arg < 2)
        {
            printf("please print one param!
    ");
            return -1;
        }
        //create server socket
        int listen_st = server_socket(atoi(args[1]));
        if (listen_st < 0)
        {
            return -1;
        }
        //设置非阻塞文件描述符
        setnonblock(listen_st);
        int i = 0;
        int maxfd = 0; //最大的socket,select函数第一个参数使用
        /*
         *建立客户端连接池
         */
        int client[MAXSOCKET]; //select最大支持1024个socket连接
        //将所有的客户端连接池初始化,将每个成员都设置为-1,表示无效
        for (; i < MAXSOCKET; i++)
        {
            client[i] = -1;
        }
        maxfd = listen_st;    //程序刚开始执行时,只有服务端socket,所以服务端socket最大
        //定义一个事件数组结构
        fd_set allset;
        while (1)
        {
            //初始化一个fd_set对象
            FD_ZERO(&allset);
            //将服务器端socket放入事件数组allset中(服务端socket需要特殊处理,所以没有放入socket池中)
            FD_SET(listen_st, &allset);
            //先假设最大的socket就是服务器端socket
            maxfd = listen_st;
            //遍历socket池 找出值最大的socket
            for (i = 0; i < MAXSOCKET; i++)
            {
                if (client[i] != -1)
                {
                    //将socket池中的所有socket都添加到事件数组allset中
                    FD_SET(client[i], &allset);
                    if (client[i] > maxfd)
                    {
                        maxfd = client[i];    //maxfd永远是值最大的socket
                    }
                }
            }
            //开始等待socket发生读事件
            int rc = select(maxfd + 1, &allset, NULL, NULL, NULL);
            /*
             * select函数返回之后,allset数组的数据产生变化,现在allset数组里的数据是发生事件的socket
             * select和epoll不同,select每次返回后,
             * 会清空select池中的所有socket,所有的socket等select返回后就被清除了
             * 所以必须由程序建立一个socket池,每次都将socket池中的socket加入到select池中
             * select不会为程序保存socket信息,这与epoll最大的不同,
             * epoll添加到events中的socket,如果不是程序员清除,epoll永远保留这些socket
             */
            if (rc < 0)
            {
                //select函数出错,跳出循环
                printf("select failed ! error message:%s
    ", strerror(errno));
                break;
            }
            //判断是否是服务器socket接收到数据,有客户端连接
            if (FD_ISSET(listen_st, &allset))
            {
                //accept
                int client_st = server_accept(listen_st);
                if (client_st < 0)
                {
                    //直接跳出select循环
                    break;
                }
                //客户端连接成功 设置客户端非阻塞
                setnonblock(client_st);
                //将客户端socket加入socket池中
                for (i = 0; i < MAXSOCKET; i++)
                {
                    if (client[i] == -1)
                    {
                        client[i] = client_st;
                        break;
                    }
                }
                if (i == MAXSOCKET)
                {
                    //socket池已满,关闭客户端连接
                    close_socket(client_st);
                }
            }
            //处理客户端的socket
            for (i = 0; i < MAXSOCKET; i++)
            {
                if (client[i] == -1)
                {
                    //无效socket直接退出
                    continue;
                }
                //判断是否是这个socket有事件发生
                if (FD_ISSET(client[i], &allset))
                {
                    //接收消息
                    if (socket_recv(client[i]) < 0)
                    {
                        //如果接收消息出错,关闭客户端socket
                        close_socket(client[i]);
                        //从socket池中将这个socket清除
                        client[i] = -1;
                    }
                    rc--;
                }
                //说明所有消息的socket已经处理完成
                if (rc < 0)
                {
                    //备注:双循环break只能跳出最近的一重循环
                    break;
                }
            }
        }
        //close server socket
        close_socket(listen_st);
        return 0;
    }
  • 相关阅读:
    用超穷归纳证明极大理想定理
    [shell]计算未知个数数据的平均值
    C中的野指针—如何避免
    [C#学习笔记02]理解值和引用
    vim编辑器的配置让你的代码更加易读
    mipslinuxgcc交叉编译工具链搭建小结
    Ubuntu 9.10下KScope的安装
    [uC/OSII]基本操作:新建任务,分配信号量
    基于Philips MF RC522的ISO14443A标准卡读写
    Git常用命令 shuo
  • 原文地址:https://www.cnblogs.com/zhanggaofeng/p/5904005.html
Copyright © 2011-2022 走看看