Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2226648
  • 博文数量: 556
  • 博客积分: 11457
  • 博客等级: 上将
  • 技术积分: 5973
  • 用 户 组: 普通用户
  • 注册时间: 2011-02-24 22:33
文章分类

全部博文(556)

文章存档

2013年(22)

2012年(74)

2011年(460)

分类: 系统运维

2012-04-19 22:42:19

       基于I/O复用的TCP回射客户-服务器程序设计

一、实验目的

1. 理解五种I/O模型及其区别。

2. 掌握I/O复用模型,掌握selectpoll函数的使用方法。

二、实验内容

1. 分别使用selectpoll函数编写TCP回射服务器程序。

2. 使用select函数编写TCP回射客户程序。

三、实验步骤

1. 搭建网络编程实验环境

按照《网络编程实验环境搭建》进行。

2.编写基于I/O复用的TCP程序

1)打开终端窗口,建立一个文件夹,假如文件夹的名称是tcpdemo,可使用命令mkdir tcpdemo进行。

2)进入tcpdemo文件夹(cd tcpdemo),使用vi编辑器编写

²  编写服务器端程序:

n  使用select函数编写TCP回射服务器程序

点击(此处)折叠或打开

  1. #include    "unp.h"
  2. int
  3. main(int argc, char **argv)
  4. {
  5.     int                    i, maxi, maxfd, listenfd, connfd, sockfd;
  6.     int                    nready, client[FD_SETSIZE];
  7.     ssize_t                n;
  8.     fd_set                rset, allset;
  9.     char                buf[MAXLINE];
  10.     socklen_t            clilen;
  11.     struct sockaddr_in    cliaddr, servaddr;
  12.     listenfd = Socket(AF_INET, SOCK_STREAM, 0);
  13.     bzero(&servaddr, sizeof(servaddr));
  14.     servaddr.sin_family = AF_INET;
  15.     servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
  16.     servaddr.sin_port = htons(SERV_PORT);
  17.     Bind(listenfd, (SA *) &servaddr, sizeof(servaddr));
  18.     Listen(listenfd, LISTENQ);
  19.     maxfd = listenfd;            /* initialize */
  20.     maxi = -1;                    /* index into client[] array */
  21.     for (i = 0; i < FD_SETSIZE; i++)
  22.         client[i] = -1;            /* -1 indicates available entry */
  23.     FD_ZERO(&allset);
  24.     FD_SET(listenfd, &allset);
  25. /* end fig01 */
  26. /* include fig02 */
  27.     for ( ; ; ) {
  28.         rset = allset;        /* structure assignment */
  29.         nready = Select(maxfd+1, &rset, NULL, NULL, NULL);
  30.         if (FD_ISSET(listenfd, &rset)) {    /* new client connection */
  31.             clilen = sizeof(cliaddr);
  32.             connfd = Accept(listenfd, (SA *) &cliaddr, &clilen);
  33. #ifdef    NOTDEF
  34.             printf("new client: %s, port %d\n",
  35.                     Inet_ntop(AF_INET, &cliaddr.sin_addr, 4, NULL),
  36.                     ntohs(cliaddr.sin_port));
  37. #endif
  38.             for (i = 0; i < FD_SETSIZE; i++)
  39.                 if (client[i] < 0) {
  40.                     client[i] = connfd;    /* save descriptor */
  41.                     break;
  42.                 }
  43.             if (i == FD_SETSIZE)
  44.                 err_quit("too many clients");
  45.             FD_SET(connfd, &allset);    /* add new descriptor to set */
  46.             if (connfd > maxfd)
  47.                 maxfd = connfd;            /* for select */
  48.             if (i > maxi)
  49.                 maxi = i;                /* max index in client[] array */
  50.             if (--nready <= 0)
  51.                 continue;                /* no more readable descriptors */
  52.         }
  53.         for (i = 0; i <= maxi; i++) {    /* check all clients for data */
  54.             if ( (sockfd = client[i]) < 0)
  55.                 continue;
  56.             if (FD_ISSET(sockfd, &rset)) {
  57.                 if ( (n = Read(sockfd, buf, MAXLINE)) == 0) {
  58.                         /*4connection closed by client */
  59.                     Close(sockfd);
  60.                     FD_CLR(sockfd, &allset);
  61.                     client[i] = -1;
  62.                 } else
  63.                     Writen(sockfd, buf, n);
  64.                 if (--nready <= 0)
  65.                     break;                /* no more readable descriptors */
  66.             }
  67.         }
  68.     }
  69. }

n  使用poll函数编写TCP回射服务器程序


 

