C#網絡程序設計(3)網絡傳輸編程之TCP編程

    網絡傳輸編程指基於各類網絡協議進行編程,包括TCP編程,UDP編程,P2P編程。本節介紹TCP編程。程序員

 

    (1)TCP簡介:編程

    TCP是TCP/IP體系中最重要的傳輸層協議,它提供全雙工和可靠交付的服務,是大多數應用協議工做的基礎。做爲上層應用編程的基礎,TCP編程也是最終實現應用程序網絡功能的基石。設計模式

    TCP是一種面向鏈接的,可靠的,基於字節流的傳輸層通訊協議。在TCP/IP協議棧中,它位於IP協議之上;在整個網絡協議簇中,它處於應用層諸多協議之下。因爲網絡上不一樣主機的應用層之間常常須要可靠的,像管道同樣的鏈接,可是IP自己並不提供這樣的機制,故須要由TCP完成傳輸管道功能。數組

 

    (2)TCP工做過程:緩存

    TCP經過中止等待協議和連續ARQ協議實現可靠傳輸,工做過程分爲鏈接創建,傳輸數據,鏈接終止三個過程:服務器

    1)鏈接創建網絡

    TCP創建鏈接的過程叫作握手,握手須要在客戶和服務器之間交換三個TCP報文段。app

  

    三次握手(three-way handshake):框架

第一次握手:創建鏈接時,客戶端發送SYN包(SEQ=x)到服務器,並進入SYN_SEND狀態,等待服務器確認。
第二次握手:服務器收到SYN包,必須確認客戶的SYN(ACK=x+1),同時本身也會發送一個SYN包(SEQ=y),即SYN+ACK包,此時服務器進入SYN_RECV狀態。
第三次握手:客戶端收到服務端的SYN+ACK包,向服務器發送確認包ACK(ACK+1),此包發送完畢,客戶端與服務端進入Established狀態,完成三次握手。

    B發送給A的報文段也能夠拆分紅兩個報文段(先發確認報文段,再發同步報文段),這樣三報文握手就變成了四報文握手。異步

    最後A還要發送一次確認主要是爲了防止已失效的鏈接請求報文忽然又傳送到了B,於是產生錯誤。(因爲網絡延時,B可能連續收到A發送的兩個請求)

    2)傳輸數據

    TCP的全雙工通訊的雙方便是發送方又是接收方。TCP協議負責把用戶數據(字節流)按必定格式和長度組成多個數據報進行發送,並在接收到數據報以後按分解順序從新組裝和恢復用戶數據。

    利用TCP傳輸數據時,數據是以字節流的形式進行傳輸的。客戶端與服務器創建鏈接後,發送方須要先將要發送的數據轉換爲字節流,而後發送給對方。發送數據時,程序員能夠經過程序不斷地將數據流寫入TCP的發送緩存中,而後TCP自動從發送緩存中取出必定量的數據,將其組成TCP報文段逐個發給IP層,再經過IP層之下的網絡接口發送出去。接收端從IP層接收到TCP報文段以後,將其暫時保存在接收緩存中,這是程序員就能夠經過程序依次讀取接收緩存中的數據,從而達到相互通訊的目的。

    3)鏈接終止

    創建一個鏈接須要三次握手,而終止一個鏈接須要通過四次握手,這是由TCP的半關閉(half-close)形成的:

  

    四次握手實現TCP鏈接的釋放:

1) TCP客戶端發送一個FIN,關閉客戶端到服務器端的數據傳送。(客戶端再也不發送報文給服務器端,但可接受服務器端報文)
(2) 服務器收到這個FIN,它發回一個ACK,確認序號爲收到的序號加1。
(3) 服務器關閉客戶端的鏈接,發送一個FIN給客戶端。(服務器端關閉到客戶端的數據傳送)
(4) 客戶段發回ACK報文確認,並將確認序號設置爲收到序號加1。

    爲了更清地看出TCP鏈接的各類狀態之間的關係,下面給出TCP的有限狀態集:

  

 

 

    (3)TCP的同步編程與異步編程:

    利用TCP開發應用程序時,.Net框架提供了兩種工做方式,一種是同步(Synchronization)工做方式,一種是異步(Asynchronous)工做方式。

同步工做方式:利用TCP編寫的程序執行到監聽或接收語句時,在未完成當前工做(偵聽到鏈接請求或收到對方發來的數據)前再也不繼續往下執行,線程處於阻塞狀態,直到該語句結束才繼續執行下一條語句。
異步工做方式:程序執行到監聽或者接收語句時,不論當前工做是否完成,都會繼續執行下去。

    對於請求和發送語句,在同步和異步方式下並沒有差異:

    TCP鏈接是網絡傳輸層的"虛鏈接",真是的網絡數據通訊是經過TCP/IP體系的底層(IP層和網絡接口)協議實現的。TCP線程在執行發送語句時,只需將待發送數據以字節流的形式寫入發送緩存,在它"看來"本身發送數據的動做已經完成(實際上此時數據可能暫存在本地而並未發送出去),至於對方進程是否真正收到就與它無關了,因而發送線程可能繼續往下執行其餘的操做(不會阻塞),而真實的發送操做是由下層協議(IP)在適當的時機(對方接收準備好)完成的。

  

    IP層爲TCP提供了實際的傳輸服務,從而對上層應用程序屏蔽了主動(請求鏈接和發送數據)操做時的同步與異步差別。儘管如此,線程在被動(監聽鏈接和接收數據)操做上仍有同步和異步之別。這是由於被動操做必須依賴於對方操做的結果,如接收數據時緩存中必須有內容,不然就無從接收。

 

    (4)C#中的TCP編程類:

    與同步工做方式和異步工做方式相對應,利用Socket類進行編程時,系統也提供相應的方法,分別稱爲同步套接字編程和異步套接字編程。可是使用套接字編程要考慮很對底層細節。爲了簡化編程複雜度,.NET又專門提供了兩個類:TCPClient和TCPListener。TCP編程也分爲同步TCP編程和異步TCP編程

    1)TCP Listener類:

    TcpListener類用於監聽和接收傳入的鏈接請求。 該類的構造函數經常使用的有如下兩種重載形式:

TcpListener(IPEndPoint iep) 
TcpListener(IPAddress localAddr, int port)

    應用示例:

IPEndPoint iep = new IPEndPoint(IPAddress.Parse(「210.2.2.1」), 9050); TCPListener t1= new TCPListener (iep);
TCPListener t2= new TCPListener (IPAddress.Any, 0)    IP地址和端口號均由系統自動分配

    TCPListener類的經常使用方法:

   

    start方法:

public void Start()
開始偵聽傳入的鏈接請求。
public void Start(int backlog)
啓動對具備最大掛起鏈接數的傳入鏈接請求的偵聽。

    AcceptTcpClient方法:

public TcpClient AcceptTcpClient()
接受掛起的鏈接請求

    Stop方法:

public void Stop()
關閉偵聽器。

    2)TCP Client類:

    該構造函數建立一個默認的TcpClient對象,並自動分配本機(客戶端)IP地址和端口號。TCPClient有四個重載函數:

TCPClient()
TCPClient(AddressFamily family)
TCPClient(IPEndpoint iep)
TCPClient(String hostname,int port)

    應用示例:

