簡要說明
上圖左邊部分表示的是客戶端的過程, 右邊部分表示的是服務(wù)端的過程. 客戶端相比服務(wù)端在建立連接之前步驟稍微少一些, 成功建立連接后客戶端和服務(wù)端都有一個CommunicateSocket負(fù)責(zé)與對方通信, 如發(fā)送消息, 接收消息, 發(fā)送文件, 接收文件等.
服務(wù)端, 聲明ServerSocket, 綁定(Bind)一個ip并指定這個IP的通信端口, 比如是127.0.0.1:9050, ServerSocket可以監(jiān)聽來自多個IP發(fā)送的連接請求, 監(jiān)聽(Listen)方法的參數(shù)可以設(shè)置允許的最多連接請求個數(shù). 然后調(diào)用異步接受請求的方法(BeginAccept), 如果接受到某個客戶端發(fā)來連接請求, 這時定義一個新的CommunicateSocket專門負(fù)責(zé)與這個客戶端通信. 然后可以通過CommunicateSocket.BeginSend()方法給客戶端發(fā)送數(shù)據(jù), CommunicateSocket.BeginReceive()可以接收客戶端發(fā)來的數(shù)據(jù).
客戶端, 有一個CommunicateSocket, 并綁定一個IP以及一個未被占用的端口, 定義IPEndPoint serverIP表示服務(wù)端Socket的IP和端口, 這樣才可以進(jìn)行端口對端口之間的通信, 接下來就可以嘗試CommunicateSocket.BeginConnect(serverIP), 連接成功之后就可以發(fā)送和接收數(shù)據(jù)了, CommunicateSocket.BeginSend(), CommunicateSocket.BeginReceive().
有些異步方法有兩種實現(xiàn)方式, 如BeginAccept()和AcceptAsync(), 這兩個方法有什么區(qū)別呢? 以 Begin 和 End 開頭的方法是以 APM(Asynchronous PRogramming Model)設(shè)計方法實現(xiàn)的異步操作, 以 Async 結(jié)尾的方法是利用稱為 EAP (Event-based Asynchronous Pattern) 的設(shè)計方法實現(xiàn)的異步操作.
代碼部分
1. SocketFunc類
SocketFunc是一個抽象類, 服務(wù)端和客戶端只有建立連接的方法不同, 其它都相同, 所以把相同的部分放到這個類中.
00 public abstract class SocketFunc
01 {
02 //不管是服務(wù)端還是客戶端, 建立連接后用這個Socket進(jìn)行通信
03 public Socket communicateSocket = null;
04
05 //服務(wù)端和客戶端建立連接的方式稍有不同, 子類會重載
06 public abstract void access(string IP, System.Action AccessAciton);
07
08 //發(fā)送消息的函數(shù)
09 public void Send(string message)
10 {
11 if (communicateSocket.Connected == false)
12 {
13 throw new Exception("還沒有建立連接, 不能發(fā)送消息");
14 }
15 Byte[] msg = Encoding.UTF8.GetBytes(message);
16 communicateSocket.BeginSend(msg,0, msg.Length, SocketFlags.None,
17 ar => {
18
19 }, null);
20 }
21
22 //接受消息的函數(shù)
23 public void Receive(System.Action<string> ReceiveAction)
24 {
25 //如果消息超過1024個字節(jié), 收到的消息會分為(總字節(jié)長度/1024 +1)條顯示
26 Byte[] msg = new byte[1024];
27 //異步的接受消息
28 communicateSocket.BeginReceive(msg, 0, msg.Length, SocketFlags.None,
29 ar => {
30 //對方斷開連接時, 這里拋出Socket Exception
31 //An existing connection was forcibly closed by the remote host
32 communicateSocket.EndReceive(ar);
33 ReceiveAction(Encoding.UTF8.GetString(msg).Trim('/0',' '));
34 Receive(ReceiveAction);
35 }, null);
36 }
37 }
2. ServerSocket:SocketFunc類
繼承自SocketFunc類, 類中重載了Access方法.
00 public class ServerSocket:SocketFunc
01 {
02 //服務(wù)端重載Access函數(shù)
03 public override void Access(string IP, System.Action AccessAciton)
04 {
05 Socket serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
06 //本機(jī)預(yù)使用的IP和端口
07 IPEndPoint serverIP = new IPEndPoint(IPAddress.Any, 9050);
08 //綁定服務(wù)端設(shè)置的IP
09 serverSocket.Bind(serverIP);
10 //設(shè)置監(jiān)聽個數(shù)
11 serverSocket.Listen(1);
12 //異步接收連接請求
13 serverSocket.BeginAccept(ar =>
14 {
15 base.communicateSocket = serverSocket.EndAccept(ar);
16 AccessAciton();
17 }, null);
18 }
19 }
3. ClientSocket:SocketFunc類
繼承自SocketFunc類, 類中重載了Access方法.
00 public class ClientSocket:SocketFunc
01 {
02 //客戶端重載Access函數(shù)
03 public override void Access(string IP, System.Action AccessAciton)
04 {
05 base.communicateSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
06 base.communicateSocket.Bind(new IPEndPoint(IPAddress.Any, 9051));
07
08 //服務(wù)器的IP和端口
09 IPEndPoint serverIP;
10 try
11 {
12 serverIP = new IPEndPoint(IPAddress.Parse(IP), 9050);
13 }
14 catch
15 {
16 throw new Exception(String.Format("{0}不是一個有效的IP地址!", IP));
17 }
18
19 //客戶端只用來向指定的服務(wù)器發(fā)送信息,不需要綁定本機(jī)的IP和端口,不需要監(jiān)聽
20 try
21 {
22 base.communicateSocket.BeginConnect(serverIP, ar =>
23 {
24 AccessAciton();
25 }, null);
26 }
27 catch
28 {
29 throw new Exception(string.Format("嘗試連接{0}不成功!", IP));
30 }
31 }
32 }
新聞熱點
疑難解答