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

王朝学院·作者佚名  2011-05-06
窄屏简体版  字體: 小  |  中  |  大  |  超大  

简要说明

上图左边部分表示的是客户端的过程, 右边部分表示的是服务端的过程. 客户端相比服务端在建立连接之前步骤稍微少一些, 成功建立连接后客户端和服务端都有一个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 }

 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
 
© 2005- 王朝網路 版權所有 導航