tcpip協(xié)議使用"流式"(套接字)進(jìn)行數(shù)據(jù)的傳輸,就是說它保證數(shù)據(jù)的可達(dá)以及數(shù)據(jù)抵達(dá)的順序,但并不保證數(shù)據(jù)是否在你接收的時(shí)候就到達(dá),特別是為了提高效率,充分利用帶寬,底層會使用緩存技術(shù),具體的說就是使用Nagle算法將小的數(shù)據(jù)包放到一起發(fā)送,但是這樣也帶來一個(gè)使用上的問題——黏包,黏包就是說一次將多個(gè)數(shù)據(jù)包發(fā)送出去,導(dǎo)致接收方不能進(jìn)行正常的解析,示意圖如下:
發(fā)生黏包一般有兩種原因,一種是發(fā)送方進(jìn)行了不該緩沖的緩沖,比如上圖中,收發(fā)雙方協(xié)議好按照一定的規(guī)則進(jìn)行編寫/解析報(bào)文,但是由于Nagle算法,可能出現(xiàn)發(fā)送方一次發(fā)送了1.5個(gè)數(shù)據(jù)包,而接收方只解析了前面的1個(gè)包,后面的0.5個(gè)由于數(shù)據(jù)不完整而解析失敗,造成數(shù)據(jù)的丟失或錯(cuò)位,很可能會影響之后所有的數(shù)據(jù)解析工作。由于發(fā)送方導(dǎo)致的黏包問題可以使用setsockopt()
來解決
int enable=1;setsockopt(sockfd,IPROTO_TCP,TCP_NODELAY,(void*)&enable,sizeof(enable))
這條指令可以禁止發(fā)送方使用Nagle算法,一組數(shù)據(jù)被寫入就會立即被發(fā)出,不需要等待mtu被填滿。
此外,接收方處理不當(dāng)也可能導(dǎo)致黏包問題,如果發(fā)送方將4個(gè)包發(fā)送到接收方的緩沖區(qū),但是由于頻繁的存取,可能有一次只取了2.5個(gè)包,就會導(dǎo)致黏包問題。接收方的黏包問題可以使用recv(sockfd