• 批量处理情况下的回射客户端


    前言

      批量处理是指将原先的输入重定向到一个输入文件,这样客户端将连续向服务器发送该文件中的数据,然后接收到服务器的回射数据后,再将其写入到另一个文件中。在这样的情况下,原来的客户端程序不能够再正确运行了。那么会发生什么问题?我们又该如何修改客户端程序才能使之正确工作呢?且看下文。

    发现问题一 传输线路中数据的丢失

      先来看看原客户端中的数据处理函数的一段:

     1 if (FD_ISSET(sockfd, &rset)) {    
     2             if (Readline(sockfd, recvline, MAXLINE) == 0)
     3                 err_quit("str_cli: server terminated prematurely");
     4             Fputs(recvline, stdout);
     5         }
     6 
     7         // 处理用户输入
     8         if (FD_ISSET(fileno(fp), &rset)) { 
     9             if (Fgets(sendline, MAXLINE, fp) == NULL)
    10                 return;        
    11             Writen(sockfd, sendline, strlen(sendline));
    12         }

    可以发现,当用户输入EOF后,该函数会立刻返回到主程序并执行 close() 关闭连接。但现在问题出现了 --- 在批量处理的情况下,此时传输线路中的一部分数据还没有到达客户端。而客户端已经关闭了连接,这部分数据只能被丢弃了。

    解决思路

      在当用户输入EOF后,我们不立刻断开连接,而是只断开连接的写入部分( 使用shutdown函数实现 )。只有当服务器也关闭了服务进程之后,才让客户端关闭连接( 为此需要设置一个标记符 stdioeof )。

    发现问题二 IO异常

      请再看上述代码的第 9 行,在批量情况下,这个输入语句只会从输入文件读取一行数据就返回,而不理会输入缓冲区中剩下的数据。上面第2行代码也是的。而当回到select以后,即使studio缓冲区仍然有数据没被取出。它假定是不知道studio使用了缓冲区,故不会返回文件描述符就绪。

    解决思路

      废弃以文本行为中心的代码,改为针对缓冲区操作。

    客户端str_cli () 函数再修订版

     1 #include    "unp.h"
     2 
     3 void
     4 str_cli(FILE *fp, int sockfd)
     5 {
     6     int            maxfdp1, stdineof;
     7     fd_set        rset;
     8     char        buf[MAXLINE];
     9     int        n;
    10 
    11     stdineof = 0;
    12     FD_ZERO(&rset);
    13     for ( ; ; ) {
    14         // 当客户端输入并没有结束
    15         if (stdineof == 0)
    16             FD_SET(fileno(fp), &rset);
    17         FD_SET(sockfd, &rset);
    18         maxfdp1 = max(fileno(fp), sockfd) + 1;
    19         Select(maxfdp1, &rset, NULL, NULL, NULL);
    20         if (FD_ISSET(sockfd, &rset)) {    
    21             // 注意已经换成了以缓冲区为处理单位的函数,后面的也是。
    22             if ( (n = Read(sockfd, buf, MAXLINE)) == 0) {
    23                 // 当客户端输入结束并且服务器也关闭了服务就正常退出
    24                 if (stdineof == 1)
    25                     return;        
    26                 // 当客户端输入还没结束但服务器已经关闭服务就正常退出
    27                 else
    28                     err_quit("str_cli: server terminated prematurely");
    29             }
    30 
    31             Write(fileno(stdout), buf, n);
    32         }
    33 
    34         if (FD_ISSET(fileno(fp), &rset)) { 
    35             if ( (n = Read(fileno(fp), buf, MAXLINE)) == 0) {
    36                 stdineof = 1;
    37                 // 输入结束的话关闭连接的写部分且清空文件监听描述符,停止对该描述符的监听。
    38                 Shutdown(sockfd, SHUT_WR);    
    39                 FD_CLR(fileno(fp), &rset);
    40                 continue;
    41             }
    42 
    43             Writen(sockfd, buf, n);
    44         }
    45     }
    46 }
  • 相关阅读:
    Filebeat
    kafka 分区 spark excutor task rdd
    Java 方法重写方法重载
    Spark union
    Storm
    pbuilder编译构建工具分析
    TCP的拥塞控制 (四)
    TCP的拥塞控制 (三)
    TCP的拥塞控制 (二)
    TCP的拥塞控制 (一)
  • 原文地址:https://www.cnblogs.com/scut-fm/p/3336252.html
Copyright © 2020-2023  润新知