網絡編程的重要性就不說了,先上源碼:https://github.com/NewLifeX/NewLife.Net
一個服務端,就是監聽一些端口,接收客戶端連接和數據,進行處理,然后響應。
/// <summary>定義服務端,用於管理所有網絡會話</summary> class MyNetServer : NetServer<MyNetSession> { } /// <summary>定義會話。每一個遠程連接唯一對應一個網絡會話,再次重復收發信息</summary> class MyNetSession : NetSession<MyNetServer> { /// <summary>客戶端連接</summary> public override void Start() { base.Start(); // 歡迎語 var str = String.Format("Welcome to visit {1}! [{0}]\r\n", Remote, Environment.MachineName); Send(str); } /// <summary>收到客戶端數據</summary> /// <param name="e"></param> protected override void OnReceive(ReceivedEventArgs e) { WriteLog("收到:{0}", e.Packet.ToStr()); // 把收到的數據發回去 Send(e.Packet); } }
服務端核心類是NetServer,一般來說,每個網絡服務端都會寫一個自己的類來繼承NetServer,以方便編寫自己的NetSession會話邏輯。
實在簡單的應用,也可以直接實例化NetServer,然后通過事件來處理收到的連接和數據。
這里我們寫了個MyNetServer,沒有任何代碼,僅僅是為了指定使用哪個網絡會話類。
網絡會話NetSession非常重要,每一個Tcp連接就對應一個會話,對Udp來說同一個遠端套接字(IP+端口)就是一個會話。
網絡會話最重要的有幾塊:
- Start會話開始,Tcp三次握手之后,雙方還沒有發送數據包之前,此時可以做一些准備工作,或者向客戶端發送歡迎語。Udp會話開始在第一個數據包達到時。
- OnReceive接收,每次收到數據包以后,都會觸發該方法,數據包位於e.Packet。Tcp默認同步處理,未完成當前數據包處理之前,不會接收本連接的下一個數據包。
- Send發送。發送Packet數據包給本會話連接的客戶端,擴展方法支持發送字符串或數據流。
!!!注意:粘包問題在OnReceive之前處理,下回有專門文章分析,接收數據的ReceivedEventArgs里面還有個Message,支持編碼器對數據包進行解碼成為消息。
本例程是Echo回聲程序,因此OnReceive把收到的數據包原樣發回去。
服務端用法很簡單
static NetServer _server; static void TestServer() { // 實例化服務端,指定端口,同時在Tcp/Udp/IPv4/IPv6上監聽 var svr = new MyNetServer { Port = 1234, Log = XTrace.Log }; svr.Start(); _server = svr; }
指定端口和日志,然后就可以開始服務了。
默認在Tcp/Udp/IPv4/IPv6上監聽,客戶端愛用哪個協議來連接都行。
當然,NetServer還可以支持多個端口同時監聽,共用數據處理代碼。
客戶端用法更簡單
var uri = new NetUri("tcp://127.0.0.1:1234"); var client = uri.CreateRemote(); client.Log = XTrace.Log; client.Received += (s, e) => { XTrace.WriteLine("收到:{0}", e.Packet.ToStr()); }; client.Open(); for (var i = 0; i < 5; i++) { Thread.Sleep(1000); var str = "你好" + (i + 1); client.Send(str); } client.Dispose();
這里的NetUri直接從字符串里面解析協議、地址、端口,然后CreateRemote建立客戶端。這里會自動識別Tcp/Udp。
也是指定日志,方便我們查看工作過程。還有兩個開關 LogSend/LogReceive能輸出更詳細的數據包日志。
Received事件里面處理收到的數據包。
Open開始連接服務端,如果網絡不同,這里會拋出異常。Tcp客戶端有斷線重連機制。
發送數據包也很簡單,直接Send就好,高級應用需要在發送后等待響應數據,可以用 await SendAsync。
因為程序很簡單,也可以用telnet命令來測試該服務端。