一、首先說下計算機網絡中的TCP/IP參考模型程序員
TCP/IP把網絡分爲5層,每一層負責完成不一樣的功能編程
1)應用層:傳輸報文,提供各類網絡應用,有FTP、SMTP、HTTP等協議服務器
2)運輸層:傳輸報文段,爲應用程序的客戶機和服務器之間提供傳輸應用層報文服務,協議有TCP,UDP網絡
3)網絡層:傳輸數據包,協議有IP協議,選路協議框架
4)鏈路層:傳輸數據幀,以太網就屬於這個層異步
5)物理層:在節點之間傳輸比特流函數
應用程序是經過套接字訪問網絡下層的服務的,套接字是網絡運輸層和應用層的一個編程接口,在程序中經過套接字來進行TCP和UDP傳輸,運輸層如下的層對程序員透明this
TCP和UDP是最基本的傳輸協議,應用層的全部協議都是基於這兩個協議進行封裝擴展的spa
TCP:可靠的,面向鏈接的鏈接數據傳輸服務,傳輸的是字節流,能保證數據的有序性.net
1)創建鏈接(三次握手) 2)傳輸數據 3)斷開鏈接(四次握手)
UDP:不可靠,面向數據報的無鏈接的數據傳輸服務,傳輸的是是數據包,不保證數據的有序性
廣播:能夠向同一個子網內的全部主機發送廣播數據
組播:能夠向全部加入組網的主機發送組播數據
二、編程(本節因爲篇幅太長,這裏只說TCP)
.NET 框架提供了下面幾個類對實現網絡通訊:
Socket:提供最基本的TCP和UDP服務
TcpListener/TcpClient 和 UdpClient:對Socket類進行了基本封裝
NetworkStream:網絡流,對網絡數據的寫入和讀取
使用套接字的步驟
TCP:服務器:建立套接字 -》 綁定套接字Bind -》 監聽套接字Listen -》 接受鏈接Accept -》 發送/接受Send/Receive -》 關閉套接字CLose
:客戶端:建立套接字 -》 鏈接 -》 發送/接受Send/Receive -》 關閉套接字CLose
UDP:建立套接字 -》 綁定套接字Bind -》 發送/接受SendTo/ReceiveFrom -》 關閉套接字CLose
1)Socket(使用異步方式鏈接和收發信息,由於等待鏈接和等待數據的時候會讓主線程阻塞)
這裏就不貼代碼了,跟下面的差很少,後面下載的代碼有(我用的VS2012,低版本不能查看能夠直接看源文件的代碼)
2)TcpListener/TcpClient(這裏也使用異步方式來鏈接和接收信息)
首先建立一個異步用的數據對象
public class StateObject { public NetworkStream networkstream = null; public byte[] buffer = new byte[1024]; public StateObject(NetworkStream netstream) { this.networkstream = netstream; } }
1)服務器端(異步監聽,當收到鏈接,則異步讀取數據,注意捕獲鏈接斷開時的異常)
TcpListener listener; NetworkStream networkstream; private void btnBind_Click(object sender, EventArgs e) { //綁定,啓動異步接受鏈接 try { int port = int.Parse(tbPort.Text); IPAddress ipaddress = IPAddress.Parse(tbIP.Text); IPEndPoint endpoint = new IPEndPoint(ipaddress, port); listener = new TcpListener(endpoint); listener.Start(10); //監聽數位10 //開始異步接收鏈接請求 listener.BeginAcceptTcpClient(DoAcceptTcpClientCallback, listener); btn.Text = "Close"; } catch (ArgumentNullException) { } catch (SocketException) { } } //異步接收請求函數 public void DoAcceptTcpClientCallback(IAsyncResult ar) { TcpListener listener = (TcpListener)ar.AsyncState; try { TcpClient client = listener.EndAcceptTcpClient(ar); //收到鏈接 this.BeginInvoke(new ThreadStart(() => { //收到鏈接請求,這裏可讓主線程更新UI })); networkstream = new NetworkStream(client.Client); StateObject so = new StateObject(networkstream); //開始異步讀取數據 networkstream.BeginRead(so.buffer, 0, so.buffer.Length, ReadCallback, so); //若是須要繼續監聽,則繼續異步接收 listener.BeginAcceptTcpClient(DoAcceptTcpClientCallback, listener); } catch (ObjectDisposedException) { //Socket關閉 } } //異步讀取數據函數 public void ReadCallback(IAsyncResult ar) { StateObject so = (StateObject)ar.AsyncState; try { NetworkStream myNetworkStream = so.networkstream; int length = myNetworkStream.EndRead(ar); string receivemsg = Encoding.UTF8.GetString(so.buffer, 0, length); this.BeginInvoke(new ThreadStart(() => { //收到數據,在這裏可讓主線程更新UI })); so.buffer = new byte[1024]; //繼續接收數據 myNetworkStream.BeginRead(so.buffer, 0, so.buffer.Length, ReadCallback, so); } catch (IOException) { this.BeginInvoke(new ThreadStart(() => { //鏈接斷開 })); networkstream = null; } }
這樣,服務器端就完成了監聽
2)客戶端(一樣經過異步實現)
TcpClient client; NetworkStream networkstream; private void btnConnect_Click(object sender, EventArgs e) { int port = int.Parse(tbPort.Text); IPAddress ipaddress = IPAddress.Parse(tbIP.Text); IPEndPoint endpoint = new IPEndPoint(ipaddress, port); if (client == null) { //開始異步鏈接 client = new TcpClient(); client.BeginConnect(ipaddress, port, ConnectCallback, client); } } private void ConnectCallback(IAsyncResult ar) { TcpClient t = ar.AsyncState as TcpClient; try { t.EndConnect(ar); networkstream = t.GetStream(); this.BeginInvoke(new ThreadStart(() => { //鏈接成功 })); //開始異步接受數據 StateObject so = new StateObject(networkstream); networkstream.BeginRead(so.buffer, 0, so.buffer.Length, ReadCallback, so); } catch (SocketException) { this.BeginInvoke(new ThreadStart(() => { //鏈接失敗,讓UI更新 })); } } public void ReadCallback(IAsyncResult ar) { StateObject so = (StateObject)ar.AsyncState; try { NetworkStream myNetworkStream = so.networkstream; int length = myNetworkStream.EndRead(ar); string receivemsg = Encoding.UTF8.GetString(so.buffer, 0, length); this.BeginInvoke(new ThreadStart(() => { //更新UI })); //繼續異步接受數據 so.buffer = new byte[1024]; myNetworkStream.BeginRead(so.buffer, 0, so.buffer.Length, ReadCallback, so); } catch (IOException) { this.BeginInvoke(new ThreadStart(() => { //鏈接斷開 })); networkstream = null; } }
3)接下來是發送數據
private void btnSend_Click(object sender, EventArgs e) { if (networkstream != null) { byte[] sendbyte = System.Text.Encoding.UTF8.GetBytes("你好:)"); networkstream.Write(sendbyte, 0, sendbyte.Length); } else { tbMsg.AppendText("未鏈接\n"); } }
具體項目代碼 http://files.cnblogs.com/bomo/%E7%BD%91%E7%BB%9C%E7%BC%96%E7%A8%8B.zip