日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【飞秋】TCP粘包

發布時間:2025/3/15 编程问答 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【飞秋】TCP粘包 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

?首先申明一下,寫的這個東西注重的是一個思想~,代碼只是參考,并不能直接運行.下面進入正題

這兩天在弄Silverlight版本的SOCKET網絡編程,參考了菩提樹下的楊過的例子,寫了一段程序

自己也遇到了一些問題,例如TCP協議的粘包,想了個解決方案,興沖沖的,GOOGLE了一下發現類似的思想很多,不過決定還是把代碼貼出來吧

?

   /// <summary>
??????? /// 發送消息
??????? /// </summary>
??????? /// <param name="msgOrSql">消息類容</param>
??????? /// <returns></returns>
??????? public bool MsgTo(MsgOrSql msgOrSql)
??????? {
??????????? try
??????????? {
??????????????? SocketAsyncEventArgs socketEventArg = new SocketAsyncEventArgs();
??????????????? MemoryStream ms = new MemoryStream();
??????????????? byte[] dataLen = new byte[sizeof(long)];
??????????????? ms.Write(dataLen, 0, dataLen.Length);//先占住前八位字符


??????????????? string jsonString = JsonConvert.SerializeObject(msgOrSql);//JSON的序列化方式,讀者也可以用其它的序列化方式
??????????????? byte[] msgByte = Encoding.UTF8.GetBytes(jsonString);//寫入需要的流
??????????????? ms.Write(msgByte,0,msgByte.Length);

??????????????? ms.Position = 0;//從頭寫
??????????????? dataLen = BitConverter.GetBytes(ms.Length - dataLen.Length);//有效長度
??????????????? ms.Write(dataLen,0,dataLen.Length);// 將有效長度寫入流中

??????????????? byte[] data = ms.ToArray();//需要發送的字節流
??????????????? ms.Close();????????????
??????????????? socketEventArg.SetBuffer(data,0,data.Length);
??????????????? socketEventArg.RemoteEndPoint = clickSocket.RemoteEndPoint;
??????????????? clickSocket.SendAsync(socketEventArg);
??????????? }
??????????? catch (Exception ee)
??????????? {
??????????????? Console.Write(ee);
??????????? }
??????????? return false;
??????? }

以上是發送代碼,下面貼一下接收方的代碼

?

  ? private int msgLength;//消息總長
??????? private int yishouLength;//已收消息長度
??????? byte[] lstReceiveBytes = new byte[] { };//已經接受的數據

  ? /// <summary>