1.TCPClient()
建立一個默認的TCPClient對象,並自動分配本機(客戶端)IP地址和端口號。
還需調用Connect方法與服務器創建鏈接。
例如:
TcpClient tcpClient = new TcpClient();
tcpClient.Connect(「www.abcd.com」,  51888);
2.TCPClient(AddressFamily family)
建立一個默認的TCPClient對象,自動分配本機(客戶端)IP地址和端口號,可是使用AddressFamily枚舉指定使用哪一種網絡協議。
必須調用Connect方法與服務器創建鏈接。
例如:
TcpClient tcpClient = new TcpClient(AddressFamily.InterNetwork);
tcpClient.Connect(「www.abcd.com」,  51888);
3.TCPClient(IPEndpoint iep)
建立一個TCPClient對象,參數指定本機(客戶端)IP地址和端口號。
必須調用Connect方法與服務器創建鏈接。
例如:
IPAddress[]  address = Dns.GetHostAddresses (Dns.GetHostName());
IPEndPoint iep = new IPEndPoint (address[0],  51888);
TcpClient tcpClient = new TcpClient(iep);
tcpClient.Connect(「www.abcd.com」,  51888);
4.TCPClient(String hostname,int port)
建立一個TCPClient對象,自動分配最合適的本地主機IP地址和端口號。
與參數指定的遠程主機創建鏈接。
例如:
TcpClient tcpClient = new TcpClient(「www.abcd.com」,  51888);
它至關於:
TcpClient tcpClient = new TcpClient();
tcpClient Connect(「www.abcd.com」,  51888);

    TCPClient類的經常使用屬性:

  

    TCPClient類的經常使用方法:

  

    Connect方法:

  

    GetStream方法:

public NetworkStream GetStream() 返回用於發送和接收數據的 NetworkStream。
示例:
TcpClient tcpClient = new TcpClient ();
NetworkStream netStream = tcpClient.GetStream (); //接收數據 
byte[] bytes = new byte[tcpClient.ReceiveBufferSize]; netStream.Read (bytes, 0, (int)tcpClient.ReceiveBufferSize);
string returndata = Encoding.UTF8.GetString (bytes); //發送數據 
Byte[] sendBytes = Encoding.UTF8.GetBytes ("Is anybody there?"); netStream.Write (sendBytes, 0, sendBytes.Length);

    NetWorkStream的read方法:

從 NetworkStream 讀取數據。
public override int Read(
    byte[] buffer,
    int offset,
    int size
)

    NetWorkStream的Write方法:

將數據寫入 NetworkStream 。
public override void Write(
    byte[] buffer,
    int offset,
    int size
)

   

    (5)TCP編程實例: 

    TCP編程的步驟:

1.服務器端:
(1)建立一個TcpListener對象,而後調用該對象的Start方法在指定的端口進行監聽。
(2)在單獨的線程中,循環調用AcceptTcpClient方法接受客戶端的鏈接請求,從該方法的返回結果中獲得與該客戶端對應的TcpClient對象,並利用該對象的GetStream方法獲得NetworkStream對象,爲進一步與對方通訊做準備。
(3)每獲得一個新的TcpClient對象,就建立一個與該客戶對應的線程,在線程中與對應的客戶進行通訊。
(4)根據傳送信息的狀況肯定是否關閉與客戶的鏈接。
2.客戶端:
(1)利用TcpClient的構造函數建立一個TcpClient對象。
(2)使用Connect方法與服務器創建鏈接。
(3)利用TcpClient對象的GetStream方法獲得網絡流,而後利用該網絡流與服務器進行數據傳輸。
(4)建立一個線程監聽指定的端口,循環接收並處理服務器發送過來的信息。
(5)完成工做後,向服務器發送關閉信息,並關閉與服務器的鏈接。

    1)TCP同步:

    服務端:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

//添加的引用
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.IO;

namespace SyncTCPServer
{
    public partial class ServerForm : Form
    {
        //成員變量
        private IPAddress localAddress;
        private int port = 18888;
        private TcpListener tcpListener;
        private TcpClient tcpClient;
        private NetworkStream networkStream;
        private BinaryReader br;
        private BinaryWriter bw;
        private int sendCount = 1;
        private int receiveCount = 10;

        /*----------聲明用於方法回調的委託----------*/
        //用於ListBox顯示消息
        private delegate void ShowMsgForViewCallBack(string str);
        private ShowMsgForViewCallBack showMsgForViewCallBack;
        //用於toolStripLabel顯示當前窗體的狀態
        private delegate void ShowStatusInfoCallBack(string str);
        private ShowStatusInfoCallBack showStatusInfoCallBack;
        //用於toolStrioProgressBar顯示當前進度
        private delegate void ShowProgressProCallBack(int progress);
        private ShowProgressProCallBack showProgressProCallBack;
        //用於重置消息文本
        private delegate void ResetMessageTextCallBack();
        private ResetMessageTextCallBack resetMessageTextCallBack;

        //本身添加的兩個委託,用於標識已發送或接受的數據個數
        private delegate void SendTextBoxCallBack();
        private SendTextBoxCallBack sendTextBoxCallBack;

        private delegate void ReceiveTextBoxCallBack(int count);
        private ReceiveTextBoxCallBack receiveTextBoxCallBack;
        public ServerForm()
        {
            InitializeComponent();
            //初始化綁定的IP地址,初始化窗口的顯示內容
            IPAddress[] listenIp = Dns.GetHostAddresses("");
            localAddress = listenIp[3];
            sendTextBox.Text = sendCount.ToString();
            receiveTextBox.Text = receiveCount.ToString();
            toolStripProgressProc.Minimum = 0;
            toolStripStatusInfo.Text = "就緒";
            //將委託的方法進行進行實例化
            showMsgForViewCallBack = new ShowMsgForViewCallBack(showMessageForListBox);
            showStatusInfoCallBack = new ShowStatusInfoCallBack(showStatusInfo);
            showProgressProCallBack = new ShowProgressProCallBack(showStatusProgress);
            resetMessageTextCallBack = new ResetMessageTextCallBack(resetListViewItems);
            //本身加的
            sendTextBoxCallBack = new SendTextBoxCallBack(sendTextAdd);
            receiveTextBoxCallBack = new ReceiveTextBoxCallBack(receiveTextSubtract);
        }
        private void receiveTextSubtract(int count)
        {
            receiveTextBox.Text = count.ToString();
        }
        private void sendTextAdd()
        {
            sendCount++;
            sendTextBox.Text = sendCount.ToString();
        }
        private void showMessageForListBox(string str) 
        {
            showMessageListBox.Items.Add(str);
            showMessageListBox.TopIndex = showMessageListBox.Items.Count - 1;
        }
        private void showStatusInfo(string str) 
        {
            toolStripStatusInfo.Text = str;
        }
        private void showStatusProgress(int progress) 
        {
            toolStripProgressProc.Value = progress;
        }
        private void resetListViewItems() 
        {
            showMessageListBox.Text = "";
            showMessageListBox.Focus();
        }

        private void beginListenButton_Click(object sender, EventArgs e)
        {
            //當點擊開始監聽的時候
            try
            {
                tcpListener = new TcpListener(localAddress, port);
                tcpListener.Start();
                toolStripProgressProc.Maximum = 10;
                toolStripProgressProc.Value = 0;
                //啓動一個線程接受請求
                Thread threadAccept = new Thread(AcceptClientConnect);
                threadAccept.Start();
            }
            catch(Exception ex)
            {
                showMessageListBox.Invoke(showMsgForViewCallBack, "監聽時:" + ex.ToString());
            }
        }

