新聞中心
C# Socket通信三大問題是什么呢?讓我們開始講述:

利辛網(wǎng)站制作公司哪家好,找成都創(chuàng)新互聯(lián)公司!從網(wǎng)頁設計、網(wǎng)站建設、微信開發(fā)、APP開發(fā)、響應式網(wǎng)站建設等網(wǎng)站項目制作,到程序開發(fā),運營維護。成都創(chuàng)新互聯(lián)公司從2013年創(chuàng)立到現(xiàn)在10年的時間,我們擁有了豐富的建站經(jīng)驗和運維經(jīng)驗,來保證我們的工作的順利進行。專注于網(wǎng)站建設就選成都創(chuàng)新互聯(lián)公司。
C# Socket通信三大問題之數(shù)據(jù)包界限符問題。
根據(jù)原項目中交通部標準,在連續(xù)觀測站中數(shù)據(jù)包中,使用﹤﹥兩個字符表示有效數(shù)據(jù)包開始和結束。實際項目有各自的具體技術規(guī)范
C# Socket通信三大問題之數(shù)據(jù)包不連續(xù)問題。
在TCP/IP等通信中,由于時延等原因,一個數(shù)據(jù)包被Socket做兩次或多次接收,此時在接收第一個包后,必須保存到TSession的DatagramBuffer中,在以后一并處理
C# Socket通信三大問題包并發(fā)與重疊問題。
由于客戶端發(fā)送過快或設備故障等原因,一次接收到一個半、兩個或多個包文。此時,也需要處理、一個半、兩個或多個包
先補充異步BeginReceive()回調(diào)函數(shù)EndReceiveData()中的數(shù)據(jù)包分合函數(shù)ResolveBuffer()。
下面是C# Socket通信三大問題的實例演示:
- /// ﹤summary﹥
- /// 1) 報文界限字符為﹤﹥,其它為合法字符,
- /// 2) 按報文頭、界限標志抽取報文,可能合并包文
- /// 3) 如果一次收完數(shù)據(jù),此時 DatagramBuffer 為空
- /// 4) 否則轉(zhuǎn)存到包文緩沖區(qū) session.DatagramBuffer
- /// ﹤/summary﹥
- private void ResolveBuffer(TSession session, int receivedSize)
- {
- // 上次留下的報文緩沖區(qū)非空(注意:必然含有開始字符 ﹤,空時不含 ﹤)
- bool hasBeginChar = (session.DatagramBufferLength ﹥ 0);
- int packPos = 0; // ReceiveBuffer 緩沖區(qū)中包的開始位置
- int packLen = 0; // 已經(jīng)解析的接收緩沖區(qū)大小
- byte dataByte = 0; // 緩沖區(qū)字節(jié)
- int subIndex = 0; // 緩沖區(qū)下標
- while (subIndex ﹤ receivedSize)
- {
- // 接收緩沖區(qū)數(shù)據(jù),要與報文緩沖區(qū) session.DatagramBuffer 同時考慮
- dataByte = session.ReceiveBuffer[subIndex];
- if (dataByte == TDatagram.BeginChar) // 是數(shù)據(jù)包的開始字符﹤,則前面的包文均要放棄
- {
- // ﹤前面有非空串(包括報文緩沖區(qū)),則前面是錯包文,防止 AAA﹤A,1,A﹥ 兩個報文一次讀現(xiàn)象
- if (packLen ﹥ 0)
- {
- Interlocked.Increment(ref _datagramCount); // 前面有非空字符
- Interlocked.Increment(ref _errorDatagramCount); // 一個錯誤包
- this.OnDatagramError();
- }
- session.ClearDatagramBuffer(); // 清空會話緩沖區(qū),開始一個新包
- packPos = subIndex; // 新包起點,即﹤所在位置
- packLen = 1;// 新包的長度(即﹤)
- hasBeginChar = true; // 新包有開始字符
- }
- else if (dataByte == TDatagram.EndChar) // 數(shù)據(jù)包的結束字符 ﹥
- {
- if (hasBeginChar) // 兩個緩沖區(qū)中有開始字符﹤
- {
- ++packLen; // 長度包括結束字符﹥
- // ﹥前面的為正確格式的包,則分析該包,并準備加入包隊列
- AnalyzeOneDatagram(session, packPos, packLen);
- packPos = subIndex + 1; // 新包起點。注意:subIndex 在循環(huán)最后處 + 1
- packLen = 0; // 新包長度
- }
- else // ﹥前面沒有開始字符,則認為結束字符﹥?yōu)橐话阕址?,待后續(xù)的錯誤包處理
- {
- ++packLen; // hasBeginChar = false;
- }
- }
- else // 非界限字符﹤﹥,就是是一般字符,長度 + 1,待解析包處理
- {
- ++packLen;
- }
- ++subIndex; // 增加下標號
- } // end while
- if (packLen ﹥ 0) // 剩下的待處理串,分兩種情況
- {
- // 剩下包文,已經(jīng)包含首字符且不超長,轉(zhuǎn)存到包文緩沖區(qū)中,待下次處理
- if (hasBeginChar && packLen +
- session.DatagramBufferLength ﹤= _maxDatagramSize)
- {
- session.CopyToDatagramBuffer(packPos, packLen);
- }
- else // 不含首字符,或超長
- {
- Interlocked.Increment(ref _datagramCount);
- Interlocked.Increment(ref _errorDatagramCount);
- this.OnDatagramError();
- session.ClearDatagramBuffer(); // 丟棄全部數(shù)據(jù)
- }
- }
- }
C# Socket通信三大問題之分析包文AnalyzeOneDatagram()函數(shù)代碼補充如下:
- /// ﹤summary﹥
- /// 具有﹤﹥格式的數(shù)據(jù)包加入到隊列中
- /// ﹤/summary﹥
- private void AnalyzeOneDatagram(
- TSession session, int packPos, int packLen)
- {
- if (packLen + session.DatagramBufferLength ﹥ _maxDatagramSize)
- // 超過長度限制
- {
- Interlocked.Increment(ref _datagramCount);
- Interlocked.Increment(ref _errorDatagramCount);
- this.OnDatagramError();
- }
- else // 一個首尾字符相符的包,此時需要判斷其類型
- {
- Interlocked.Increment(ref _datagramCount);
- TDatagram datagram = new TDatagram();
- if (!datagram.CheckDatagramKind())
- // 包格式錯誤(只能是短期BG、或長期SG包)
- {
- Interlocked.Increment(ref _datagramCount);
- Interlocked.Increment(ref _errorDatagramCount);
- this.OnDatagramError();
- datagram = null; // 丟棄當前包
- }
- else // 實時包、定期包,先解析數(shù)據(jù),判斷正誤,并發(fā)回確認包
- {
- datagram.ResolveDatagram();
- if (true) // 正確的包才入包隊列
- {
- Interlocked.Increment(ref _datagramQueueCount);
- lock (_datagramQueue)
- {
- _datagramQueue.Enqueue(datagram); // 數(shù)據(jù)包入隊列
- }
- }
- else
- {
- Interlocked.Increment(ref _errorDatagramCount);
- this.OnDatagramError();
- }
- }
- }
- session.ClearDatagramBuffer(); // 清包文緩沖區(qū)
- }
C# Socket通信三大問題之TSession的拷貝轉(zhuǎn)存數(shù)據(jù)包文的方法CopyToDatagramBuffer()代碼如下:
- /// ﹤summary﹥
- /// 拷貝接收緩沖區(qū)的數(shù)據(jù)到數(shù)據(jù)緩沖區(qū)(即多次讀一個包文)
- /// ﹤/summary﹥
- public void CopyToDatagramBuffer(int startPos, int packLen)
- {
- int datagramLen = 0;
- if (DatagramBuffer != null) datagramLen =
- DatagramBuffer.Length;
- // 調(diào)整長度(DataBuffer 為 null 不會出錯)
- Array.Resize(ref DatagramBuffer,
- datagramLen + packLen);
- // 拷貝到數(shù)據(jù)就緩沖區(qū)
- Array.Copy(ReceiveBuffer, startPos,
- DatagramBuffer, datagramLen, packLen);
- }
代碼中注釋比較詳細了,下面指出C# Socket通信三大問題實例開發(fā)思路:
使用TSession會話對象的字節(jié)數(shù)組ReceiveBuffer保存BeginReceiver()接收到的數(shù)據(jù),使用字節(jié)數(shù)組DatagramBuffer保存一次接收后分解或合并的剩下的包文。本項目中,由于是5分鐘一個包,正常情況下不需要用到DatagramBuffer數(shù)組
處理ReceiveBuffer中的字節(jié)數(shù)據(jù)包時,先考慮DatagramBuffer是否有開始字符﹤。如果有,則當前包文是前個包文的補充,否則前個包文是錯誤的。正確的包文可能存在于兩個緩沖區(qū)中,見分析函數(shù)AnalyzeOneDatagram()
分析完接收數(shù)據(jù)包后,剩下的轉(zhuǎn)存到DatagramBuffer中,見函數(shù)CopyToDatagramBuffer()
設計時考慮的另一個重要問題就是處理速度。如果自動觀測站達到100個,此時5*60=300秒鐘就有100個包,即每3秒種一個包,不存在處理速度慢問題。但是,真正耗時的是判斷包是否重復!特別地,當設備故障時存在混亂上傳數(shù)據(jù)包現(xiàn)象,此時將存在大量的重復包。筆者采用了所謂的區(qū)間判重算法,較好地解決了判重速度問題,使得系統(tǒng)具有很好的可伸縮性(分析算法的論文被EI核心版收錄,呵呵,意外收獲)。事實上,前年的交通部接收服務器還不具備該項功能,可能是太費時間了。
還有,就是在.NET Framework的托管CLR下,系統(tǒng)本身的響應速度如何?當時的確沒有把握,認為只要穩(wěn)定性和速度滿足要求就行了。三年半運行情況表明,系統(tǒng)有良好的處理速度、很好的穩(wěn)定性、滿足了部省要求。
C# Socket通信三大問題的基本內(nèi)容就向你介紹到這里了,希望對你了解和學習C# Socket通信三大問題有所幫助。
名稱欄目:C#Socket通信三大問題詳解
瀏覽路徑:http://m.5511xx.com/article/ccdoeip.html


咨詢
建站咨詢
