TCP的流模式与UDP的报文模式对比

1       案例背景

在学习TCP-IP协议详解卷一时,读到介绍TCP协议的部分,发现TCP的首部是没有报文总长度字段的,而在UDP中是有的,对这个问题的思考引出了两者之间的区别。

2    案例分析

TCP报文的格式:

 

TCP首部的格式:

 

UDP报文的格式:

 

UDP首部的格式:

 

针对首部公共部分的对比,很明显的一个区别是UDP首部是有数据报总长度字段的,而TCP首部是没有数据报总长度字段的,这个原因的解释在TCP-IP详解卷一答案中的解释是TCP首部有选项字段而UDP首部大小是固定的,而网上的查询结果有一种是因为模式的不同。

我比较赞同的是,TCP是面向连接的流模式,而UDP是不连接的数据报模式。

3       实验

实验一:

       TCP客户端循环发送数据到服务器,主循环部分分三次调用send或者sendto,分别发送111,222,333;而服务器是睡眠十秒,然后调用recv或者recvfrom接收数据。注意,只接收一次。

客户端发送部分(其中的sendto可用send代替):

    while(1)

       {

              memset(achBuf,0,1024);

              memcpy(achBuf,"111",3);

        buflen = strlen(achBuf);

              ret = sendto(nSockFd,achBuf,buflen,0,(struct sockaddr*)&ServAddr,sizeof(ServAddr));

              memset(achBuf,0,1024);

              memcpy(achBuf,"222",3);

        buflen = strlen(achBuf);

           ret = sendto(nSockFd,achBuf,buflen,0,(struct sockaddr*)&ServAddr,sizeof(ServAddr));

              memset(achBuf,0,1024);

              memcpy(achBuf,"333",3);

        buflen = strlen(achBuf);

           ret = sendto(nSockFd,achBuf,buflen,0,(struct sockaddr*)&ServAddr,sizeof(ServAddr));

}

服务器接收部分(其中的recv可用recvfrom代替):

       sleep(10);

       recv(conn,buf,1024,0);

       printf("conn = %s\n",buf);

四种不同的发送接收组合,均是以下结果:

 

实验二:

UDP客户端循环发送数据到服务器,分三次调用sendto,分别发送了111,222,333;服务器睡眠十秒,然后调用recvfrom循环接收数据。为了表示是第几次接收到的数据,首先打印接收序号。

客户端发送部分:

       nNum = sendto(nSockFd,"111\n", 12, 0, (struct sockaddr *)&MCAddr,sizeof(MCAddr));

    printf("nNum = %d\n",nNum);

       nNum = sendto(nSockFd,"222\n", 12, 0, (struct sockaddr *)&MCAddr,sizeof(MCAddr));

    printf("nNum = %d\n",nNum);   

       nNum = sendto(nSockFd,"333\n", 12, 0, (struct sockaddr *)&MCAddr,sizeof(MCAddr));

    printf("nNum = %d\n",nNum);

服务器接收部分:

       while(1)

       {

              sleep(10);

              memset(achBuf,0,MAXBUFLEN);

              nNum = recvfrom(nServFd,achBuf,MAXBUFLEN,0,(struct sockaddr *)&CliAddr, &dwCliAddrLen);

             

              if(nNum < 0)

              {

                     printf("recverror\n");

                     break;    

              }

              printf("%d\n",i);i++;

              printf("%s\n",achBuf);

       }

结果如下图:

 

4       总结

由实验结果可以知道,读取数据的方式和调用的函数没有关系,而和套接字类型有关。而TCP接收数据时不是一次只读取一个数据报,而是根据buf的大小和缓冲区数据的大小中的较小值来读取数据的,可以一次性读取多个数据报;而UDP是按照接收到的数据次序,一次只读取一个数据报。

现在可以大概的推敲出流模式和数据报模式的区别,接收和发送数据方式的不同。流模式只要不超过流的容量就可以继续往流上提交数据,另一端只要流上有数据就可以读取,而不管这个数据的开头和结尾;数据报模式,有严格的次序关系和数据报的分割关系。而这两种的不同大概是由于TCP一个套接字只接收来自一个对象的数据,而UDP套接字可以接收来自任意对象的数据。

两者在模式上的不同,导致两者在效率和应用模式上的不同。

在每个数据都要分析的情况下,例如发送一条配置命令,TCP必须约定消息头格式指出这条消息的大小,而UDP不需要。而在流媒体数据上,由于TCP有数据重组的特性,效率相对UDP更高。

posted @ 2015-10-09 10:25  __sipl  阅读(3966)  评论(0编辑  收藏  举报