使用C# 撰寫非同步方法 TCP socket --3

當Server 接受 Client 的連線後,有指定當該Socket有資料傳入時,要叫用接受資料WaitForData()函式,其 WaitForData() 詳細如下:

//宣告AsyncCallback類別的變數 pfnWorkerCallBack
public AsyncCallback pfnWorkerCallBack;
public void WaitForData(System.Net.Sockets.Socket soc)
{
  try{
    //當pfnWorkerCallBack物件尚未實體化時,進行實體化
    if (pfnWorkerCallBack == null)
    {
        //假設已連線的RCC客戶端要傳送資料給RCS時,所指定的回呼函式-OnDataReceive,這也是C#中的delagate型別,此函式內容詳述於後
        pfnWorkerCallBack = new AsyncCallback(OnDataReceived);
    }
    //自行定義的型別 SocketPacket,附於此小節尾,內容只有一個Socket類和一個int。
    SocketPacket theSocPkt = new SocketPacket();
    //指定此一建立連線之Socket soc 給定義的 theSocPkt
    theSocPkt.m_currentSocket = soc;
    // 接下來定義當Socket 接收到資料時要交給哪一個函數處理,這裡定義了BeginReceive()
    // 參數第一個為存放的位置,為byte[],傳入的資料會置於此陣列中;第二參數為啟始位置、第三為一次置入的長度;第四為封包的旗標,例如標記為廣播封包 之類,第五參數為開始接受資料時叫用的回呼函式,由於pfnWorkerCallBack已實體化指定OnDataReceived為回呼函式,所以當有 客戶端將資料傳進來時,OnDataReceived函式會被叫用;第六為狀態的參數,這個是用戶自訂,當回呼函式OnDataReceived被叫用 時,此參數的值會被傳遞到OnDataReceived,因此雖然SocketPacket theSocPkt宣告的是區域變數,但是回呼函式仍會曉得是哪一個Socket在傳送資料。

    soc.BeginReceive(theSocPkt.dataBuffer, 0, theSocPkt.dataBuffer.Length, SocketFlags.None, pfnWorkerCallBack, theSocPkt);
  }
  catch (SocketException) { …例外處理略... }
 }

//自型定義的物件封包的類別
public class SocketPacket
{
    //目前Activating之Socket
    public System.Net.Sockets.Socket m_currentSocket;
    public byte[] dataBuffer = new byte[1500]; //接受資料陣列
}

當建立連線的 Socket 有資料傳入時,要叫用的回呼函式為OnDataReceived() 。

此回呼函式有一參數類型為IasyncResult,因為該類型是.NET中很特別的類型,稱之為介面(Interface),簡單的說,介面算是一個只有定義沒有實作項的類別。由於BeginReceive 方法被叫用時的傳入的最未個參數是自定的theSocPkt物件,會轉型成IAsyncResult.AsyncState 傳入,因此宣告的IasyncResult類變數asyn,則asyn.AsyncState 可取得符合或包含非同步作業資訊的使用者定義的物件。

下方將實作出OnDataReceived() 函式,由於此函式必需將收到的資料分析及編碼處理,所以原函式稍長,故僅節錄出和TCP非同步連線有關之部分於下:

public void OnDataReceived(IAsyncResult asyn)
{
  try{
    SocketPacket socketData = (SocketPacket)asyn.AsyncState;//取得接受的資料
    string msg = "";//宣告及定義訊息字串
    int iRx = 0;//宣告及定義訊息長度
    //叫用 EndReceive 完成指定的非同步接收作業, 參數asyn 識別要完成的非同步接收作業,並要從其中擷取最終結果。
    iRx = socketData.m_currentSocket.EndReceive(asyn);
    //以下為將取出的部分轉成 UTF8的編碼方式,有關編碼方式轉換可依需求自行修改
    byte[] databuff = socketData.dataBuffer;
    msg = Encoding.UTF8.GetString(databuff);
    …分析處理部分略,主要msg訊息的利用和重組…
    //重新叫用 WaitForData 重新開始接收資料
    WaitForData(socketData.m_currentSocket);
  }
  catch (SocketException) { …例外處理略... }
}

以上幾個 函式就完成了 非同步方法 TCP socket ,這裡將其整理一下:

Server() 啟動監聽
OnClientConnect(IAsyncResult) 當客戶端建立連線時叫用
WaitForData(Socket) 建立連線等待資料傳入
OnDataReceived(IAsyncResult)  已連線連線並有資料傳入時叫用

FindEmptyChannel() 尋找未用的頻道

祝各位使用愉快

[參考資料]

Asynchronous Socket Programming in C#
http://www.codeguru.com/csharp/csharp/cs_network/sockets/article.php/c7695/#more

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值