构造多协议服务器

来源:互联网 发布:windows pe 硬盘版 编辑:程序博客网 时间:2024/06/06 05:21

这次我们讨论多协议服务器

设计初衷:

每种协议使用一个服务器会使代码重复,另外,UDPTCP都是用相同的基本算法来计算响应,他们都包含执行计算所需要的代码,这样的话管理程序就变得冗长和乏味。

设计:

一个多协议服务器由一个单执行线程构成,这个线程既可以在TCP也可以在UDP上使用异步I/O来处理通信。服务器最初打开2个套接字,一个UDP,一个TCP。接着服务器使用异步I/O等待两个套接字之一就绪。如果TCPsocket就绪,说明是一个TCP连接,使用accept获得新的连接,并在这个链接上与客户通信。如果UDPsocket就绪,说明客户以UDP数据报形式发来一个请求。服务器就用recvfrom读取该请求,并记录此发送者的端点地址。当服务器计算出响应后,就调用sendto将响应发回给客户。

进程结构:

代码:

extern int      errno;

 

int   daytime(char buf[]);

int   errexit(const char *format, ...);

int   passiveTCP(const char *service, int qlen);

int   passiveUDP(const char *service);

 

#define  MAX(x, y)      ((x) > (y) ? (x) : (y))

 

#define  QLEN             32

 

#define  LINELEN        128

 

/*------------------------------------------------------------------------

 * main - Iterative server for DAYTIME service

 *------------------------------------------------------------------------

 */

int

main(int argc, char *argv[])

{

       char       *service = "daytime";  /* service name or port number       */

       char       buf[LINELEN+1];         /* buffer for one line of text       */

       struct sockaddr_in fsin;      /* the request from address      */

       unsigned int   alen;              /* from-address length              */

       int   tsock;                  /* TCP master socket         */

       int   usock;                  /* UDP socket                    */

       int   nfds;

       fd_set     rfds;                     /* readable file de  script  ors  */

 

       switch (argc) {

       case       1:

              break;

       case       2:

              service = argv[1];

              break;

       default:

              errexit("usage: daytimed [port]/n");

       }

 

       tsock = passiveTCP(service, QLEN);

       usock = passiveUDP(service);

服务器创建主套接字后,便准备使用select,以便等待其中之一或两者同时I/O准备就绪。首先,他把变量nfds设置为两个套接字中较大的那个,以此作为描述符比特屏蔽码的索引,他还把比特屏蔽码(遍历那个rfds)清零。接着,服务器进入一个无限循环之中。在每次循环中,使用宏FD_SET构造比特屏蔽码,其置1的比特对应于两个主套接字的描述符。接着使用select等待这二者之一的输入激活。

       nfds = MAX(tsock, usock) + 1;  /* bit number of max fd     */

 

       FD_ZERO(&rfds);

 

       while (1) {

              FD_SET(tsock, &rfds);

              FD_SET(usock, &rfds);

              if (select(nfds, &rfds, (fd_set *)0, (fd_set *)0,

                            (struct timeval *)0) < 0)

                     errexit("select error: %s/n", strerror(errno));

              if (FD_ISSET(tsock, &rfds)) {

                     int   ssock;           /* TCP slave socket     */

 

                     alen = sizeof(fsin);

                     ssock = accept(tsock, (struct sockaddr *)&fsin,

                            &alen);

                     if (ssock < 0)

                            errexit("accept failed: %s/n",

                                          strerror(errno));

                     daytime(buf);

                     (void) write(ssock, buf, strlen(buf));

                     (void) close(ssock);

              }

              if (FD_ISSET(usock, &rfds)) {

                     alen = sizeof(fsin);

                     if (recvfrom(usock, buf, sizeof(buf), 0,

                            (struct sockaddr *)&fsin, &alen) < 0)

                            errexit("recvfrom: %s/n",

                                   strerror(errno));

                     daytime(buf);

                     (void) sendto(usock, buf, strlen(buf), 0,

                            (struct sockaddr *)&fsin, sizeof(fsin));

              }

       }

}

这段代码很简单,他们都是用单线程来解决并发问题,基本上就是循环的无连接服务器+循环的面向连接的服务器的集合版本。

这里有个小的调整就是daytime函数,因为他要既要适合tcp也要适合udp,由于udp是不用write函数,而是拿到了数据之后直接sendto,而tcp拿到数据之后先要write然后再关闭连接,所以daytime函数的设计更显得一般化。Time函数返回一个时间。

/*------------------------------------------------------------------------

 * daytime - fill the given buffer with the time of day

 *------------------------------------------------------------------------

 */

int

daytime(char buf[])

{

       char       *ctime();

       time_t    now;

 

       (void) time(&now);

       sprintf(buf, "%s", ctime(&now));

}

原创粉丝点击