??????? /// 接受服務端發來的數據-回調處理
??????? /// </summary>
??????? /// <param name="sender"></param>
??????? /// <param name="e"></param>
??????? private void OnSocketReceiveCompleted(object sender, SocketAsyncEventArgs e)
??????? {
??????????? if (e.Buffer == null)
??????????? {
??????????????? return;
??????????? }
??????????? MemoryStream ms = new MemoryStream();
??????????? if (lstReceiveBytes.Length == 0)//判斷緩存是否存在數據
??????????? {

      //緩存中沒有數據
??????????????? msgLength = int.Parse(BitConverter.ToInt64(e.Buffer, 0).ToString());//獲得數據長度,也就是發送端寫入的字符長度

??????????????? ms.Write(e.Buffer, 8, e.BytesTransferred - 8);//將剩余的字符流寫入緩存,除了長度字符之外,所以是從第八位開始讀取數據流的
??????????? }
??????????? else
??????????? {

      //緩存中有數據了
??????????????? ms.Write(lstReceiveBytes,0,lstReceiveBytes.Length);//將原有的數據寫入緩存
??????????????? ms.Write(e.Buffer, 0, e.BytesTransferred);//將當前接收數據寫入緩存
??????????? }
??????????? yishouLength += e.BytesTransferred;//已收數據長度+=當前收的數據長度
??????????? lstReceiveBytes = ms.ToArray();//緩存中的數據替換
??????????? ms.Close();
??????????? GetMsgByByte();//調用處理緩存數據的方法
??????????? try
??????????? {
??????????????? //繼續異步地從服務端 Socket 接收數據(類似長連接)
??????????????? if (clickSocket != null && clickSocket.Connected)
??????????????? {
??????????????????? clickSocket.ReceiveAsync(e);
??????????????? }
??????????????? else
??????????????? {
??????????????????? Console.Write("無法連接到服務器...請刷新后再試...");
??????????????? }
??????????? }
??????????? catch (Exception ex)
??????????? {
??????????????? Console.Write(ex.Message.ToString());
??????????? }

??????? }
??????? private void GetMsgByByte()//處理緩存數據的方法
??????? {
??????????? try
??????????? {
??????????????? if (lstReceiveBytes.Length >= msgLength) //如果已接受的數據長度大于等于定義的數據長度 也就是說可以處理一條消息了
??????????????? {

       byte[] msgByte = new byte[] { };//當前需要處理的包信息
??????????????????? msgByte = lstReceiveBytes;//默認為緩存中的信息
??????????????????? if (lstReceiveBytes.Length > msgLength) //處于粘包狀態
??????????????????? {

         //將字符流分為兩個部分,一部分為當前的一條消息,分離出來當前處理,另一部分為下一步操作的數據流,寫入緩存進行下一步操作,(或許寫的有點模糊)   

         MemoryStream m = new MemoryStream();
??????????????????????? m.Write(lstReceiveBytes,0,msgLength);//取字符流中的一條傳送完畢的消息
??????????????????????? msgByte = m.ToArray();
??????????????????????? m.Close();
??????????????????????? m = new MemoryStream();
??????????????????????? m.Write(lstReceiveBytes, msgLength, lstReceiveBytes.Length - msgLength);//根據當前的數據長度讀取一條數據,所屬的所有字符流
??????????????????????? byte[] bb = m.ToArray();
??????????????????????? msgLength = int.Parse(BitConverter.ToInt64(bb, 0).ToString());//獲得下一條信息的字符流的長度

??????????????????????? m.Close();
??????????????????????? m = new MemoryStream();
??????????????????????? m.Write(lstReceiveBytes, msgLength, lstReceiveBytes.Length - msgLength);//獲得下一條信息的字符流,(不包含長度的字符流)

??????????????????????? lstReceiveBytes = m.ToArray();//替換緩存中的數據
??????????????????????? m.Close();

????????     }
??????????????????? string jsonString = Encoding.UTF8.GetString(lstReceiveBytes.ToArray(), 0, msgLength);//JSON的序列化方式,大家可以不用理會
??????????????????? MsgOrSql msgOrSql = new MsgOrSql();
??????????????????? msgOrSql = JsonConvert.DeserializeObject<MsgOrSql>(jsonString);
??????????????????? if (msgOrSql.dbInfo != null)
??????????????????? {
??????????????????????? if (msgOrSql.dbInfo.FangFaMin != null)
??????????????????????? {
??????????????????????????? DBHelper.listDbInfo.Add(msgOrSql.dbInfo.FangFaMin, msgOrSql.dbInfo);
??????????????????????? }
??????????????????? }
??????????????????? if (msgOrSql.msgInfo != null)
??????????????????? {
??????????????????????? if (msgOrSql.msgInfo.Id != null)//發送者的ID不為空
??????????????????????? {
??????????????????????????? UserHelper.listMsg.Add(msgOrSql.msgInfo);
??????????????????????? }
??????????????????? }
??????????????????? if (lstReceiveBytes.Length > msgLength)
??????????????????? {
??????????????????????? GetMsgByByte();//遞歸調用處理字符流的方法
??????????????????? }else

       {

         return; 

       }

       //字符流處理完畢,初始化接受消息的一些信息
??????????????????? msgLength = 0;
??????????????????? yishouLength = 0;
??????????????????? lstReceiveBytes=new byte[0];
??????????????? }
???????????????
??????????? }
??????????? catch (Exception ex)
??????????? {
??????????????? Console.Write(ex);
??????????? }


??????? }

兩個方法,一個是接受的回調函數,另外一個是處理字符流的方法

?

代碼寫的可能有些問題,COPY下去也運行不了,不過主要的思想應該是表現出來了,相信有些功底的人都能看得懂

發送消息之前,將消息打包,消息頭之前添加該消息的字符長度,接收方接受消息之后根據字符長度,判斷消息是否處理完畢,如果出現粘包,則繼續根據下一條消息的長度,處理下一條消息

?

希望對讀者有所啟發吧

關注技術文章飛秋:http://www.freeeim.com/,24小時專業轉載。

總結

以上是生活随笔為你收集整理的【飞秋】TCP粘包的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。