Unix网络编程服务器设计方式之三

来源:互联网 发布:帝国cms 数据备份目录 编辑:程序博客网 时间:2024/05/20 00:15

通过Select函数实现并发

select函数允许进程指示内核等待多个事件中的任何一个发生,并只在有一个或多个事件发生或经历一段时间后唤醒它。这样我们就可以利用select函数同时监控多个连接,并且维护一个客户端连接数组用来存储连接描述符。当有客户端连接进来后,把连接符加入到此数组中,同时让select函数监控此连接述符,当有文件描述符准备好后select返回,然后轮循连接数组,判断是那个连接符已经准备好,调用客户请求处理函数,执行完成后将连接数据对应的值清空,并且将连接符从select中清除,将连接关闭。这种方法比较适合小量的并发连接。

 

例子:回射服务器,即服务器端接收客户端来的数据,并将数据原样返回给客户端,代码在CentOS5.0测试通过

服务器端代码:

#include <stdio.h>

#include <sys/socket.h>

#include <sys/types.h>

#include <netinet/in.h>

#include <sys/time.h>

#include <sys/select.h>

#include <strings.h>

 

#define SERV_PORT 2003

#define MAXLINE 1024

#define LISTENQ 4

 

int makeListenByPort(short port)

{

   int listenfd;

   struct sockaddr_in servaddr;

 

   listenfd = socket(AF_INET, SOCK_STREAM, 0);

 

   bzero(&servaddr, sizeof(servaddr));

   servaddr.sin_family = AF_INET;

   servaddr.sin_addr.s_addr = htonl(INADDR_ANY);

   servaddr.sin_port = htons(port);

 

   bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr));

 

   listen(listenfd, LISTENQ);

 

   return listenfd;

}

 

int main(int argc, char **argv)

{

   int listenfd, connfd, maxfd, sockfd;

   int client[FD_SETSIZE], nready;

   int maxi;

   unsigned int clilen;

   ssize_t n;

   char buf[MAXLINE];

   struct sockaddr_in cliaddr;

    inti;

   fd_set rset, allset;

 

   listenfd = makeListenByPort(SERV_PORT);

 

   maxfd = listenfd;

   maxi = -1;

   for(i = 0; i < FD_SETSIZE; i++) {

       client[i] = -1;

    }

   FD_ZERO(&allset);

   FD_SET(listenfd, &allset);

 

   for(;;) {

       rset = allset;

       /* select系统调用 */

       nready = select(maxfd+1, &rset, NULL, NULL, NULL);

 

       /* 监控是否有新的连接 */

       if(FD_ISSET(listenfd, &rset)) {

           clilen = sizeof(cliaddr);

           connfd = accept(listenfd, (struct sockaddr *)&cliaddr, &clilen);

 

           for(i = 0; i < FD_SETSIZE; i++) {

                if(client[i] < 0) {

                    client[i] = connfd;

                    break;

                }

           }

           if(i == FD_SETSIZE) {

               printf("too manyclients\n");

                continue;

           }

           FD_SET(connfd, &allset);

           if(connfd > maxfd) maxfd = connfd;

           /* 维护客户端的个数 */

           if(i > maxi) maxi = i;

 

           if(--nready <= 0) continue;

       }

       /* 轮循所有的客户端连接符 */

       for(i = 0; i <= maxi; i++) {

           if((sockfd = client[i]) < 0)

                continue;

           if(FD_ISSET(sockfd, &rset)) {

                /* 如果有数据可读,则将读到的数据回写,否则清理连接 */

               if((n = read(sockfd, buf,MAXLINE)) == 0) {

                    close(sockfd);

                    FD_CLR(sockfd,&allset);

                    client[i] = -1;

                } else {

                   write(sockfd, buf, n);

                }

               if(--nready <= 0)break;

           }

       }

    }

}

 

客户端代码:

#include <stdio.h>

#include <stdlib.h>

#include <sys/socket.h>

#include <sys/types.h>

#include <netinet/in.h>

#include <strings.h>

#include <string.h>

 

#define MAXLINE 1024

#define SERV_PORT 2003

 

void cli_str(FILE *fp, int sockfd)

{

   char sendline[MAXLINE];

   char recvline[MAXLINE];

 

   memset(recvline, 0x00, sizeof(recvline));

   memset(sendline, 0x00, sizeof(sendline));

   printf("cli#");

   while((fgets(sendline, MAXLINE, fp)) != NULL) {

       write(sockfd, sendline, strlen(sendline));

       if(read(sockfd, recvline, MAXLINE) == 0) {

           printf("str_cli:server terminated prematurely\n");

           exit(0);

       }

       fputs(recvline, stdout);

       fflush(stdout);

       memset(recvline, 0x00, sizeof(recvline));

       printf("cli#");

    }

}

 

int main(int argc, char **argv)

{

   int sockfd;

   struct sockaddr_in servaddr;

 

   if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {

       printf("socket error\n");

       exit(0);

    }

 

   bzero(&servaddr, sizeof(servaddr));

   servaddr.sin_family = AF_INET;

   inet_pton(AF_INET, argv[1], &servaddr.sin_addr);

   servaddr.sin_port = htons(SERV_PORT);

   if((connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)))== -1) {

       printf("connect error\n");

       exit(0);

    }

 

   cli_str(stdin, sockfd);

   exit(0);

}

原创粉丝点击