        private void AcceptClientConnect(object obj)
        {
            toolStripContainer1.Invoke(showStatusInfoCallBack,"["+localAddress.ToString()+":"+ port +"]偵聽");
            DateTime nowTime = DateTime.Now;
            while(nowTime.AddSeconds(1)>DateTime.Now){}
            try
            {
                toolStripContainer1.Invoke(showStatusInfoCallBack,"等待鏈接......");
                toolStripContainer1.Invoke(showProgressProCallBack, 1);
                tcpClient = tcpListener.AcceptTcpClient();
                //後續操做進度顯示
                toolStripContainer1.Invoke(showProgressProCallBack, 10);
                if(tcpClient!=null)
                {
                    toolStripContainer1.Invoke(showStatusInfoCallBack, "接受了一個鏈接.");
                    networkStream = tcpClient.GetStream();
                    br = new BinaryReader(networkStream);
                    bw = new BinaryWriter(networkStream);
                }
            }
            catch 
            {
                toolStripContainer1.Invoke(showStatusInfoCallBack, "中止偵聽.");
                //間歇延時
                DateTime now = DateTime.Now;
                while (nowTime.AddSeconds(1) > DateTime.Now) { }
                toolStripContainer1.Invoke(showProgressProCallBack, 0);
                toolStripContainer1.Invoke(showStatusInfoCallBack, "就緒");
            }
        }

        private void receiveButton_Click(object sender, EventArgs e)
        {
            receiveCount = int.Parse(receiveTextBox.Text);
            toolStripProgressProc.Maximum = receiveCount;
            toolStripProgressProc.Value = 0;
            Thread threadReceive = new Thread(ReceiveMessage);
            threadReceive.Start();
        }

        private void ReceiveMessage(object obj)
        {
            toolStripContainer1.Invoke(showStatusInfoCallBack, "接收中");
            for (int i = 0; i < receiveCount;i++ )
            {
                try
                {
                    string receiveMessageStr = br.ReadString();
                    //後續操做進行進度顯示
                    toolStripContainer1.Invoke(showProgressProCallBack, i+1);
                    receiveTextBox.Invoke(receiveTextBoxCallBack,10-i-1);
                    if (receiveMessageStr != null)
                    {
                        showMessageListBox.Invoke(showMsgForViewCallBack,receiveMessageStr);
                    }
                }catch(Exception e)
                {
                    showMessageListBox.Invoke(showMsgForViewCallBack, "接收時:" + e.ToString());
                    whenExceptionOcur();
                    break;
                }
            }
            toolStripContainer1.Invoke(showStatusInfoCallBack,"接收了"+receiveCount+"條消息.");
        }
        private void closeAll()
        {
            if (br != null)
            {
                br.Close();
            }
            if (bw != null)
            {
                bw.Close();
            }
            if (tcpClient != null)
            {
                tcpClient.Close();
            }
        }
        private void whenExceptionOcur()
        {
            closeAll();
            toolStripContainer1.Invoke(showStatusInfoCallBack, "鏈接斷開");
            toolStripContainer1.Invoke(showProgressProCallBack, 0);
            DateTime now = DateTime.Now;
            while (now.AddSeconds(2) > DateTime.Now) { }
            Thread threadAccept = new Thread(AcceptClientConnect);
            threadAccept.Start();
        }
        private void sendButton_Click(object sender, EventArgs e)
        {
            sendCount = int.Parse(sendTextBox.Text);
            toolStripProgressProc.Maximum = sendCount;
            toolStripProgressProc.Value = 0;
            Thread threadSend = new Thread(new ParameterizedThreadStart(sendMessage));
            threadSend.Start(sendedTextBox.Text);
        }

        private void sendMessage(object obj)
        {
            string sendText = obj.ToString();
            toolStripContainer1.Invoke(showStatusInfoCallBack,"正在發送......");
            try
            {
                bw.Write(sendText);
                //後續操做進行進度顯示
                toolStripContainer1.Invoke(showStatusInfoCallBack, "完畢");
                sendTextBox.Invoke(sendTextBoxCallBack);
                DateTime now = DateTime.Now;
                while (now.AddSeconds(2) > DateTime.Now) { }
                bw.Flush();
             }
             catch (Exception e)
            {
                showMessageListBox.Invoke(showMsgForViewCallBack,"發送時:"+e.ToString());
                whenExceptionOcur();
            }
        }

        private void disconnectButton_Click(object sender, EventArgs e)
        {
            //也能夠用
            whenExceptionOcur();
        }

        private void clearButton_Click(object sender, EventArgs e)
        {
            showMessageListBox.Items.Clear();
        }

        private void closeListenButton_Click(object sender, EventArgs e)
        {
            tcpListener.Stop();
        }
    }
}

    客戶端:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

//添加的引用
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.IO;

namespace SyncTCPClient
{
    public partial class SyncTCPClientForm : Form
    {
        private TcpClient tcpClient;
        private NetworkStream networkStream;
        private BinaryReader br;
        private BinaryWriter bw;
        private int sendCount = 1;
        private int receiveCount = 10;

        private IPAddress serverIP;
        private int serverPort;

        /*----------聲明用於方法回調的委託----------*/
        //用於ListBox顯示消息
        private delegate void ShowMsgForViewCallBack(string str);
        private ShowMsgForViewCallBack showMsgForViewCallBack;
        //用於toolStripLabel顯示當前窗體的狀態
        private delegate void ShowStatusInfoCallBack(string str);
        private ShowStatusInfoCallBack showStatusInfoCallBack;
        //用於toolStrioProgressBar顯示當前進度
        private delegate void ShowProgressProCallBack(int progress);
        private ShowProgressProCallBack showProgressProCallBack;
        //用於重置消息文本
        private delegate void ResetMessageTextCallBack();
        private ResetMessageTextCallBack resetMessageTextCallBack;

        //本身添加的兩個委託,用於標識已發送或接受的數據個數
        private delegate void SendTextBoxCallBack();
        private SendTextBoxCallBack sendTextBoxCallBack;

        private delegate void ReceiveTextBoxCallBack(int count);
        private ReceiveTextBoxCallBack receiveTextBoxCallBack;
        public SyncTCPClientForm()
        {
            InitializeComponent();
            IPAddress[] serverIPS = Dns.GetHostAddresses("");
            serverIP = serverIPS[3];
            serverIPTextBox.Text = serverIP.ToString();
            serverPortTextBox.Text = "18888";
            serverPort =int.Parse(serverPortTextBox.Text);
            serverIPTextBox.SelectAll();
            sendTextBox.Text = sendCount.ToString();
            receiveTextBox.Text = receiveCount.ToString();
            toolStripProgressProc.Minimum = 0;
            toolStripProgressProc.Maximum = 10;
            showMsgForViewCallBack = new ShowMsgForViewCallBack(showMessageForListBox);
            showStatusInfoCallBack = new ShowStatusInfoCallBack(showStatusInfo);
            showProgressProCallBack = new ShowProgressProCallBack(showStatusProgress);
            resetMessageTextCallBack = new ResetMessageTextCallBack(resetListViewItems);
            //本身加的
            sendTextBoxCallBack = new SendTextBoxCallBack(sendTextAdd);
            receiveTextBoxCallBack = new ReceiveTextBoxCallBack(receiveTextSubtract);
        }
        private void receiveTextSubtract(int count)
        {
            receiveTextBox.Text = count.ToString();
        }
        private void sendTextAdd()
        {
            sendCount++;
            sendTextBox.Text = sendCount.ToString() ;
        }
        private void showMessageForListBox(string str)
        {
            showMessageListBox.Items.Add(str);
            showMessageListBox.TopIndex = showMessageListBox.Items.Count - 1;
        }
        private void showStatusInfo(string str)
        {
            toolStripStatusInfo.Text = str;
        }
        private void showStatusProgress(int progress)
        {
            toolStripProgressProc.Value = progress;
        }
        private void resetListViewItems()
        {
            showMessageListBox.Text = "";
            showMessageListBox.Focus();
        }

