Socket解决粘包问题2
在AsynServer中對接收函數增加接收判斷,如果收到客戶端發送的請求信息,則發送10個測試包給發送端,否則繼續接收,修改后的接收代碼如下:
private void AsynReceive(){byte[] data = new byte[1024];//接收緩存string receiveStr;string[] sendArr = PackageBuilder.BuildPackage(10);//生成發送數組,10個包socket.BeginReceive(data, 0, data.Length, SocketFlags.None, asyncResult => {int length = socket.EndReceive(asyncResult);receiveStr = Encoding.ASCII.GetString(data, 0, length);//獲取緩存中的信息// Console.WriteLine(receiveStr);if (receiveStr == "1") //標志字符'1',如果收到1,則發送測試包給客戶端,如果不是1,繼續接受 {for (int i = 0; i < 10; i++){Console.WriteLine("第{0}次發送:",i);AsynSend(sendArr[i]);// Thread.Sleep(200); }}elseAsynReceive();}, null);} View Cosde其中if (receiveStr == "1")是接收判斷,如果收到客戶端發來的1,則發送測試包給客戶端,如果不是1,繼續接收。因為是異步發送,所以Console.WriteLine("第{0}次發送:",i);顯示可能和發送數據不同步,但肯定是發送了10次。
測試一下,發送10次,接收端收到結果如下:
發了10次,而只收了8次,從上圖中我們可以發現第6次和第7次發生了粘包,兩個包被當作1個包接收了,如果你編寫解包程序時不考慮粘包,那么解包循環在第7次解包時會拋異常。當然一種快捷的避免粘包方式是在發送函數的?AsynSend(sendArr[i]);下面加上Thread.Sleep(200);減少發送頻率,但這不是長久之計,接下來我們進入客戶端來處理粘包問題。
客戶端主要是修改了SyncReceive方法,使用StringBuilder來做接收,因為StringBuilder較于string而言,增加字符串,刪除字符串的效率比較高,代碼如下:
string[] receiveArr = new string[10];//用于存儲接收到的數據int arri=0;//數組位序public virtual void SyncReceive(){//StringBuilder sb = new StringBuilder(1024*1024);StringBuilder receiveSb = new StringBuilder(); //接收字符串bufferstring receiveStr; //解包過程中用于 中間處理 int index; //位序,用于解包int dataLength; //存儲接收包中的數據長度int i = 0;Thread th = new Thread(() =>{while (receiveFlag){byte[] buffer = new byte[1024];int r = socket.Receive(buffer);string str = Encoding.ASCII.GetString(buffer, 0, r); //只是用來顯示Console.WriteLine("第{0}次收到數據:{1}",i++,str);Console.WriteLine();receiveSb.Append(str); //存儲接收字符串,可能存多個包receiveStr = receiveSb.ToString();index = receiveStr.IndexOf("data:");//可能有多個"data"while (index > 1){dataLength = int.Parse(receiveStr.Substring(index - 2, 2));//數據長度規定為2個字節receiveArr[arri] = receiveStr.Substring(index, dataLength);//保存數據到數組中Console.WriteLine("保存的數據數組[{0}]:{1}",arri,receiveArr[arri++]);receiveSb.Remove(0, 10 + dataLength);//包頭+數據長度字節共10個字節"HEAD|H1|38",后面是數據"data:xxxxxxxxxxxxxxxxxxxx"receiveStr = receiveSb.ToString();index = receiveStr.IndexOf("data:");//尋找下一個"data",如果沒有跳出循環 }//sb.AppendFormat("{0}", Encoding.ASCII.GetString(buffer, 0, r)); }});th.Start();} View Code方法上面加了兩個全局變量,receiveArr是一個數組,用于保存接收到的實時數據,這些數據可以用于前臺展示,也可以直接保存到數據庫;arri是數組位序,運行結果如下:
如圖所示,客戶端接收了7次數據,第一次有4個包粘在了一起,但我們通過合適的解包,依然將10次數據分開保存在字符串數組中。
客戶端要先發送"1"標志給客戶端才能執行上面的程序,???? SynSend("1");
程序的源碼下載地址:
鏈接:http://pan.baidu.com/s/1nvfa8lF 密碼:zjoa
粘包的處理是比較簡單的,更麻煩的是分包,雖然不常見,但也要考慮,后面考慮做一下分包的處理,程序寫的比較毛糙,如有不足之處希望大家指出。
?
轉載于:https://www.cnblogs.com/gongheng/p/5699092.html
總結
以上是生活随笔為你收集整理的Socket解决粘包问题2的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: PHP异常与错误处理机制
- 下一篇: hdfs基本操作命令(完整)