1.目的:實現客戶端向服務器發送數據
原理:

2.建立兩個控制台應用,一個為服務器,用於接收數據。一個為客戶端,用於發送數據。
關鍵類與對應方法:
1)類IPEndPoint:
1.是抽象類EndPoint的實現類
2.Socket對象的RemoteEndPoint、 LocalEndPoint都是這個類型
3.屬性Address: 使用IPv4表示的地址
4.屬性Port:使用int表示的端口
2)類Socket:
這個類即可以用於作服務器端的開發,又可以作客戶端的開發
構造方法:
參數 AddressFamily:指定使用IPv4的地址InterNetwork
參數SocketType:指定使用流式傳輸Stream
參數ProtocolType:指定協議類型Tcp
1.方法Bind()E 綁定IP與端口,這樣就成為了服務器,可以監聽指定IP的特定端口
2.方法Listen(); 置於監聽狀態,參數是最大的掛起數
3.方法Accept(): 接收客戶端連接,返回Socket對象, 這個方法會阻塞當前線程,建議開啟新線程執行些方法,結合尾遞歸,這樣就可以接收多個客戶端
4.方法Receive(): 接收客戶端發送過來的消息,以字節為單位進行操作,此方法會阻塞當前線程,建議開啟新線程執行此方法,結合尾遞歸,就可以持續接收多條信息
5. 方法Send(): 發送消息,以字節為單位
3.具體實現
其他內容不做過多解釋了,備注做的超詳細,應該只有笨笨的人才寫這么多備注吧。。
1.服務器
主函數:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ServerTest { class Program { static void Main(string[] args) { // 調用構造函數,使用Start方法 ServerControl server = new ServerControl(); server.Start(); Console.ReadKey(); } } }
ServerControl類:
using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading; using System.Threading.Tasks; namespace ServerTest { public class ServerControl { // 聲明變量(使用Socket需using System.Net.Sockets;) private Socket serverSocket; // 自定義有參構造方法(IP地址,流程傳輸方式,TCP協議) public ServerControl() { serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); } // 創建啟動方法(IPEndPoint用於指定地址及端口初始化,需using System.Net;) public void Start() { // 服務器啟動 // 綁定IP地址(為任意IP)與端口(設置為12345) serverSocket.Bind(new IPEndPoint(IPAddress.Any,12345)); serverSocket.Listen(10); Console.WriteLine("服務器啟動成功"); // 開啟線程:目的實現服務器和客戶端一對多連接 Thread threadAccept = new Thread(Accept); threadAccept.IsBackground = true; threadAccept.Start(); } // Accept方法測試:接收客戶端連接 private void Accept() { // 接收客戶端方法,會掛起當前線程(.RemoteEndPoint表示遠程地址) Socket client = serverSocket.Accept(); IPEndPoint point = client.RemoteEndPoint as IPEndPoint; Console.WriteLine(point.Address + "[" + point.Port + "] 連接成功!"); // 開啟一個新線程線程,實現消息多次接收 Thread threadReceive = new Thread(Receive); threadReceive.IsBackground = true; threadReceive.Start(client); // 尾遞歸 Accept(); } // Receive方法的使用測試 // 接收客戶端發送過來的消息,以字節為單位進行操作 // 該方法會阻塞當前線程,所以適合開啟新的線程使用該方法 // Accept()中將Receive作為線程傳遞對象,所以要注意一點,使用線程傳遞對象只能是object類型的!! private void Receive(object obj) { // 將object類型強行轉換成socket Socket client = obj as Socket; IPEndPoint point = client.RemoteEndPoint as IPEndPoint; // 此處的異常拋出主要針對客戶端異常的問題 // 比如,客戶端關閉或者連接中斷 // 程序會停留在int msgLen = client.Receive(msg);這段代碼,而導致無法繼續往下走 try { byte[] msg = new byte[1024]; // 實際接收到字節數組長度,該方法會阻塞當前線程,即(client.Receive(msg)開始掛起) // 同時,這里還是尾遞歸掛起處 int msgLen = client.Receive(msg); // 將msg裝換成字符串 Console.WriteLine(point.Address + "[" + point.Port + "]:" + Encoding.UTF8.GetString(msg, 0, msgLen)); // 此處實現服務器自動向客戶端返回一條消息 // 因為Send發送信息是以字節為單位發送的 // 所以下面(Encoding.UTF8.GetString(msg,0,msgLen)+" yes.boy")這一塊是把這一部分均搞成string // 后使用Encoding.UTF8.GetBytes統一轉化成字節傳遞 // 這里呢,已經實現服務器向客戶端發送消息了,客戶端只需要receive一下,格式一轉就可視化了 client.Send(Encoding.UTF8.GetBytes(Encoding.UTF8.GetString(msg,0,msgLen)+" yes.boy")); // 尾遞歸實現多條消息的接收;和while同理。 Receive(client); } catch { Console.WriteLine(point.Address + "[" + point.Port + "]積極斷開"); } } } }
2.客戶端:
主函數:
client.Connect("127.0.0.1",12345);
修改IP可實現不同計算機之間的連接。
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ClientTest { class Program { static void Main(string[] args) { // 調用構造函數 ClientControl client = new ClientControl(); // 輸入本機IP與端口號 client.Connect("127.0.0.1",12345); // 提示操作方法 Console.WriteLine("請輸入發送至服務器的內容或者輸入quit退出"); // 輸入內容 string msg = Console.ReadLine(); // 非退出情況下操作方式,使用while可以持續不斷的接收用戶輸入 while(msg != "quit") { client.Send(msg); msg = Console.ReadLine(); } Console.ReadKey(); } } }
ClientControl類:
using System; using System.Collections.Generic; using System.Linq; using System.Net.Sockets; using System.Text; using System.Threading; using System.Threading.Tasks; namespace ClientTest { public class ClientControl { // 聲明變量 private Socket clientSocket; // 自定義有參構造方法((IP地址,流程傳輸方式,TCP協議)) public ClientControl() { clientSocket = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp); } // 創建通過IP與端口號連接的方法 public void Connect(string ip,int port) { clientSocket.Connect(ip, port); Console.WriteLine("連接服務器成功"); // 客戶端接收服務器消息的線程 Thread threadReceive = new Thread(Receive); threadReceive.IsBackground = true; threadReceive.Start(); } // 用於測試服務器向客戶端返回一條消息 private void Receive() { while(true) { try { // 用於接收服務器的回復信息 byte[] msg = new byte[1024]; int msgLen = clientSocket.Receive(msg); Console.WriteLine("服務器:"+Encoding.UTF8.GetString(msg,0,msgLen)); } // 異常處理方法 catch { Console.WriteLine("服務器積極拒絕!!"); // 退出while循環 break; } } } // Send方法測試:即發送消息,以字節為單位 public void Send(string msg) { // 將字符創傳化為字節數組 clientSocket.Send(Encoding.UTF8.GetBytes(msg)); } } }
4.實現
本地連接:IP為127.0.0.1

遠程連接:因為我只有一台電腦,所以用騰訊雲服務器作為我的服務器,我本地的PC作為客戶端,實現連接。
1.修改客戶端主程序里面的IP為我的騰訊雲IP

2.使用遠程桌面連接

3.連接成功