        private void connectButton_Click(object sender, EventArgs e)
        {
            //toolStripContainer1.Invoke(showProgressProCallBack,);
            toolStripProgressProc.Maximum = 10;
            toolStripProgressProc.Value = 0;
            //經過一個線程發起鏈接請求
            Thread threadConnnect = new Thread(ConnectToServer);
            threadConnnect.Start();
        }
        private void ConnectToServer()
        {
            try
            {
                toolStripContainer1.Invoke(showStatusInfoCallBack,"正在鏈接......");
                //IPHostEntry remoteHost = Dns.GetHostEntry(serverIPTextBox.Text);
                tcpClient = new TcpClient();
                toolStripContainer1.Invoke(showProgressProCallBack,1);
                tcpClient.Connect(serverIP,serverPort);
                //tcpClient.Connect(remoteHost,serverPort);
                toolStripContainer1.Invoke(showProgressProCallBack, 10);
                //間歇延時
                DateTime now = DateTime.Now;
                while (now.AddSeconds(1) > DateTime.Now) { }
                if(tcpClient!=null)
                {
                    toolStripContainer1.Invoke(showStatusInfoCallBack,"鏈接成功......");
                    networkStream = tcpClient.GetStream();
                    br = new BinaryReader(networkStream);
                    bw = new BinaryWriter(networkStream);
                }

            }catch(Exception e)
            {
                showMessageListBox.Invoke(showMsgForViewCallBack,e.ToString());
                toolStripContainer1.Invoke(showStatusInfoCallBack, "鏈接失敗......");
                //間歇延時
                DateTime now = DateTime.Now;
                while (now.AddSeconds(1) > DateTime.Now) { }
                toolStripContainer1.Invoke(showProgressProCallBack, 0);
                toolStripContainer1.Invoke(showStatusInfoCallBack, "就緒");
            }
        }

        private void receiveButton_Click(object sender, EventArgs e)
        {
            receiveCount = int.Parse(receiveTextBox.Text);
            toolStripProgressProc.Maximum = receiveCount;
            toolStripProgressProc.Value = 0;
            Thread threadReceive = new Thread(ReceiveMessage);
            threadReceive.Start();
        }
        private void ReceiveMessage(object obj)
        {
            toolStripContainer1.Invoke(showStatusInfoCallBack, "接收中");
            for (int i = 0; i < receiveCount; i++)
            {
                try
                {
                    string receiveMessageStr = br.ReadString();
                    //後續操做進行進度顯示
                    toolStripContainer1.Invoke(showProgressProCallBack, i + 1);
                    receiveTextBox.Invoke(receiveTextBoxCallBack,10-i-1);
                    if (receiveMessageStr != null)
                    {
                        showMessageListBox.Invoke(showMsgForViewCallBack, receiveMessageStr);
                    }
                }
                catch (Exception e)
                {
                    showMessageListBox.Invoke(showMsgForViewCallBack, "接收時:" + e.ToString());
                    closeAll();
                    toolStripContainer1.Invoke(showStatusInfoCallBack, "鏈接斷開......");
                    toolStripContainer1.Invoke(showProgressProCallBack, 0);
                    break;
                }
            }
            toolStripContainer1.Invoke(showStatusInfoCallBack, "接收了" + receiveCount + "條消息.");
        }
        private void closeAll()
        {
            if (br != null)
            {
                br.Close();
            }
            if (bw != null)
            {
                bw.Close();
            }
            if (tcpClient != null)
            {
                tcpClient.Close();
            }
        }

        private void clearButton_Click(object sender, EventArgs e)
        {
            showMessageListBox.Items.Clear();
        }
        private void disconnectButton_Click(object sender, EventArgs e)
        {
            closeAll();
            toolStripContainer1.Invoke(showStatusInfoCallBack, "鏈接斷開......");
            toolStripContainer1.Invoke(showProgressProCallBack, 0);
        }
        private void sendButton_Click(object sender, EventArgs e)
        {
            sendCount = int.Parse(sendTextBox.Text);
            toolStripProgressProc.Maximum = sendCount;
            toolStripProgressProc.Value = 0;
            Thread threadSend = new Thread(new ParameterizedThreadStart(sendMessage));
            threadSend.Start(sendedText.Text);
        }
        private void sendMessage(object obj)
        {
            string sendText = obj.ToString();
            toolStripContainer1.Invoke(showStatusInfoCallBack, "正在發送......");
                try
                {
                    bw.Write(sendText);
                    //後續操做進行進度顯示
                    sendTextBox.Invoke(sendTextBoxCallBack);
                    DateTime now = DateTime.Now;
                    while (now.AddSeconds(1) > DateTime.Now) { }
                    bw.Flush();
                }
                catch (Exception e)
                {
                    showMessageListBox.Invoke(showMsgForViewCallBack, "發送時:" + e.ToString());
                    Close();
                    toolStripContainer1.Invoke(showStatusInfoCallBack, "鏈接斷開......");
                    toolStripContainer1.Invoke(showProgressProCallBack, 0);
                }
            toolStripContainer1.Invoke(showStatusInfoCallBack, "完畢");
        }
    }
}

    實驗效果:

  

    2)TCP異步:

    服務端:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.IO;

namespace ASyncTcpServer
{
    public partial class frmAsyncTcpServer : Form
    {
        private IPAddress localAddress;
        private const int port =52888;
        private TcpListener tcpListener;
        private TcpClient tcpClient;
        private NetworkStream networkStream;
        private BinaryReader br;
        private BinaryWriter bw;
        private int sendCount = 1;
        private int receiveCount = 10;
        /*------------聲明委託------------*/
        //顯示消息
        private delegate void ShwMsgforViewCallBack(string str);
        private ShwMsgforViewCallBack shwMsgforViewCallBack;
        //顯示狀態
        private delegate void ShwStatusInfoCallBack(string str);
        private ShwStatusInfoCallBack shwStatusInfoCallBack;
        //顯示進度
        private delegate void ShwProgressProcCallBack(int progress);
        private ShwProgressProcCallBack shwProgressProcCallBack;
        //重置消息文本
        private delegate void ResetMsgTxtCallBack();
        private ResetMsgTxtCallBack resetMsgTxtCallBack;
        /*------------聲明委託------------*/
       // 異步調用(與要調用的的方法具備相同簽名)
        private delegate void ReceiveMessageDelegate(out string receiveMessage);
        private ReceiveMessageDelegate receiveMessageDelegate;
        private delegate void SendMessageDelegate(string sendMessage);
        private SendMessageDelegate sendMessageDelegate;
        public frmAsyncTcpServer()
        {
            InitializeComponent();
            /*----------定義委託----------*/
            //顯示消息
            shwMsgforViewCallBack = new ShwMsgforViewCallBack(ShwMsgforView);
            //顯示狀態
            shwStatusInfoCallBack = new ShwStatusInfoCallBack(ShwStatusInfo);
            //顯示進度
            shwProgressProcCallBack = new ShwProgressProcCallBack(ShwProgressProc);
            //重置消息文本
            resetMsgTxtCallBack = new ResetMsgTxtCallBack(ResetMsgTxt);
            /*----------定義委託----------*/
            receiveMessageDelegate = new ReceiveMessageDelegate(AsyncRcvMsg);//接收消息
            sendMessageDelegate = new SendMessageDelegate(AsyncSndMsg);//發送消息
            IPAddress[] listenIp = Dns.GetHostAddresses("");
            localAddress = listenIp[3];
            tbxSendCount.Text = sendCount.ToString();
            tbxReceiveCount.Text = receiveCount.ToString();
            toolStripProgressProc.Minimum = 0;
        }

