Linux网络编程:TCP服务器(单进程多用户),使用

Linux下的单进程多用户TCP服务器,采用select方法实现。

/*************************************************  * File name   : server.c  * Description : 单进程并发服务器  * Author      : sg131971@qq.com  * Version     : V1.0  * Date        :   * Compiler    : arm-linux-gcc-4.4.3  * Target      : mini2440(Linux-2.6.32)  * History     :   *   <author>  <time>   <version >   <desc>  *************************************************/   #include <stdio.h>    #include <string.h>    #include <unistd.h>    #include <sys/types.h>    #include <sys/socket.h>    #include <netinet/in.h>    #include <arpa/inet.h>    #include <sys/time.h>    #include <stdlib.h>       #define PORT 1234               //服务器端口    #define BACKLOG 5               //listen队列中等待的连接数    #define MAXDATASIZE 1024        //缓冲区大小       typedef struct _CLIENT   {       int fd;                     //客户端socket描述符        char name[20];              //客户端名称        struct sockaddr_in addr;    //客户端地址信息结构体        char data[MAXDATASIZE];     //客户端私有数据指针    } CLIENT;      void process_client(CLIENT * client, char *recvbuf, int len);   //客户请求处理函数       /*************************************************  * Function    : main()  * Description :   * Calls       : process_client()  * Called By   :   * Input       :   * Output      :   * Return      :   *************************************************/   void main(int argc ,char **argv)   {       int i, maxi, maxfd, sockfd;       int nready;       ssize_t n;       fd_set rset, allset;        //select所需的文件描述符集合        int listenfd, connectfd;    //socket文件描述符        struct sockaddr_in server;  //服务器地址信息结构体           CLIENT client[FD_SETSIZE];  //FD_SETSIZE为select函数支持的最大描述符个数        char recvbuf[MAXDATASIZE];  //缓冲区        int sin_size;               //地址信息结构体大小           if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)       {                           //调用socket创建用于监听客户端的socket            perror("Creating socket failed.");           exit(1);       }          int opt = SO_REUSEADDR;       setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));  //设置socket属性           bzero(&server, sizeof(server));       server.sin_family = AF_INET;       server.sin_port = htons(PORT);       server.sin_addr.s_addr = htonl(INADDR_ANY);          if (bind(listenfd, (struct sockaddr *)&server, sizeof(struct sockaddr)) == -1)       {                           //调用bind绑定地址            perror("Bind error.");           exit(1);       }          if (listen(listenfd, BACKLOG) == -1)       {                           //调用listen开始监听            perror("listen() error\n");           exit(1);       }          //初始化select        maxfd = listenfd;       maxi = -1;       for (i = 0; i < FD_SETSIZE; i++)       {           client[i].fd = -1;       }       FD_ZERO(&allset);           //清空        FD_SET(listenfd, &allset);  //将监听socket加入select检测的描述符集合           while (1)       {           struct sockaddr_in addr;           rset = allset;           nready = select(maxfd + 1, &rset, NULL, NULL, NULL);    //调用select            printf("Select() break and the return num is %d. \n", nready);              if (FD_ISSET(listenfd, &rset))           {                       //检测是否有新客户端请求                printf("Accept a connection.\n");               //调用accept,返回服务器与客户端连接的socket描述符                sin_size = sizeof(struct sockaddr_in);               if ((connectfd =                    accept(listenfd, (struct sockaddr *)&addr, (socklen_t *) & sin_size)) == -1)               {                   perror("Accept() error\n");                   continue;               }                  //将新客户端的加入数组                for (i = 0; i < FD_SETSIZE; i++)               {                   if (client[i].fd < 0)                   {                       char buffer[20];                       client[i].fd = connectfd;   //保存客户端描述符                        memset(buffer, '0'sizeof(buffer));                       sprintf(buffer, "Client[%.2d]", i);                       memcpy(client[i].name, buffer, strlen(buffer));                       client[i].addr = addr;                       memset(buffer, '0'sizeof(buffer));                       sprintf(buffer, "Only For Test!");                       memcpy(client[i].data, buffer, strlen(buffer));                       printf("You got a connection from %s:%d.\n", inet_ntoa(client[i].addr.sin_addr),ntohs(client[i].addr.sin_port));                       printf("Add a new connection:%s\n",client[i].name);                       break;                   }               }                              if (i == FD_SETSIZE)                   printf("Too many clients\n");               FD_SET(connectfd, &allset); //将新socket连接放入select监听集合                if (connectfd > maxfd)                   maxfd = connectfd;  //确认maxfd是最大描述符                if (i > maxi)       //数组最大元素值                    maxi = i;               if (--nready <= 0)                   continue;       //如果没有新客户端连接,继续循环            }              for (i = 0; i <= maxi; i++)           {               if ((sockfd = client[i].fd) < 0)    //如果客户端描述符小于0,则没有客户端连接,检测下一个                    continue;               // 有客户连接,检测是否有数据                if (FD_ISSET(sockfd, &rset))               {                   printf("Receive from connect fd[%d].\n", i);                   if ((n = recv(sockfd, recvbuf, MAXDATASIZE, 0)) == 0)                   {               //从客户端socket读数据,等于0表示网络中断                        close(sockfd);  //关闭socket连接                        printf("%s closed. User's data: %s\n", client[i].name, client[i].data);                       FD_CLR(sockfd, &allset);    //从监听集合中删除此socket连接                        client[i].fd = -1;  //数组元素设初始值,表示没客户端连接                    }                   else                       process_client(&client[i], recvbuf, n); //接收到客户数据,开始处理                    if (--nready <= 0)                       break;      //如果没有新客户端有数据,跳出for循环回到while循环                }           }       }       close(listenfd);            //关闭服务器监听socket         }      /*************************************************  * Function    : process_client()  * Description : 处理客户端连接函数  * Calls       :   * Called By   : main()  * Input       :   * Output      :   * Return      :   *************************************************/   void process_client(CLIENT * client, char *recvbuf, int len)   {       char sendbuf[MAXDATASIZE];       int i;          printf("Received client( %s ) message: %s\n", client->name, recvbuf);             for (i = 0; i < len - 1; i++)       {           sendbuf[i] = recvbuf[len - i - 2];       }              sendbuf[len - 1] = '\0';          send(client->fd, sendbuf, strlen(sendbuf), 0);   }  

测试结果:

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wwgsjg.html