首页 > 代码库 > Linux 网络编程九(select应用--大并发处理)

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 1024int main(int arg, char *args[]){    if (arg < 2)    {        printf("please print one param!\n");        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\n", strerror(errno));            break;        }        //判断是否是服务器socket接收到数据,有客户端连接        if (FD_ISSET(listen_st, &allset))        {            //accept            int client_st = server_accept(listen_st);            if (client_st < 0)            {                //继续等待下次客户端连接                continue;            }            //客户端连接成功 设置客户端非阻塞            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;}

 

Linux 网络编程九(select应用--大并发处理)