        /*----------定義回調函數----------*/
        //顯示消息
        private void ShwMsgforView(string str)
        {
            lstbxMsgView.Items.Add(str);
            lstbxMsgView.TopIndex = lstbxMsgView.Items.Count - 1;
        }

        //顯示狀態
        private void ShwStatusInfo(string str)
        {
            toolStripStatusInfo.Text = str;
        }

        //顯示進度
        private void ShwProgressProc(int progress)
        {
            toolStripProgressProc.Value = progress;
        }

        //重置消息文本
        private void ResetMsgTxt()
        {
            tbxMsg.Text = "";
            tbxMsg.Focus();
        }
        /*----------定義回調函數----------*/
        private void AsyncRcvMsg(out string receiveMessage)
        {
            receiveMessage = null;
            try
            {
                receiveMessage = br.ReadString();
            }
            catch
            {
                if (br != null)
                {
                    br.Close();
                }
                if (bw != null)
                {
                    bw.Close();
                }
                if (tcpClient != null)
                {
                    tcpClient.Close();
                }
                statusStripInfo.Invoke(shwStatusInfoCallBack, "鏈接斷開!");
                statusStripInfo.Invoke(shwProgressProcCallBack, 0);
            }
        }
        private void AsyncSndMsg(string sendMessage)
        {
            try
            {
                bw.Write(sendMessage);
                DateTime now = DateTime.Now;
                while (now.AddSeconds(5) > DateTime.Now) { }
                bw.Flush();

            }
            catch
            {
                if (br != null)
                {
                    br.Close();
                }
                if (bw != null)
                {
                    bw.Close();
                }
                if (tcpClient != null)
                {
                    tcpClient.Close();
                }
                statusStripInfo.Invoke(shwStatusInfoCallBack, "鏈接斷開!");
                statusStripInfo.Invoke(shwProgressProcCallBack, 0);
            }
        }
        private void btnStart_Click(object sender, EventArgs e)
        {
            tcpListener = new TcpListener(localAddress, port);
            tcpListener.Start();
            toolStripProgressProc.Maximum = 100;
            toolStripProgressProc.Value = 0;
            //啓動一個線程接受請求
            Thread threadAccept = new Thread(AcceptClientConnect);
            threadAccept.Start();
        }

        //接受請求
        private void AcceptClientConnect()
        {
            statusStripInfo.Invoke(shwStatusInfoCallBack, "[" + localAddress + ":" + port + "]偵聽...");
            //間歇延時
            DateTime nowtime = DateTime.Now;
            while (nowtime.AddSeconds(1) > DateTime.Now) { }
            AsyncCallback acceptcallback=new AsyncCallback(AcceptClientCallBack);
            statusStripInfo.Invoke(shwStatusInfoCallBack, "等待鏈接...");
            statusStripInfo.Invoke(shwProgressProcCallBack, 1);
            IAsyncResult result=tcpListener.BeginAcceptTcpClient(acceptcallback,tcpListener);
            int i=2;
            while(result.IsCompleted==false){
                  statusStripInfo.Invoke(shwProgressProcCallBack,i);
                  i++;
                  if(i==10){
                      i=0;
                  }
                Thread.Sleep(30);
            }
        }
        private void AcceptClientCallBack(IAsyncResult iar){
             try{
                     tcpListener=(TcpListener)iar.AsyncState;
                     tcpClient=tcpListener.EndAcceptTcpClient(iar);
                     //後續操做進度顯示
                    statusStripInfo.Invoke(shwProgressProcCallBack, 100);
                if (tcpClient != null)
                {
                    statusStripInfo.Invoke(shwStatusInfoCallBack, "接受了一個鏈接!");
                    networkStream = tcpClient.GetStream();
                    br = new BinaryReader(networkStream);
                    bw = new BinaryWriter(networkStream);
                }
            }
            catch
            {
                statusStripInfo.Invoke(shwStatusInfoCallBack, "中止偵聽。");
                //間歇延時
                DateTime now = DateTime.Now;
                while (now.AddSeconds(1) > DateTime.Now) { }
                statusStripInfo.Invoke(shwProgressProcCallBack, 0);
                statusStripInfo.Invoke(shwStatusInfoCallBack, "就緒");
            }
        }
        private void btnReceive_Click(object sender, EventArgs e)
        {
            receiveCount = int.Parse(tbxReceiveCount.Text);
            toolStripProgressProc.Maximum = receiveCount;
            toolStripProgressProc.Value = 0;
            Thread threadReceive = new Thread(ReceiveMessage);
            threadReceive.Start();
        }

        //接收消息
        private void ReceiveMessage()
        {
            statusStripInfo.Invoke(shwStatusInfoCallBack, "接收中...");
            string receiveString = null;
            for (int i = 0; i < receiveCount; i++)
            {
                try
                {
                    IAsyncResult result = receiveMessageDelegate.BeginInvoke(out receiveString, null, null);
                    int j = 1;
                    while (result.IsCompleted == false)
                    {
                        statusStripInfo.Invoke(shwProgressProcCallBack, j);
                        j++;
                        if (j == receiveCount)
                        {
                            j = 0;
                        }
                        Thread.Sleep(500);
                    }
                    receiveMessageDelegate.EndInvoke(out receiveString, result);
                    statusStripInfo.Invoke(shwProgressProcCallBack, receiveCount);
                    if (receiveString != null)
                    {
                        lstbxMsgView.Invoke(shwMsgforViewCallBack, receiveString);
                    }
                }
                catch
                {

                    DateTime now = DateTime.Now;
                    while (now.AddSeconds(2) > DateTime.Now) { }
                    Thread threadAccept = new Thread(AcceptClientConnect);
                    threadAccept.Start();
                    break;
                }
            }
            statusStripInfo.Invoke(shwStatusInfoCallBack, "接收了" + receiveCount + "條消息.");
        }
        

        private void btnSend_Click(object sender, EventArgs e)
        {
            sendCount = int.Parse(tbxSendCount.Text);
            toolStripProgressProc.Maximum = sendCount;
            toolStripProgressProc.Value = 0;
            Thread threadSend = new Thread(new ParameterizedThreadStart(SendMessage));
            threadSend.Start(tbxMsg.Text);
        }

        //發送消息
        private void SendMessage(object state)
        {
            statusStripInfo.Invoke(shwStatusInfoCallBack, "正在發送...");
            for (int i = 0; i < sendCount; i++)
            {
                try
                {
                    IAsyncResult result = sendMessageDelegate.BeginInvoke(state.ToString(), null, null);
                    while (result.IsCompleted == false)
                    {
                        Thread.Sleep(30);
                    }
                    sendMessageDelegate.EndInvoke(result);
                    statusStripInfo.Invoke(shwProgressProcCallBack, i + 1);
                }
                catch
                {
                    DateTime now = DateTime.Now;
                    while (now.AddSeconds(2) > DateTime.Now) { }
                    Thread threadAccept = new Thread(AcceptClientConnect);
                    threadAccept.Start();
                    break;
                }

            }
            statusStripInfo.Invoke(shwStatusInfoCallBack, "完畢");
            //間歇延時
            DateTime nowtime = DateTime.Now;
            while (nowtime.AddSeconds(1) > DateTime.Now) { }
            statusStripInfo.Invoke(shwProgressProcCallBack, 0);
            tbxMsg.Invoke(resetMsgTxtCallBack, null);
        }
        private void btnDisconnect_Click(object sender, EventArgs e)
        {
            if (br != null)
            {
                br.Close();
            }
            if (bw != null)
            {
                bw.Close();
            }
            if (tcpClient != null)
            {
                tcpClient.Close();
            }
            toolStripStatusInfo.Text = "鏈接斷開!";
            toolStripProgressProc.Maximum = 100;
            toolStripProgressProc.Value = 0;
            //間歇延時
            DateTime now = DateTime.Now;
            while (now.AddSeconds(2) > DateTime.Now) { }
            //重啓一個線程等待接受新的請求
            Thread threadAccept = new Thread(AcceptClientConnect);
            threadAccept.Start();
        }

