tsunami 项目通信协议分析

  1 ttp_open_transfer 函数 作用:(主要用来交互一些c/s 两端之间的通信协议)

      服务器端接收客户端发来的所要请求的文件的名字 , 若是成功则返回0 , 否则返回< 0 。

     (1) 服务器首先读取客户端发送来的请求文件名,然后对文件名进行判断,根据文件名的不同采取不同的操作。

             a)  若文件名等于 "!#DIR??"  

                  则表示客户端向 服务器请求了一系列的(已经共享的) 文件名 和 对应文件的大小。

                  于是 首先 server 首先将存储在 parameter结构体中的 total_files (表示文件的个数)传递给client 。

                  然后分别发送parameter结构体中的 file_names  和 file_sizes 。 这就将一些列文件的名字个大小发送给了服务器。

                 最后: 接收客户端发送而来的一个消息,确认客户端已经接收到了上述信息。

 

          b)  若文件名是   "*"

                /*表示客户端请求了多个文件 ,向客户端发送所有的文件的大小,然后是所有文件的个数*/

                  上面的两个变量存储在parameter 结构体中的 file_name_size 和  file_no 中。

                  然后server 接收 client发送过来的一个 message 。

                  下一步 服 务器 依次向 客户端发送 文件名字 。

                   然后server 再次接收 client发送过来的一个 message , 当做反馈。

                   接着 , server 试着 读取客户端发送来的请求一个特定文件的文件名。

 (2)

         进行完上面的判断之后,将得到的文件名,存储在 transfer 结构体中的变量filename ,

         然后调用open函数 打开文件,将文件句柄存储在transfer的 file 变量中。

         如果open函数失败那么就向客户端发送一个 内容为 0x008的 消息。

 

  (3) 开始进行消息传递的估计

           初始化 计时器 ping_s 。

           向client 发送一个内容为000 的消息 。

  (4)  server 端接收 客户端发送来的    block_size     , target_rate , error_rate

   (5) 获得消息传递结束的时间 ping_e

   (6)   server 端接收 client 发来的 关于 speedup 和 slowdown 的一些参数 。

          这些参数包括 :slower_num slower_den  faster_num faster_den

    (7) 得到transfer结构体中的 file_size 参数                     

         fseeko(xfer->file , 0 , SEEK_END) ;
        param->file_size = ftello(xfer->file) ;
        fseeko(xfer->file , 0 , SEEK_SET) ;

        以上3句,用来求出总的文件的大小。

   (8)初始化 parameter结构体中的block_count  以及 epoch 两个变量 。

   (9)将Parameter 变量中的  file_size     block_size  block_count  epoch 传递给客户端 。

   (10) 根据 ping_e ping_s 来初始化 wait_u_sec 。

             然后 wait_u_sec 再增加自身的10% 。

    (11) 然后求出 param->ipd_time , 以及 transfer的 ipd_current 。

    (12)将一些信息写入日志中。        

 

综上 : 这个函数主要是c/s 之间,来初始化parameter 结构体中的一些变量,如 file  file_size , 以及一些file_size , block_size , block_count

             epoch , 以及 wait_u_sec 等等 , 主要是一些消息的头部信息。

             另外还有一点也显示出来作者的牛逼, 就是注意到了套接字设置为阻塞式 和 非阻塞 两种

            在应用TCP协议协商头部信息的时候,使用的是阻塞式 , 而使用udp协议传递文件数据的时候,使用的是非阻塞式 。

 

 

