lijianweiabcde 发表于 2011-12-23 01:04

有关TCP和UDP 粘包 消息保护边界

<span class="Apple-style-span" style="font-family: arial; line-height: 21px; background-color: rgb(244, 248, 251); "><div id="appShareTitle" style="word-wrap: break-word; height: 24px; line-height: 24px; font-size: 14px; font-weight: bold; color: rgb(51, 51, 51); "><br></div><div id="appShareOpt" style="word-wrap: break-word; text-align: right; margin-bottom: 10px; margin-right: 5px; line-height: 24px; "></div><div id="app-share-content" style="word-wrap: break-word; border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-top-style: solid; border-right-style: solid; border-bottom-style: solid; border-left-style: solid; border-top-color: rgb(237, 241, 244); border-right-color: rgb(237, 241, 244); border-bottom-color: rgb(237, 241, 244); border-left-color: rgb(237, 241, 244); background-image: initial; background-attachment: initial; background-origin: initial; background-clip: initial; background-color: rgb(255, 255, 255); padding-top: 20px; padding-right: 20px; padding-bottom: 20px; padding-left: 20px; color: rgb(154, 154, 154); font-size: 12px; background-position: initial initial; background-repeat: initial initial; ">在socket网络程序中,TCP和UDP分别是面向连接和非面向连接的。因此TCP的socket编程,收发两端(客户端和服务器端)都要有一一成对的socket,因此,发送端为了将多个发往接收端的包,更有效的发到对方,使用了优化方法(Nagle算法),将多次间隔较小且数据量小的数据,合并成一个大的数据块,然后进行封包。这样,接收端,就难于分辨出来了,必须提供科学的拆包机制。<br>对于UDP,不会使用块的合并优化算法,这样,实际上目前认为,是由于UDP支持的是一对多的模式,所以接收端的skbuff(套接字缓冲区)采用了链式结构来记录每一个到达的UDP包,在每个UDP包中就有了消息头(消息来源地址,端口等信息),这样,对于接收端来说,就容易进行区分处理了<br><br>保护消息边界和流<p style="margin-top: 0px; margin-right: 0px; margin-bottom: 1em; margin-left: 0px; color: rgb(109, 109, 109); line-height: 26px; ">那么什么是保护消息边界和流呢?</p><p style="margin-top: 0px; margin-right: 0px; margin-bottom: 1em; margin-left: 0px; color: rgb(109, 109, 109); line-height: 26px; ">保护消息边界,就是指传输协议把数据当作一条独立的消息在网上&nbsp;<br>传输,接收端只能接收独立的消息.也就是说存在保护消息边界,接收&nbsp;<br>端一次只能接收发送端发出的一个数据包.&nbsp;<br>而面向流则是指无保护<strong style="color: black; background-color: rgb(160, 255, 255); ">消息保护边界</strong>的,如果发送端连续发送数据,&nbsp;<br>接收端有可能在一次接收动作中,会接收两个或者更多的数据包.</p><p style="margin-top: 0px; margin-right: 0px; margin-bottom: 1em; margin-left: 0px; color: rgb(109, 109, 109); line-height: 26px; ">我们举个例子来说,例如,我们连续发送三个数据包,大小分别是2k,&nbsp;<br>4k , 8k,这三个数据包,都已经到达了接收端的网络堆栈中,如果使&nbsp;<br>用<strong style="color: black; background-color: rgb(255, 255, 102); ">UDP</strong>协议,不管我们使用多大的接收缓冲区去接收数据,我们必须有&nbsp;<br>三次接收动作,才能够把所有的数据包接收完.而使用TCP协议,我们&nbsp;<br>只要把接收的缓冲区大小设置在14k以上,我们就能够一次把所有的&nbsp;<br>数据包接收下来.只需要有一次接收动作.</p><p style="margin-top: 0px; margin-right: 0px; margin-bottom: 1em; margin-left: 0px; color: rgb(109, 109, 109); line-height: 26px; ">这就是因为<strong style="color: black; background-color: rgb(255, 255, 102); ">UDP</strong>协议的保护消息边界使得每一个消息都是独立的.而&nbsp;<br>流传输,却把数据当作一串数据流,他不认为数据是一个一个的消息.</p><p style="margin-top: 0px; margin-right: 0px; margin-bottom: 1em; margin-left: 0px; color: rgb(109, 109, 109); line-height: 26px; ">所以有很多人在使用tcp协议通讯的时候,并不清楚tcp是基于流的&nbsp;<br>传输,当连续发送数据的时候,他们时常会认识tcp会丢包.其实不然,&nbsp;<br>因为当他们使用的缓冲区足够大时,他们有可能会一次接收到两个甚&nbsp;<br>至更多的数据包,而很多人往往会忽视这一点,只解析检查了第一个&nbsp;<br>数据包,而已经接收的其他数据包却被忽略了.所以大家如果要作这&nbsp;<br>类的网络编程的时候,必须要注意这一点.</p>结论:<br>根据以上所说,可以这样理解,TCP为了保证可靠传输,尽量减少额外<br>开销(每次发包都要验证),因此采用了流式传输,面向流的传输,<br>相对于面向消息的传输,可以减少发送包的数量。从而减少了额外开<br>销。但是,对于数据传输频繁的程序来讲,使用TCP可能会容易粘包。<br>当然,对接收端的程序来讲,如果机器负荷很重,也会在接收缓冲里<br>粘包。这样,就需要接收端额外拆包,增加了工作量。因此,这个特<br>别适合的是数据要求可靠传输,但是不需要太频繁传输的场合(<br>两次操作间隔100ms,具体是由TCP等待发送间隔决定的,取决于内核<br>中的socket的写法)<br><br>而UDP,由于面向的是消息传输,它把所有接收到的消息都挂接到缓冲<br>区的接受队列中,因此,它对于数据的提取分离就更加方便,但是,<br>它没有粘包机制,因此,当发送数据量较小的时候,就会发生数据包<br>有效载荷较小的情况,也会增加多次发送的系统发送开销(系统调用,<br>写硬件等)和接收开销。因此,应该最好设置一个比较合适的数据包<br>的包长,来进行UDP数据的发送。(UDP最大载荷为1472,因此最好能<br>每次传输接近这个数的数据量,这特别适合于视频,音频等大块数据<br>的发送,同时,通过减少握手来保证流媒体的实时性)</div></span>
页: [1]
查看完整版本: 有关TCP和UDP 粘包 消息保护边界