        private void btnStop_Click(object sender, EventArgs e)
        {
            tcpListener.Stop();
        }

        private void btnClear_Click(object sender, EventArgs e)
        {
            lstbxMsgView.Items.Clear();
        }
    }
}

    客戶端:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.IO;

namespace ASyncTcpClient
{
    public partial class frmAsyncTcpClient : Form
    {
        private TcpClient tcpClient;
        private NetworkStream networkStream;
        private BinaryReader br;
        private BinaryWriter bw;
        private int sendCount = 1;
        private int receiveCount = 10;
        /*------------聲明委託------------*/
        //顯示消息
        private delegate void ShwMsgforViewCallBack(string str);
        private ShwMsgforViewCallBack shwMsgforViewCallBack;
        //顯示狀態
        private delegate void ShwStatusInfoCallBack(string str);
        private ShwStatusInfoCallBack shwStatusInfoCallBack;
        //顯示進度
        private delegate void ShwProgressProcCallBack(int progress);
        private ShwProgressProcCallBack shwProgressProcCallBack;
        //重置消息文本
        private delegate void ResetMsgTxtCallBack();
        private ResetMsgTxtCallBack resetMsgTxtCallBack;
        /*------------聲明委託------------*/
        private delegate void ReceiveMessageDelegate(out string receiveMessage);
        private ReceiveMessageDelegate receiveMessageDelegate;
        private delegate void SendMessageDelegate(string sendMessage);
        private SendMessageDelegate sendMessageDelegate;

        public frmAsyncTcpClient()
        {
            InitializeComponent();
            /*----------定義委託----------*/
            //顯示消息
            shwMsgforViewCallBack = new ShwMsgforViewCallBack(ShwMsgforView);
            //顯示狀態
            shwStatusInfoCallBack = new ShwStatusInfoCallBack(ShwStatusInfo);
            //顯示進度
            shwProgressProcCallBack = new ShwProgressProcCallBack(ShwProgressProc);
            //重置消息文本
            resetMsgTxtCallBack = new ResetMsgTxtCallBack(ResetMsgTxt);
            receiveMessageDelegate = new ReceiveMessageDelegate(AsyncRcvMsg);//接收消息
            sendMessageDelegate = new SendMessageDelegate(AsyncSndMsg);//發送消息

            /*----------定義委託----------*/
            IPAddress[] serverIp = Dns.GetHostAddresses("");
            tbxSrvIp.Text = serverIp[3].ToString();
            tbxSrvIp.SelectAll();
            tbxPort.Text = "52888";
            tbxSendCount.Text = sendCount.ToString();
            tbxReceiveCount.Text = receiveCount.ToString();
            toolStripProgressProc.Minimum = 0;
        }

        /*----------定義回調函數----------*/
        //顯示消息
        private void ShwMsgforView(string str)
        {
            lstbxMsgView.Items.Add(str);
            lstbxMsgView.TopIndex = lstbxMsgView.Items.Count - 1;
        }

        //顯示狀態
        private void ShwStatusInfo(string str)
        {
            toolStripStatusInfo.Text = str;
        }

        //顯示進度
        private void ShwProgressProc(int progress)
        {
            toolStripProgressProc.Value = progress;
        }

        //重置消息文本
        private void ResetMsgTxt()
        {
            tbxMsg.Text = "";
            tbxMsg.Focus();
        }
        /*----------定義回調函數----------*/
        //異步方法
        private void AsyncRcvMsg(out string receiveMessage)
        {
            receiveMessage = null;
            try
            {
                receiveMessage = br.ReadString();
            }
            catch
            {
                if (br != null)
                {
                    br.Close();
                }
                if (bw != null)
                {
                    bw.Close();
                }
                if (tcpClient != null)
                {
                    tcpClient.Close();
                }
                statusStripInfo.Invoke(shwStatusInfoCallBack, "鏈接斷開!");
                statusStripInfo.Invoke(shwProgressProcCallBack, 0);
            }
        }
        private void AsyncSndMsg(string sendMessage)
        {
            try
            {
                bw.Write(sendMessage);
                DateTime now= DateTime.Now;
                while(now.AddSeconds(5)>DateTime.Now){}
                bw.Flush();

            }
            catch
            {
                if (br != null)
                {
                    br.Close();
                }
                if (bw != null)
                {
                    bw.Close();
                }
                if (tcpClient != null)
                {
                    tcpClient.Close();
                }
                statusStripInfo.Invoke(shwStatusInfoCallBack, "鏈接斷開!");
                statusStripInfo.Invoke(shwProgressProcCallBack, 0);
            }
        }
        private void btnConnect_Click(object sender, EventArgs e)
        {
            toolStripProgressProc.Maximum = 100;
            toolStripProgressProc.Value = 0;
            //經過一個線程發起請求
            Thread threadConnect = new Thread(ConnectoServer);
            threadConnect.Start();
        }

        //發起鏈接請求
        private void ConnectoServer()
        {
            AsyncCallback requestcallback = new AsyncCallback(RequestCallBack);
            statusStripInfo.Invoke(shwStatusInfoCallBack, "正在鏈接...");
            statusStripInfo.Invoke(shwProgressProcCallBack, 1); 
            tcpClient = new TcpClient(AddressFamily.InterNetwork);
            IAsyncResult result=tcpClient.BeginConnect(IPAddress.Parse(tbxSrvIp.Text),int.Parse(tbxPort.Text),requestcallback,tcpClient);
            while(result.IsCompleted==false){
                Thread.Sleep(30);
            }      
        }
        //回調函數,用於向服務進程發起鏈接請求
          private void RequestCallBack(IAsyncResult iar){
                 try{
                     tcpClient=(TcpClient)iar.AsyncState;
                     tcpClient.EndConnect(iar);
                     //後續操做進度顯示
                    statusStripInfo.Invoke(shwProgressProcCallBack, 100);
                //間歇延時
                DateTime nowtime = DateTime.Now;
                while (nowtime.AddSeconds(1) > DateTime.Now) { }
                if (tcpClient != null)
                {
                    statusStripInfo.Invoke(shwStatusInfoCallBack, "鏈接成功!");
                    networkStream = tcpClient.GetStream();
                    br = new BinaryReader(networkStream);
                    bw = new BinaryWriter(networkStream);
                }
            }
            catch
            {
                statusStripInfo.Invoke(shwStatusInfoCallBack, "鏈接失敗!");
                //間歇延時
                DateTime now = DateTime.Now;
                while (now.AddSeconds(1) > DateTime.Now) { }
                statusStripInfo.Invoke(shwProgressProcCallBack, 0);
                statusStripInfo.Invoke(shwStatusInfoCallBack, "就緒");
            }
}
        private void btnReceive_Click(object sender, EventArgs e)
        {
            receiveCount = int.Parse(tbxReceiveCount.Text);
            toolStripProgressProc.Maximum = receiveCount;
            toolStripProgressProc.Value = 0;
            Thread threadReceive = new Thread(ReceiveMessage);
            threadReceive.Start();
        }