2 下面附上client_handler 函数的剩余代码进行研究

 

   /* while we haven't been told to stop */
    /*直到通知结束的时候,才停止接收*/
    while (1) {

    /* make the client descriptor blocking */
   /*将连接变为阻塞式链接*/
    status = fcntl(session->client_fd, F_SETFL, 0);
    if (status < 0)
        error("Could not make client socket blocking");

    /* negotiate another transfer */
    status = ttp_open_transfer(session);
    if (status < 0) {
        warn("Invalid file request");
        continue;
    }

    /* negotiate a data transfer port */
    status = ttp_open_port(session);
    if (status < 0) {
        warn("UDP socket creation failed");
        continue;
    }

    /* make the client descriptor non-blocking again */
    /*将socket连接变为非阻塞式*/
    status = fcntl(session->client_fd, F_SETFL, O_NONBLOCK);
    if (status < 0)
        error("Could not make client socket non-blocking");

    /*---------------------------
     * START TIMIN
    * 开始计时 
     *---------------------------*/
    gettimeofday(&start, NULL);
    if (param->transcript_yn)
        xscript_data_start(session, &start);

    lasthblostreport       = start;
    lastfeedback           = start;
    prevpacketT            = start;
    deadconnection_counter = 0;
    ipd_time               = 0;
    ipd_time_max           = 0;
    ipd_usleep_diff        = 0;
    retransmitlen          = 0;

    /* start by blasting out every block */
    
    xfer->block = 0;
   /*当当前transfer中的要传递的block index 比 paramter协商中的小,则一直传递*/
    while (xfer->block <= param->block_count) {

        /* default: flag as retransmitted block */
        block_type = TS_BLOCK_RETRANSMISSION;

        /* precalculate time to wait after sending the next packet */
        gettimeofday(&currpacketT, NULL);
        ipd_usleep_diff = xfer->ipd_current + tv_diff_usec(prevpacketT, currpacketT);
        prevpacketT = currpacketT;
        if (ipd_usleep_diff > 0 || ipd_time > 0) {
            ipd_time += ipd_usleep_diff;
        }
        ipd_time_max = (ipd_time > ipd_time_max) ? ipd_time : ipd_time_max;

        /* see if transmit requests are available */
        /*从客户端的retransmission队列中接受一个消息*/
        status = read(session->client_fd, ((char*)&retransmission)+retransmitlen, sizeof(retransmission)-retransmitlen);
        #ifndef VSIB_REALTIME
        if ((status <= 0) && (errno != EAGAIN))
            error("Retransmission read failed");
        #else
        if ((status <= 0) && (errno != EAGAIN) && (!session->parameter->fileout))
            error("Retransmission read failed and not writing local backup file");
        #endif
        if (status > 0)
            retransmitlen += status;

        /* if we have a retransmission */
        /*当我们完整地接收了一个retransmission消息的时候*/
        if (retransmitlen == sizeof(retransmission_t)) {

            /* store current time */
            lastfeedback           = currpacketT;
            lasthblostreport       = currpacketT;
            deadconnection_counter = 0;

            /* if it's a stop request, go back to waiting for a filename */
            if (ntohs(retransmission.request_type) == REQUEST_STOP) {
                fprintf(stderr, "Transmission complete.\n");
                break;
            }

            /* otherwise, handle the retransmission */
            /*执行具体的消息传输操作*/
            status = ttp_accept_retransmit(session, &retransmission, datagram);
            if (status < 0)
                warn("Retransmission error");
            retransmitlen = 0;

        /* if we have no retransmission */
        /*如果当前接收的不是retransmission*/
        } else if (retransmitlen < sizeof(retransmission_t)) {

            /* build the block */
           /*可能是因为transfer中的 block 已经传递到了最后一个*/
            xfer->block = min(xfer->block + 1, param->block_count);
            /*如果传递的是最后一个,那么就将消息类型变为TS_BLOCK_TERMINATE*/
            block_type = (xfer->block == param->block_count) ? TS_BLOCK_TERMINATE : TS_BLOCK_ORIGINAL;
            /*调用build_datagram函数,创建terminate消息*/
            status = build_datagram(session, xfer->block, block_type, datagram);
            if (status < 0) {
                sprintf(g_error, "Could not read block #%u", xfer->block);
                error(g_error);
            }

            /* transmit the block */
            /*发送上面的消息 终止消息 或则 original 消息*/
            status = sendto(xfer->udp_fd, datagram, 6 + param->block_size, 0, xfer->udp_address, xfer->udp_length);
            if (status < 0) {
                sprintf(g_error, "Could not transmit block #%u", xfer->block);
                warn(g_error);
                continue;
            }

        /* if we have too long retransmission message */
          /*如果接收消息的长度大于了transmission 的长度,那么直接报错*/
        } else if (retransmitlen > sizeof(retransmission_t)) {

            fprintf(stderr, "warn: retransmitlen > %d\n", (int)sizeof(retransmission_t));
            retransmitlen = 0;

        }

        /* monitor client heartbeat and disconnect dead client */
        /*统计已经失去连接的client数*/
        if ((deadconnection_counter++) > 2048) {
            char stats_line[160];

            deadconnection_counter = 0;

            /* limit 'heartbeat lost' reports to 500ms intervals */
            if (get_usec_since(&lasthblostreport) < 500000.0) continue;
            gettimeofday(&lasthblostreport, NULL);

            /* throttle IPD with fake 100% loss report */
            #ifndef VSIB_REALTIME
            /*发送REQUEST_ERROR_RATE消息*/
            retransmission.request_type = htons(REQUEST_ERROR_RATE);
            retransmission.error_rate   = htonl(100000);
            retransmission.block = 0;
            ttp_accept_retransmit(session, &retransmission, datagram);
            #endif

            delta = get_usec_since(&lastfeedback);

            /* show an (additional) statistics line */
            snprintf(stats_line, sizeof(stats_line)-1,
                                "   n/a     n/a     n/a %7u %6.2f %3u -- no heartbeat since %3.2fs\n",
                                xfer->block, 100.0 * xfer->block / param->block_count, session->session_id,
                                1e-6*delta);
            if (param->transcript_yn)
               xscript_data_log(session, stats_line);
            fprintf(stderr, "%s", stats_line);

            /* handle timeout for normal file transfers */
            #ifndef VSIB_REALTIME
            if ((1e-6 * delta) > param->hb_timeout) {
                fprintf(stderr, "Heartbeat timeout of %d seconds reached, terminating transfer.\n", param->hb_timeout);
                break;
            }
            #else
            /* handle timeout condition for : realtime with local backup, simple realtime */
            if ((1e-6 * delta) > param->hb_timeout) {
                if ((session->parameter->fileout) && (block_type == TS_BLOCK_TERMINATE)) {
                    fprintf(stderr, "Reached the Terminate block and timed out, terminating transfer.\n");
                    break;
                } else if(!session->parameter->fileout) {
                    fprintf(stderr, "Heartbeat timeout of %d seconds reached and not doing local backup, terminating transfer now.\n", param->hb_timeout);
                    break;
                } else {
                    lastfeedback = currpacketT;
                }
            }
            #endif
        }

         /* wait before handling the next packet */
         if (block_type == TS_BLOCK_TERMINATE) {
             usleep_that_works(10*ipd_time_max);
         }
         if (ipd_time > 0) {
             usleep_that_works(ipd_time);
         }

    }

    /*---------------------------
     * STOP TIMING
      *---------------------------*/
  /*停止计时操作*/
   
    gettimeofday(&stop, NULL);
    if (param->transcript_yn)
        xscript_data_stop(session, &stop);
    delta = 1000000LL * (stop.tv_sec - start.tv_sec) + stop.tv_usec - start.tv_usec;

    /* report on the transfer */
    if (param->verbose_yn)
        fprintf(stderr, "Server %d transferred %llu bytes in %0.2f seconds (%0.1f Mbps)\n",
                session->session_id, (ull_t)param->file_size, delta / 1000000.0, 
                8.0 * param->file_size / (delta * 1e-6 * 1024*1024) );

    /* close the transcript */
    if (param->transcript_yn)
        xscript_close(session, delta);

    #ifndef VSIB_REALTIME

    /* close the file */
    fclose(xfer->file);

    #else

    /* VSIB local disk copy: close file only if file output was requested */
    if (param->fileout) {
        fclose(xfer->file);
    }

    /* stop the VSIB */
    stop_vsib(session);
    fclose(xfer->vsib);

    #endif

    /* close the UDP socket */
    close(xfer->udp_fd);
    memset(xfer, 0, sizeof(*xfer));

    } //while(1)

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

转载于:https://www.cnblogs.com/buptduming/archive/2010/07/07/1772005.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值