tcp中的粘包、半包的處理方法
TCP粘包是指傳送方傳送的若干包資料到接收方接收時粘成一包,從接收緩衝區看,後一包資料的頭緊接著前一包資料的尾。
出現粘包現象的原因既可能由傳送方造成,也可能由接收方造成。
傳送方引起的粘包是由TCP協議本身造成的,TCP為提高傳輸效率,傳送方往往要收集到足夠多的資料後才傳送一包資料。若連續幾次傳送的資料都很少,通常TCP會根據優化演算法把這些資料合成一包後一次傳送出去,這樣接收方就收到了粘包資料。
接收方引起的粘包是由於接收方使用者程式不及時接收資料,從而導致粘包現象。這是因為接收方先把收到的資料放在系統接收緩衝區,使用者程式從該緩衝區取資料,若下一包資料到達時前一包資料尚未被使用者程式取走,則下一包資料放到系統接收緩衝區時就接到前一包資料之後,而使用者程式根據預先設定的緩衝區大小從系統接收緩衝區取資料,這樣就一次取到了多包資料。
c++的解決方法如下:
接收端
int iRecvSize = PackteSize + 10;
int iRet;
int idx = 0;
while (iRecvSize > 0)
{
iRet = recv(AcceptSocket, recvbuf+idx, iRecvSize, 0);
if (iRet > 0)
{
idx += iRet;
iRecvSize -= iRet;
}
else if (iRet == 0)
{
break;
}
else if ( iRet == SOCKET_ERROR)
{
break;
}
}
傳送端:
int iSendSize = PacketSize + 10;
int iSent;
int idx = 0;
while (iSendSize > 0)
{
iSent = send(m_socket,sendbuffer+idx,iSendSize,0);
if (iSent > 0)
{
idx += iSent;
iSendSize -= iSent;
}
else if (iSent == 0)
{
break;
}
else if (iSent == SOCKET_ERROR)
{
wprintf(L"send failed with error: %d\n", WSAGetLastError());
//closesocket(m_socket);
//WSACleanup();
break;
}
}
若傳輸的資料為不帶結構的連續流資料(如檔案傳輸),則不必把粘連的包分開(簡稱分包),反之則必須分包。
c#中用socket的Available成員來表示是否還有資料需要讀取,如果Available>0,表示還有資料需有讀取,反之讀取完成。
public class ConnectInfo
{
public ArrayList tmpList { get; set; }
public SocketAsyncEventArgs SendArg { get; set; }
public SocketAsyncEventArgs ReceiveArg { get; set; }
public Socket ServerSocket { get; set; }
public User user = new User();
}
if (client.Available > 0)
{
Console.WriteLine("粘包處理");
for (int i = 0; i < rec; i++)
info.tmpList.Add(datas[i]);
Array.Clear(datas, 0, datas.Length);
datas = new byte[client.Available];
e.SetBuffer(datas, 0, datas.Length);
client.ReceiveAsync(e);
}
else
{
//檢查暫存資料的ArrayList中有沒有資料,有就和本次的資料合併
if (info.tmpList.Count > 0)
{
for (int i = 0; i < rec; i++)
info.tmpList.Add(datas[i]);
datas = info.tmpList.ToArray(typeof(byte)) as byte[];
rec = datas.Length;
}
//對接收的完整資料進行處理
}
半包顧名思義,就不是一個完整的包,tcp發出一個段後,它啟動一個定時器,等待目的端確認收到這個報文段。如果不能及時收到一個確認,將重發這個報文段。
常見的解決方法就是制定規範的資料傳輸格式。
只要控制好 你需要讀取的位元組長度,就可以了
比如一個包有10個位元組,包頭4個位元組是長度,包體6個位元組是包內容
你首先要讀的就是4位元組,如果不夠就等下一次recv的返回
夠了4位元組,就能得到包的長度,如果超過4位元組,也只取4位元組,多出來的內容是包體的,後面再處理
然後這4位元組裡面的內容,得到是6,表示後面有6個位元組的包體
然後就是讀6位元組,依然是如果不夠就等下一次recv的返回
直到夠了6位元組為止,
如果讀了6位元組還有多餘,就是下一個包的資料
相關文章
- 資料接收中粘包及半包的處理
- 詳說tcp粘包和半包TCP
- go語言處理TCP拆包/粘包GoTCP
- TCP通訊處理粘包詳解TCP
- GO語言手動處理TCP粘包GoTCP
- socket的半包,粘包與分包的問題
- Netty解決半包(TCP粘包/拆包導致)讀寫問題NettyTCP
- [ gev ] Go 語言優雅處理 TCP “粘包”GoTCP
- Netty粘包&半包解決方案Netty
- TCP的粘包拆包技術TCP
- TCP 粘包拆包TCP
- java nio解決半包 粘包問題Java
- C# 優雅的處理TCP資料(心跳,超時,粘包斷包,SSL加密 ,資料處理等)C#TCP加密
- java nio訊息半包、粘包解決方案Java
- TCP粘包拆包問題TCP
- Netty Protobuf處理粘包分析Netty
- Go TCP 粘包問題GoTCP
- 網路遊戲資料傳輸:粘包的處理遊戲
- Netty 中的粘包和拆包Netty
- TCP 粘包 - 拆包問題及解決方案TCP
- TCP協議粘包問題詳解TCP協議
- 再聊t-io網路程式設計架構的基礎知識:半包和粘包程式設計架構
- 64行程式碼實現零拷貝go的TCP拆包粘包行程GoTCP
- 計算機網路 - TCP粘包、拆包以及解決方案計算機網路TCP
- Netty原始碼學習6——netty編碼解碼器&粘包半包問題的解決Netty原始碼
- Smartform中的長文處理方法ORM
- 粘包問題原因和解決方法
- 硬核圖解TCP粘包 資料包:我只是犯了每個資料包都會犯的錯圖解TCP
- 深入學習Netty(5)——Netty是如何解決TCP粘包/拆包問題的?NettyTCP
- 即時通訊下資料粘包、斷包處理例項(基於CocoaAsyncSocket)
- Netty(三) 什麼是 TCP 拆、粘包?如何解決?NettyTCP
- Netty中使用MessagePack時的TCP粘包問題與解決方案NettyTCP
- 從零開始netty學習筆記之TCP粘包和拆包Netty筆記TCP
- Wireshark中的TCP協議包分析TCP協議
- 【DG】 DataGuard 中處理archive gap的方法Hive
- ppt中插入和處理影片的方法
- 粘包問題
- NIO框架之MINA原始碼解析(四):粘包與斷包處理及編碼與解碼框架原始碼