網絡傳輸編程指基於各種網絡協議進行編程,包括TCP編程,UDP編程,P2P編程。本節介紹TCP編程。
(1)TCP簡介:
TCP是TCP/IP體系中最重要的傳輸層協議,它提供全雙工和可靠交付的服務,是大多數應用協議工作的基礎。作為上層應用編程的基礎,TCP編程也是最終實現應用程序網絡功能的基石。
TCP是一種面向連接的,可靠的,基於字節流的傳輸層通信協議。在TCP/IP協議棧中,它位於IP協議之上;在整個網絡協議簇中,它處於應用層諸多協議之下。由於網絡上不同主機的應用層之間經常需要可靠的,像管道一樣的連接,但是IP本身並不提供這樣的機制,故需要由TCP完成傳輸管道功能。
(2)TCP工作過程:
TCP通過停止等待協議和連續ARQ協議實現可靠傳輸,工作過程分為連接建立,傳輸數據,連接終止三個過程:
1)連接建立
TCP建立連接的過程叫做握手,握手需要在客戶和服務器之間交換三個TCP報文段。

三次握手(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