        //接收消息
        private void ReceiveMessage()
        {
            statusStripInfo.Invoke(shwStatusInfoCallBack, "接收中...");
            string receiveString = null;
            for (int i = 0; i < receiveCount; i++)
            {
                try
                {
                    IAsyncResult result = receiveMessageDelegate.BeginInvoke(out receiveString, null, null);
                    int j = 1;
                    while (result.IsCompleted == false)
                    {
                        statusStripInfo.Invoke(shwProgressProcCallBack, j);
                        j++;
                        if (j == receiveCount)
                        {
                            j = 0;
                        }
                        Thread.Sleep(500);
                    }
                    receiveMessageDelegate.EndInvoke(out receiveString, result);
                    statusStripInfo.Invoke(shwProgressProcCallBack, receiveCount);
                    if (receiveString != null)
                    {
                        lstbxMsgView.Invoke(shwMsgforViewCallBack, receiveString);
                    }
                }
                catch
                {

                    DateTime now = DateTime.Now;
                    while (now.AddSeconds(2) > DateTime.Now) { }
                    break;
                }
            }
            statusStripInfo.Invoke(shwStatusInfoCallBack, "接收了" + receiveCount + "條消息.");
        }

        private void btnSend_Click(object sender, EventArgs e)
        {
            sendCount = int.Parse(tbxSendCount.Text);
            toolStripProgressProc.Maximum = sendCount;
            toolStripProgressProc.Value = 0;
            Thread threadSend = new Thread(new ParameterizedThreadStart(SendMessage));
            threadSend.Start(tbxMsg.Text);
        }

        //發送消息
        private void SendMessage(object state)
        {
            statusStripInfo.Invoke(shwStatusInfoCallBack, "正在發送...");
            for (int i = 0; i < sendCount; i++)
            {
                try
                {
                    IAsyncResult result = sendMessageDelegate.BeginInvoke(state.ToString(), null, null);
                    while (result.IsCompleted == false)
                    {
                        Thread.Sleep(30);
                    }
                    sendMessageDelegate.EndInvoke(result);
                    statusStripInfo.Invoke(shwProgressProcCallBack, i + 1);
                }
                catch{
                      DateTime now=DateTime.Now;
                    while(now.AddSeconds(2)>DateTime.Now){}
                    break;
                }
                   
            }
            statusStripInfo.Invoke(shwStatusInfoCallBack, "完畢");
            //間歇延時
            DateTime nowtime = DateTime.Now;
            while (nowtime.AddSeconds(1) > DateTime.Now) { }
            statusStripInfo.Invoke(shwProgressProcCallBack, 0);
            tbxMsg.Invoke(resetMsgTxtCallBack, null);
        }

        private void btnDisconnect_Click(object sender, EventArgs e)
        {
            if (br != null)
            {
                br.Close();
            }
            if (bw != null)
            {
                bw.Close();
            }
            if (tcpClient != null)
            {
                tcpClient.Close();
            }
            toolStripStatusInfo.Text = "鏈接斷開!";
            toolStripProgressProc.Maximum = 100;
            toolStripProgressProc.Value = 0;
            DateTime nowtime = DateTime.Now;
            while (nowtime.AddSeconds(2) > DateTime.Now) { }
           
        }

        private void btnClear_Click(object sender, EventArgs e)
        {
            lstbxMsgView.Items.Clear();
        }
    }
}

    顯示結果:

  

     注意:這裏並不支持IPV6的地址,所以要注意取本機的Ip地址集時要選對Ip地址。

 

    (6)異步TCP程序設計:

    使用異步操做方式設計程序就是異步程序設計。異步程序設計有兩種模式:

1.基於事件
(1)封裝了異步編程的複雜性,簡化了設計難度
(2)屏蔽了異步操做原理
2.基於IAsyncResult
(1)提供了更靈活的控制功能
(2)經過前綴分別爲Begin和End的兩個方法實現開始和結束異步操做
(3)每一個Begin方法都必須有一個與其對應的End方法
(4)程序在調用Begin方法後,調用該方法的線程會繼續執行下面的語句,同時該方法用另外一個單獨的線程執行異步操做,當異步操做完成後,會返回一個實現IAsyncResult接口的對象。
(5)調用Begin方法後,應該調用End方法來結束異步操做。

    1)基於IAsyncResult的異步設計模式:

    TcpListener和TcpClient除了提供同步模式下的對應的方法外,還爲基於IAsyncResult的異步設計模式提供了相應的方法。

    基本原理:

    基於IAsyncResult的異步設計模式經過前綴分別爲Begin和End的兩個方法實現開始和結束異步操做,每一個Begin方法都必須有一個與之對應的End方法。程序在調用Begin方法後,調用該方法的線程會繼續執行下面的語句,同時該方法用另外一個單獨的線程執行異步操做,當異步操做完成後,會返回一個實現IAsyncResult接口的對象,該對象存儲了有關異步操做的信息:

IAsyncResult的屬性:
(1)AsyncState
獲取用戶定義的對象,它限定或包含關於異步操做的信息。 
(2)AsyncWaitHandle
獲取用於等待異步操做完成的 WaitHandle。 
(3)CompletedSynchronously
獲取異步操做是否同步完成的指示。 
(4)IsCompleted
獲取異步操做是否已完成的指示。

    AsyncCallback委託:

    AsyncCallback委託用於在異步操做完成時調用指定的回調方法。在基於IAsyncResult的異步操做方式下,程序能夠再啓動異步操做後執行其它代碼,所以必須有一種機制,以保證該異步操做完成時可以及時通知調用者。AsyncCallback委託就是爲實現這種機制提供的。

    回調方法是在程序中事先定義的,在回調方法中,經過End方法得到Begin方法的返回值和全部輸入或輸出參數,從而達到在異步操做方式下的參數傳遞的目的。

public delegate void AsyncCallback( IAsyncResult ar)使用 AsyncCallback 委託在一個單獨的線程中處理異步操做的結果。
回調方法採用 IAsyncResult 參數,該參數隨後可用來獲取異步操做的結果。

    異步設計模式控制同步問題:

    基於IAsyncResult的異步設計模式控制同步問題很是麻煩,並且代碼難以理解,所以在實際設計中通常不採用AsyncCallback委託處理異步操做的結果,而是採用輪詢方式判斷異步操做是否完成。思路:調用Begin方法獲得IAsyncResult對象,再循環判斷該對象的IsCompleted屬性決定操做是否完成。(這時將Begin方法的AsyncCallback參數設置爲null便可)

    2)異步Tcp編程經常使用方法:

    

    BeginAcceptTcpClient:

開始一個異步操做來接受一個傳入的鏈接嘗試。
public IAsyncResult BeginAcceptTcpClient(
    AsyncCallback callback,
    Object state)
參數:
一個 AsyncCallback 委託,它引用操做完成時要調用的方法。
一個用戶定義對象,其中包含接收操做的相關信息。當操做完成時,此對象會被傳遞給 callback 委託。
返回值:
一個 IAsyncResult,它引用 TcpClient 的異步建立。

    EndAcceptTcpClient:

異步接受傳入的鏈接嘗試,並建立新的 TcpClient 來處理遠程主機通訊。
public TcpClient EndAcceptTcpClient(
    IAsyncResult asyncResult)
參數:
BeginAcceptTcpClient 方法調用返回的 IAsyncResult。
返回值:
TcpClient 。

    BeginConnect:

開始一個對遠程主機鏈接的異步請求。
BeginConnect(IPAddress, Int32, AsyncCallback, Object)
開始一個對遠程主機鏈接的異步請求。遠程主機由 IPAddress 和端口號 (Int32) 指定。 
BeginConnect(IPAddress[], Int32, AsyncCallback, Object)
開始一個對遠程主機鏈接的異步請求。遠程主機由 IPAddress 數組和端口號 (Int32) 指定。 
BeginConnect(String, Int32, AsyncCallback, Object)
開始一個對遠程主機鏈接的異步請求。遠程主機由主機名 (String) 和端口號 (Int32) 指定。
返回值:IAsyncResult 。

    EndConnect:

