| 在上一篇文章中介紹了Socket基礎(chǔ)—TCP與UDP協(xié)議和他們之間的區(qū)別,這篇文章參考另一位前輩的博文重點(diǎn)記錄下Socket的原理及兩種協(xié)議的開(kāi)發(fā)過(guò)程。 一、Socket通信簡(jiǎn)介1.按慣例先來(lái)介紹下socket        Windows中的很多東西都是從Unix領(lǐng)域借鑒過(guò)來(lái)的,Socket也是一樣。在Unix中,socket代表了一種文件描述符(在Unix中一切都是以文件為單位),而這里這個(gè)描述符則是用于描述網(wǎng)絡(luò)訪(fǎng)問(wèn)的。什么意思呢?就是程序員可以通過(guò)socket來(lái)發(fā)送和接收網(wǎng)絡(luò)上的數(shù)據(jù)。你也可以理解成是一個(gè)API。有了它,你就不用直接去操作網(wǎng)卡了,而是通過(guò)這個(gè)接口,這樣就省了很多復(fù)雜的操作。 2.有了socket,那就可以用它來(lái)訪(fǎng)問(wèn)網(wǎng)絡(luò)了      不過(guò)你不要高興得太早,要想訪(fǎng)問(wèn)網(wǎng)絡(luò),還得有些基本的條件(和編程無(wú)關(guān)的我就不提了):a. 要確定本機(jī)的IP和端口,socket只有與某一IP和端口綁定,才能發(fā)揮強(qiáng)大的威力。b. 得有協(xié)議吧(否則誰(shuí)認(rèn)得你這發(fā)送到網(wǎng)絡(luò)的是什么呀)。想要復(fù)雜的,我們可以自己來(lái)定協(xié)議。但是這個(gè)就不在這篇里提了,我這里介紹兩種大家最熟悉不過(guò)的協(xié)議:TCP & UDP。(別說(shuō)你不知道,不然...不然...我不告訴你) 面向連接的套接字系統(tǒng)調(diào)用時(shí)序 (TCP)     無(wú)連接的套接字系統(tǒng)調(diào)用時(shí)序(UDP)  二、TCP協(xié)議的Socket實(shí)例
 服務(wù)端 后臺(tái)代碼:   1 using System; 2 using System.Collections.Generic; 3 using System.ComponentModel; 4 using System.Data; 5 using System.Drawing; 6 using System.IO; 7 using System.Linq; 8 using System.Net; 9 using System.Net.Sockets; 10 using System.Text; 11 using System.Threading; 12 using System.Threading.Tasks; 13 using System.Windows.Forms; 14 15 namespace Socket通信 16 { 17 public partial class Form1 : Form 18 { 19 20 public Form1() 21 { 22 InitializeComponent(); 23 TextBox.CheckForIllegalCrossThreadCalls = false; 24 25 } 26 Socket socketSend; 27 Thread threadWatch = null; // 負(fù)責(zé)監(jiān)聽(tīng)客戶(hù)端連接請(qǐng)求的 線(xiàn)程; 28 Socket socketWatch = null; 29 30 31 /// <summary> 32 /// 監(jiān)聽(tīng)客戶(hù)端請(qǐng)求的方法; 33 /// </summary> 34 void WatchConnecting() 35 { 36 try 37 { 38 while (true) // 持續(xù)不斷的監(jiān)聽(tīng)客戶(hù)端的連接請(qǐng)求; 39 { 40 // 開(kāi)始監(jiān)聽(tīng)客戶(hù)端連接請(qǐng)求,Accept方法會(huì)阻斷當(dāng)前的線(xiàn)程; 41 Socket sokConnection = socketWatch.Accept(); 42 // 一旦監(jiān)聽(tīng)到一個(gè)客戶(hù)端的請(qǐng)求,就返回一個(gè)與該客戶(hù)端通信的 套接字; 43 // 向列表控件中添加客戶(hù)端的IP信息; 44 lbOnline.Items.Add(sokConnection.RemoteEndPoint.ToString()); 45 ShowMsg("客戶(hù)端連接成功!"); 46 //開(kāi)啟一個(gè)新線(xiàn)程,執(zhí)行接收消息方法 47 Thread r_thread = new Thread(Received); 48 r_thread.IsBackground = true; 49 r_thread.Start(sokConnection); 50 } 51 } 52 catch (Exception e) 53 { 54 ShowMsg("異常:" + e.Message); 55 } 56 57 } 58 /// <summary> 59 /// 服務(wù)器端不停的接收客戶(hù)端發(fā)來(lái)的消息 60 /// </summary> 61 /// <param name="o"></param> 62 void Received(object o) 63 { 64 try 65 { 66 socketSend = o as Socket; 67 while (true) 68 { 69 //客戶(hù)端連接服務(wù)器成功后,服務(wù)器接收客戶(hù)端發(fā)送的消息 70 // 定義一個(gè)3M的緩存區(qū); 71 byte[] buffer = new byte[1024 * 1024 * 3]; 72 //實(shí)際接收到的有效字節(jié)數(shù) 73 // 將接受到的數(shù)據(jù)存入到輸入 buffer中; 74 int len = socketSend.Receive(buffer); 75 if (len == 0) 76 { 77 break; 78 } 79 string str = Encoding.UTF8.GetString(buffer, 0, len); 80 ShowMsg("接收到的客戶(hù)端數(shù)據(jù):" + socketSend.RemoteEndPoint + ":" + str); 81 Send("服務(wù)端接收成功(" + str + ")"); 82 83 } 84 } 85 catch (Exception e) 86 { 87 ShowMsg("異常:" + e.Message); 88 } 89 } 90 /// <summary> 91 /// 服務(wù)器向客戶(hù)端發(fā)送消息 92 /// </summary> 93 /// <param name="str"></param> 94 void Send(string str) 95 { 96 byte[] buffer = Encoding.UTF8.GetBytes(str); 97 socketSend.Send(buffer); 98 99 } 100 void ShowMsg(string str) 101 { 102 txtMsg.AppendText(str + "\r\n"); 103 } 104 private void button1_Click_1(object sender, EventArgs e) 105 { 106 // 創(chuàng)建負(fù)責(zé)監(jiān)聽(tīng)的套接字,注意其中的參數(shù); 107 socketWatch = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 108 // 獲得文本框中的IP對(duì)象; 109 IPAddress address = IPAddress.Parse(txtIp.Text.Trim()); 110 // 創(chuàng)建包含ip和端口號(hào)的網(wǎng)絡(luò)節(jié)點(diǎn)對(duì)象; 111 IPEndPoint endPoint = new IPEndPoint(address, int.Parse(txtPort.Text.Trim())); 112 try 113 { 114 // 將負(fù)責(zé)監(jiān)聽(tīng)的套接字綁定到唯一的ip和端口上; 115 socketWatch.Bind(endPoint); 116 } 117 catch (SocketException se) 118 { 119 MessageBox.Show("異常:" + se.Message); 120 return; 121 } 122 // 設(shè)置監(jiān)聽(tīng)隊(duì)列的長(zhǎng)度; 123 socketWatch.Listen(10); 124 // 創(chuàng)建負(fù)責(zé)監(jiān)聽(tīng)的線(xiàn)程; 125 threadWatch = new Thread(WatchConnecting); 126 threadWatch.IsBackground = true; 127 threadWatch.Start(); 128 ShowMsg("服務(wù)器啟動(dòng)監(jiān)聽(tīng)成功!"); 129 } 130 } 131 } 
 客戶(hù)端 后臺(tái)代碼:   1 using System; 2 using System.Collections.Generic; 3 using System.ComponentModel; 4 using System.Data; 5 using System.Drawing; 6 using System.Linq; 7 using System.Text; 8 using System.Threading.Tasks; 9 using System.Windows.Forms; 10 using System.Net; 11 using System.Net.Sockets; 12 using System.Threading; 13 14 15 namespace Socket通信客戶(hù)端 16 { 17 public partial class Socket_client : Form 18 { 19 public Socket_client() 20 { 21 InitializeComponent(); 22 CheckForIllegalCrossThreadCalls = false; 23 } 24 Socket socketSend; 25 void ShowMsg(string str) 26 { 27 txtMsg.AppendText(str + "\r\n"); 28 } 29 /// <summary> 30 /// 接收服務(wù)端返回的消息 31 /// </summary> 32 void Received() 33 { 34 while (true) 35 { 36 try 37 { 38 byte[] buffer = new byte[1024 * 1024 * 3]; 39 //實(shí)際接收到的有效字節(jié)數(shù) 40 int len = socketSend.Receive(buffer); 41 if (len == 0) 42 { 43 continue; 44 } 45 string str = Encoding.UTF8.GetString(buffer, 0, len); 46 ShowMsg("接收到的服務(wù)端數(shù)據(jù):" + socketSend.RemoteEndPoint + ":" + str); 47 } 48 catch 49 { 50 MessageBox.Show("接收失敗,請(qǐng)檢查服務(wù)端是否斷開(kāi)!"); 51 return; 52 } 53 } 54 } 55 56 private void btnDisconnect_Click(object sender, EventArgs e) 57 { 58 socketSend.Close(); 59 ShowMsg("連接已經(jīng)斷開(kāi)!"); 60 } 61 void Send(string str) 62 { 63 byte[] buffer = Encoding.UTF8.GetBytes(str); 64 socketSend.Send(buffer); 65 } 66 } 67 } 三、UDP協(xié)議的Socket實(shí)例  using System; using System.Collections.Generic; using System.Text; using System.Net; using System.Net.Sockets; namespace SimpleUdpSrvr { class Program { static void Main(string[] args) { int recv; byte[] data = new byte[1024]; IPEndPoint ipep = new IPEndPoint(IPAddress.Any, 9050);//定義一網(wǎng)絡(luò)端點(diǎn) Socket newsock = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);//定義一個(gè)Socket newsock.Bind(ipep);//Socket與本地的一個(gè)終結(jié)點(diǎn)相關(guān)聯(lián) Console.WriteLine("Waiting for a client.."); IPEndPoint sender = new IPEndPoint(IPAddress.Any, 0);//定義要發(fā)送的計(jì)算機(jī)的地址 EndPoint Remote = (EndPoint)(sender);// recv = newsock.ReceiveFrom(data, ref Remote);//接受數(shù)據(jù) Console.WriteLine("Message received from{0}:", Remote.ToString()); Console.WriteLine(Encoding.ASCII.GetBytes(data,0,recv)); string welcome = "Welcome to my test server!"; data = Encoding.ASCII.GetBytes(welcome); newsock.SendTo(data, data.Length, SocketFlags.None, Remote); while (true) { data = new byte[1024]; recv = newsock.ReceiveFrom(data, ref Remote); Console.WriteLine(Encoding.ASCII.GetString(data, 0, recv)); newsock.SendTo(data, recv, SocketFlags.None, Remote); } } } }   using System; using System.Collections.Generic; using System.Text; using System.Net; using System.Net.Sockets; namespace SimpleUdpClient { class Program { static void Main(string[] args) { byte[] data = new byte[1024];//定義一個(gè)數(shù)組用來(lái)做數(shù)據(jù)的緩沖區(qū) string input, stringData; IPEndPoint ipep = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 9050); Socket server = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); string welcome = "Hello,are you there?"; data = Encoding.ASCII.GetBytes(welcome); server.SendTo(data, data.Length, SocketFlags.None, ipep);//將數(shù)據(jù)發(fā)送到指定的終結(jié)點(diǎn) IPEndPoint sender = new IPEndPoint(IPAddress.Any, 0); EndPoint Remote = (EndPoint)sender; data = new byte[1024]; int recv = server.ReceiveFrom(data, ref Remote);//接受來(lái)自服務(wù)器的數(shù)據(jù) Console.WriteLine("Message received from{0}:", Remote.ToString()); Console.WriteLine(Encoding.ASCII.GetString(data, 0, recv)); while (true)//讀取數(shù)據(jù) { input = Console.ReadLine();//從鍵盤(pán)讀取數(shù)據(jù) if (input == "text")//結(jié)束標(biāo)記 { break; } server.SendTo(Encoding.ASCII.GetBytes(input), Remote);//將數(shù)據(jù)發(fā)送到指定的終結(jié)點(diǎn)Remote data = new byte[1024]; recv = server.ReceiveFrom(data, ref Remote);//從Remote接受數(shù)據(jù) stringData = Encoding.ASCII.GetString(data, 0, recv); Console.WriteLine(stringData); } Console.WriteLine("Stopping client"); server.Close(); } } } 上面的示例只是簡(jiǎn)單的應(yīng)用了socket來(lái)實(shí)現(xiàn)通信,你也可以實(shí)現(xiàn)異步socket、IP組播 等等。      MS還為我們提供了幾個(gè)助手類(lèi):TcpClient類(lèi)、TcpListener類(lèi)、UDPClient類(lèi)。這幾個(gè)類(lèi)簡(jiǎn)化了一些操作,所以你也可以利用這幾類(lèi)來(lái)寫(xiě)上面的代碼,但我個(gè)人還是比較習(xí)慣直接用socket來(lái)寫(xiě)。 | 
|  | 
來(lái)自: 小樣樣樣樣樣樣 > 《待分類(lèi)》