点击(此处)折叠或打开

  1. /* include fig01 */
  2. #include    "unp.h"
  3. #include    <limits.h>        /* for OPEN_MAX */
  4. #define OPEN_MAX 32
  5. #define POLLRDNORM 0x040
  6. int
  7. main(int argc, char **argv)
  8. {
  9.     int                    i, maxi, listenfd, connfd, sockfd;
  10.     int                    nready;
  11.     ssize_t                n;
  12.     char                buf[MAXLINE];
  13.     socklen_t            clilen;
  14.     struct pollfd        client[OPEN_MAX];
  15.     struct sockaddr_in    cliaddr, servaddr;

  16.     listenfd = Socket(AF_INET, SOCK_STREAM, 0);

  17.     bzero(&servaddr, sizeof(servaddr));
  18.     servaddr.sin_family = AF_INET;
  19.     servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
  20.     servaddr.sin_port = htons(SERV_PORT);

  21.     Bind(listenfd, (SA *) &servaddr, sizeof(servaddr));

  22.     Listen(listenfd, LISTENQ);

  23.     client[0].fd = listenfd;
  24.     client[0].events = POLLRDNORM;
  25.     for (i = 1; i < OPEN_MAX; i++)
  26.         client[i].fd = -1;        /* -1 indicates available entry */
  27.     maxi = 0;                    /* max index into client[] array */
  28. /* end fig01 */

  29. /* include fig02 */
  30.     for ( ; ; ) {
  31.         nready = Poll(client, maxi+1, INFTIM);

  32.         if (client[0].revents & POLLRDNORM) {    /* new client connection */
  33.             clilen = sizeof(cliaddr);
  34.             connfd = Accept(listenfd, (SA *) &cliaddr, &clilen);
  35. #ifdef    NOTDEF
  36.             printf("new client: %s\n", Sock_ntop((SA *) &cliaddr, clilen));
  37. #endif

  38.             for (i = 1; i < OPEN_MAX; i++)
  39.                 if (client[i].fd < 0) {
  40.                     client[i].fd = connfd;    /* save descriptor */
  41.                     break;
  42.                 }
  43.             if (i == OPEN_MAX)
  44.                 err_quit("too many clients");

  45.             client[i].events = POLLRDNORM;
  46.             if (i > maxi)
  47.                 maxi = i;                /* max index in client[] array */

  48.             if (--nready <= 0)
  49.                 continue;                /* no more readable descriptors */
  50.         }

  51.         for (i = 1; i <= maxi; i++) {    /* check all clients for data */
  52.             if ( (sockfd = client[i].fd) < 0)
  53.                 continue;
  54.             if (client[i].revents & (POLLRDNORM | POLLERR)) {
  55.                 if ( (n = read(sockfd, buf, MAXLINE)) < 0) {
  56.                     if (errno == ECONNRESET) {
  57.                             /*4connection reset by client */
  58. #ifdef    NOTDEF
  59.                         printf("client[%d] aborted connection\n", i);
  60. #endif
  61.                         Close(sockfd);
  62.                         client[i].fd = -1;
  63.                     } else
  64.                         err_sys("read error");
  65.                 } else if (n == 0) {
  66.                         /*4connection closed by client */
  67. #ifdef    NOTDEF
  68.                     printf("client[%d] closed connection\n", i);
  69. #endif
  70.                     Close(sockfd);
  71.                     client[i].fd = -1;
  72.                 } else
  73.                     Writen(sockfd, buf, n);

  74.                 if (--nready <= 0)
  75.                     break;                /* no more readable descriptors */
  76.             }
  77.         }
  78.     }
  79. }

²  编写客户端程序


 

点击(此处)折叠或打开

  1. #include    "unp.h"
  2. void
  3. str_cli(FILE *fp, int sockfd)
  4. {
  5.     int            maxfdp1, stdineof;
  6.     fd_set        rset;
  7.     char        buf[MAXLINE];
  8.     int        n;
  9.     stdineof = 0;
  10.     FD_ZERO(&rset);
  11.     for ( ; ; ) {
  12.         if (stdineof == 0)
  13.             FD_SET(fileno(fp), &rset);
  14.         FD_SET(sockfd, &rset);
  15.         maxfdp1 = max(fileno(fp), sockfd) + 1;
  16.         Select(maxfdp1, &rset, NULL, NULL, NULL);

  17.         if (FD_ISSET(sockfd, &rset)) {    /* socket is readable */
  18.             if ( (n = Read(sockfd, buf, MAXLINE)) == 0) {
  19.                 if (stdineof == 1)
  20.                     return;        /* normal termination */
  21.                 else
  22.                     err_quit("str_cli: server terminated prematurely");
  23.             }
  24.             Write(fileno(stdout), buf, n);
  25.         }
  26.         if (FD_ISSET(fileno(fp), &rset)) { /* input is readable */
  27.             if ( (n = Read(fileno(fp), buf, MAXLINE)) == 0) {
  28.                 stdineof = 1;
  29.                 Shutdown(sockfd, SHUT_WR);    /* send FIN */
  30.                 FD_CLR(fileno(fp), &rset);
  31.                 continue;
  32.             }
  33.             Writen(sockfd, buf, n);
  34.         }
  35.     }
  36. }
tcpcli01.c

点击(此处)折叠或打开

  1. #include    "unp.h"
  2. int
  3. main(int argc, char **argv)
  4. {
  5.     int                    sockfd;
  6.     struct sockaddr_in    servaddr;
  7.     if (argc != 2)
  8.         err_quit("usage: tcpcli ");
  9.     sockfd = Socket(AF_INET, SOCK_STREAM, 0);
  10.     bzero(&servaddr, sizeof(servaddr));
  11.     servaddr.sin_family = AF_INET;
  12.     servaddr.sin_port = htons(SERV_PORT);
  13.     Inet_pton(AF_INET, argv[1], &servaddr.sin_addr);
  14.     Connect(sockfd, (SA *) &servaddr, sizeof(servaddr));
  15.     str_cli(stdin, sockfd);        /* do it all */
  16.     exit(0);
  17. }

实验结果:

在客户端输入aaa,然后回显aaa

四 实验总结

通过本次实验,了解了I/O复用:selectpoll函数,有了I/O复用,我们就可以调用selectpoll,在这两个系统调用中的某一个上阻塞,而不是阻塞于真正的I/O系统调用。I/O复用模型最常用的函数时select,因此对select函数的掌握对于I/O复用的学习是有很大的帮助。通过本次实验的学习,强化了TCP客户-服务器程序的基本框架,使我真正明白了客户端和服务器直接回射的机理,熟悉了Ubuntu,同时对网络底层的一些运行原理有了很好的理解及掌握。

参考资料:《Unix网络编程》

 

阅读(2554) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~