C#异步的Socket通信(重构局域网聊天小工具)

5/5/2011来源:C#应用人气:11792

简要说明
        上图左边部分表示的是客户端的过程, 右边部分表示的是服务端的过程. 客户端相比服务端在建立连接之前步骤稍微少一些, 成功建立连接后客户端和服务端都有一个CommunicateSocket负责与对方通信, 如发送消息, 接收消息, 发送文件, 接收文件等.

        服务端, 声明ServerSocket, 绑定(Bind)一个ip并指定这个IP的通信端口, 比如是127.0.0.1:9050, ServerSocket可以监听来自多个IP发送的连接请求, 监听(Listen)方法的参数可以设置允许的最多连接请求个数. 然后调用异步接受请求的方法(BeginAccept), 如果接受到某个客户端发来连接请求, 这时定义一个新的CommunicateSocket专门负责与这个客户端通信. 然后可以通过CommunicateSocket.BeginSend()方法给客户端发送数据, CommunicateSocket.BeginReceive()可以接收客户端发来的数据.

        客户端, 有一个CommunicateSocket, 并绑定一个IP以及一个未被占用的端口, 定义IPEndPoint serverIP表示服务端Socket的IP和端口, 这样才可以进行端口对端口之间的通信, 接下来就可以尝试CommunicateSocket.BeginConnect(serverIP), 连接成功之后就可以发送和接收数据了, CommunicateSocket.BeginSend(), CommunicateSocket.BeginReceive().

        有些异步方法有两种实现方式, 如BeginAccept()和AcceptAsync(), 这两个方法有什么区别呢?  以 Begin 和 End 开头的方法是以 APM(Asynchronous PRogramming Model)设计方法实现的异步操作, 以 Async 结尾的方法是利用称为 EAP (Event-based Asynchronous Pattern) 的设计方法实现的异步操作.

代码部分
1. SocketFunc类
        SocketFunc是一个抽象类, 服务端和客户端只有建立连接的方法不同, 其它都相同, 所以把相同的部分放到这个类中.

00 public abstract class SocketFunc 

01 { 

02     //不管是服务端还是客户端, 建立连接后用这个Socket进行通信 

03     public Socket communicateSocket = null; 

04   

05     //服务端和客户端建立连接的方式稍有不同, 子类会重载 

06     public abstract void access(string IP, System.Action AccessAciton); 

07   

08     //发送消息的函数 

09     public void Send(string message) 

10     { 

11         if (communicateSocket.Connected == false) 

12         { 

13             throw new Exception("还没有建立连接, 不能发送消息"); 

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     //接受消息的函数 

23     public void Receive(System.Action<string> ReceiveAction) 

24     { 

25         //如果消息超过1024个字节, 收到的消息会分为(总字节长度/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     //服务端重载Access函数 

03     public override void Access(string IP, System.Action AccessAciton) 

04     { 

05         Socket serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 

06         //本机预使用的IP和端口 

07         IPEndPoint serverIP = new IPEndPoint(IPAddress.Any, 9050); 

08         //绑定服务端设置的IP 

09         serverSocket.Bind(serverIP); 

10         //设置监听个数 

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函数 

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         //服务器的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         //客户端只用来向指定的服务器发送信息,不需要绑定本机的IP和端口,不需要监听 

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 }