異步接受傳入的鏈接嘗試。
public void EndConnect(
    IAsyncResult asyncResult)
參數:
BeginConnect 調用所返回的 IAsyncResult 對象。

    3)異步收發數據

    用NetWorkStream對象的BeginRead和BeginWrite方法需解決TCP的無消息邊界問題,很是麻煩。

    TCP的無消息邊界:

    雖然採用TCP協議通訊時,接收方可以按照發送方發送的順序接收數據,可是在網絡傳輸中,可能會出現發送方一次發送的消息與接收方一次接收的消息不一致的現象:

發送方第一次發送的字符串數據爲「12345」,第二次發送的字符串數據爲「abcde」:
1.正常狀況下,接收方接收的字符串應該是第一次接收:「12345」,第二次接收:「abcde」。 2.當收發信息速度很是快時,接收方也可能一次接收到的內容就是「12345abcde」,即兩次或者屢次發送的內容一塊兒接收。 接收方也可能會通過屢次才能接收到發送方發送的消息。例如第一次接收到「1234」,第二次爲「45ab」,第三次爲「cde」。

    由於TCP協議是字節流形式的、無消息邊界的協議,因爲受網絡傳輸中的不肯定因素的影響,所以不能保證單個Send方法發送的數據被單個Receive方法讀取。

    解決TCP協議消息邊界問題的方法:

1.第一種方法是發送固定長度的消息。
BinaryReader和BinaryWriter對象提供了多種重載方法,發送和接收具備固定長度類型的數據很是方便。
2.第二種方法是將消息長度與消息一塊兒發送。
BinaryReader對象和BinaryWriter對象一樣是實現這種方法的最方便的途徑。
3.第三種方法是使用特殊標記分隔消息。例如用回車換行(\r\n)做爲分隔符。這種方法主要用於消息中不包含特殊標記的場合。

    解決方法:(用BinaryReader和BinaryWriter類)

提供同步的方法
使用異步方式調用同步方法

    4)異步方式調用同步方法:

    步驟:

1.聲明一個與要調用的方法具備相同簽名的委託
2.調用委託的BeginInvoke方法開始異步執行
3.調用委託的EndInvoke方法結束異步操做

    聲明委託:

private BinaryWriter bw;
......
private delegate void SendMessageDelegate(string sendMessage);//定義
private SendMessageDelegate sendMessageDelegate;//聲明
sendMessageDelegate = new SendMessageDelegate(AsyncSndMsg);//實例化
//調用方法
private void AsyncSndMsg(string sendMessage)
{    
       bw.Write(sendMessage);
    bw.Flush();        
}

    調用BeginInvoke方法:

委託的BeginInvoke方法
參數:
1.與異步執行方法的參數相同
2.可選。一個 AsyncCallback 委託,該委託引用在異步調用完成時要調用的方法。
3.可選。一個用戶定義的對象,該對象可向回調方法傳遞信息。
返回值:
IAsyncResult,可用於監視異步調用進度。
private bool needExit;
…
IAsyncResult result = sendMessageDelegate.BeginInvoke(sendMessage, null, null);
while (result.IsCompleted == false)
{    if (needExit)
    {    break;    }
    Thread.Sleep (50);
}

    調用EndInvoke方法:

Endlnvoke方法用於檢索異步調用的結果,並結束異步調用。
調用Beginlnvoke以後,隨時能夠調用該方法。
若是異步調用還沒有完成,則Endlnvoke會一直阻止調用線程,直到異步調用完成。
例如,在退出輪詢後,能夠直接經過下面的代碼結束異步調用:
sendMessageDelegate.EndInvoke(result);

    5)四種進行異步調用的經常使用方法

    調用 BeginInvoke 以後:

a.進行某些操做,而後調用 EndInvoke 一直阻止到調用完成。
b.使用 IAsyncResult.AsyncWaitHandle 屬性獲取 WaitHandle,使用它的 WaitOne 方法一直阻止執行直到發出 WaitHandle 信號,而後調用 EndInvoke。
c.輪詢由 BeginInvoke 返回的 IAsyncResult的IsCompleted屬性,肯定異步調用什麼時候完成,而後調用 EndInvoke。
d.將用於回調方法的委託傳遞給 BeginInvoke。異步調用完成後,將在 ThreadPool 線程上執行該方法。該回調方法將調用 EndInvoke。

    示例:

1.使用EndInvoke等待異步調用
public delegate string AsyncMethodCaller(int callDuration, out int threadId);     
AsyncMethodCaller caller = new AsyncMethodCaller(ad.TestMethod);
IAsyncResult result = caller.BeginInvoke(3000, out threadId, null, null);
Thread.Sleep(0);
Console.WriteLine("Main thread {0} does some work.",Thread.CurrentThread.ManagedThreadId);
// Call EndInvoke to wait for the asynchronous call to complete,
// and to retrieve the results.
string returnValue = caller.EndInvoke(out threadId, result);
Console.WriteLine("The call executed on thread {0}, with return value \"{1}\".",  threadId, returnValue);
2.使用WaitHandle等待異步調用
public delegate string AsyncMethodCaller(int callDuration, out int threadId);     
AsyncMethodCaller caller = new AsyncMethodCaller(ad.TestMethod);
IAsyncResult result = caller.BeginInvoke(3000, out threadId, null, null);
Thread.Sleep(0);
Console.WriteLine("Main thread {0} does some work.",
Thread.CurrentThread.ManagedThreadId);
// Wait for the WaitHandle to become signaled.
result.AsyncWaitHandle.WaitOne();
// Perform additional processing here.
// Call EndInvoke to retrieve the results.
string returnValue = caller.EndInvoke(out threadId, result);
Console.WriteLine("The call executed on thread {0}, with return value \"{1}\".",  threadId, returnValue);
3.輪詢異步調用完成
public delegate string AsyncMethodCaller(int callDuration, out int threadId);
AsyncMethodCaller caller = new AsyncMethodCaller(ad.TestMethod);
// Initiate the asychronous call.
IAsyncResult result = caller.BeginInvoke(3000, out threadId, null, null);
// Poll while simulating work.
while(result.IsCompleted == false) {
     Thread.Sleep(10);
}
// Call EndInvoke to retrieve the results.
string returnValue = caller.EndInvoke(out threadId, result);
Console.WriteLine("The call executed on thread {0}, with return value \"{1}\".",  threadId, returnValue);
4.異步調用完成時執行回調方法
public delegate string AsyncMethodCaller(int callDuration, out int threadId);          
AsyncMethodCaller caller = new AsyncMethodCaller(ad.TestMethod);
// Initiate the asychronous call.  Include an AsyncCallback
// delegate representing the callback method, and the data
// needed to call EndInvoke.
IAsyncResult result = caller.BeginInvoke(3000,out threadId, new AsyncCallback(CallbackMethod),caller );
Console.WriteLine("Press Enter to close application.");
Console.ReadLine();
// Callback method must have the same signature as the
// AsyncCallback delegate.
static void CallbackMethod(IAsyncResult ar) 
{
     // Retrieve the delegate.
     AsyncMethodCaller caller = (AsyncMethodCaller) ar.AsyncState;
     // Call EndInvoke to retrieve the results.
     string returnValue = caller.EndInvoke(out threadId, ar);
     Console.WriteLine("The call executed on thread {0}, with return value \"{1}\".", threadId, returnValue);
}

   

實驗文檔:http://files.cnblogs.com/files/MenAngel/TCP.zip

相關文章
相關標籤/搜索