基于C#的异步Socket程序(TCP)

今天我门将通过一个多人聊天的例子来说明异步Socket程序。

没有基础的可以看一下之前的同步Socket程序。

地址:http://blog.csdn.net/YongshuangZhao/article/details/78696718

1.代码如下:

服务端代码:

using System;
using System.Net; 
using System.Net.Sockets;
using System.Collections;
using System.Collections.Generic;

namespace AsyncTCPServer
{
	//客户端连接类
	public class Connect
	{
		//与客户端连接的套接字
		public Socket socket;
		//缓冲区大小
		public const int BUFFER_SIZE=1024;
		//读缓冲区
		public byte[] readBuff=new byte[BUFFER_SIZE];
		//当前缓冲区大小
		public int buffCount=0;
		//是否被使用
		public bool isUse=false;

		public Connect ()
		{
			readBuff=new byte[BUFFER_SIZE];
		}
		//初始化
		//初始化方法,在启用一个连接时会调用该方法,从而给一些变量赋值
		public void Init(Socket socket){
			this.socket = socket;
			isUse = true;
			buffCount = 0;
		}
		//缓冲区剩余的字节数
		public int BuffRemain(){
			return BUFFER_SIZE - buffCount;
		}
		//获取客户端IP地址和端口
		public string GetAdress(){
			if (!isUse) {
				return "无法获取地址";
			}
			return socket.RemoteEndPoint.ToString ();
		}
		//关闭
		public void Close(){
			if (!isUse) {
				return;
			}
			Console.WriteLine ("[断开连接]" + GetAdress ());
			socket.Close ();
			isUse = false;
		}
	}
}


using System;
using System.Net; 
using System.Net.Sockets;
using System.Collections;
using System.Collections.Generic;

namespace AsyncTCPServer
{
	//该类包含一个Connect类型的对象池(数组),用于维护客户端连接。
	public class Server
	{
		//监听嵌套字
		public Socket listenfd;
		//客户端连接
		public Connect[] connects;
		//最大连接数
		public int maxConnectCount=50;

		//开启服务器
		public void Start(string host,int port){
			//连接池
			connects=new Connect[maxConnectCount];
			for (int i = 0; i < maxConnectCount; i++) {
				connects [i] = new Connect ();
			}
			//Socket连接的流程
			//socket
			listenfd =new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
			//Bind
			IPAddress ipAdr=IPAddress.Parse(host);
			IPEndPoint ipEp = new IPEndPoint (ipAdr, port);
			listenfd.Bind (ipEp);
			//Listen
			listenfd.Listen(maxConnectCount);
			//Accept
			listenfd.BeginAccept(AcceptCb,null);
			Console.WriteLine ("[服务器]启动成功");
		}
		//获取连接池索引,返回负数表示获取失败
		public int NewIndex(){
			if (connects == null) {
				return -1;
			}
			for (int i = 0; i < connects.Length; i++) {
				if (connects [i] == null) {
					connects [i] = new Connect ();
					return i;
				} else if (connects [i].isUse == false) {
					return i;
				}
			}
			return -1;
		}
		//Accept是BeginAccept的回调函数,它成立了如下3件事情
		//(1)给新的连接分配connect
		//(2)异步接收客户端数据
		//(3)再次调用BeginAccept实现循环
		//Accept回调
		private void AcceptCb(IAsyncResult ar){
			try{
				Socket socket=listenfd.EndAccept(ar);
				int index=NewIndex();

				if(index<0){
					socket.Close();
					Console.WriteLine("[警告]连接已满");
				}else{
					Connect connect=connects[index];
					connect.Init(socket);
					string adr=connect.GetAdress();
					Console.WriteLine("客户端["+adr+"]connect池ID:"+index);
					connect.socket.BeginReceive(connect.readBuff,connect.buffCount,connect.BuffRemain(),SocketFlags.None,ReceiveCb,connect);
				}
				listenfd.BeginAccept(AcceptCb,null);
			}catch(Exception e){
				Console.WriteLine ("AcceptCb失败:" + e.Message);
			}
		}
		//ReceiveCb是BeginReceive的回调函数,它处理了3件事情
		//(1)接收并处理消息,因为有多个客户端,服务端收到消息后,要把它转发给所有人
		//(2)如果收到客户端关闭连接的信号(count==0),则断开连接
		//(3)继续调用BeginReceive接收下一个数据
		//Receive回调
		private void ReceiveCb(IAsyncResult ar){
			Connect connect = (Connect)ar.AsyncState;
			try{
				int count=connect.socket.EndReceive(ar);
				//关闭信号
				if(count<=0){
					Console.WriteLine("收到["+connect.GetAdress()+"]断开连接");
					connect.Close();
					return;
				}
				//数据处理
				string str=System.Text.Encoding.UTF8.GetString(connect.readBuff,0,count);
				Console.WriteLine("收到["+connect.GetAdress()+"]数据:"+str);
				str=connect.GetAdress()+":"+str;
				byte[] bytes=System.Text.Encoding.Default.GetBytes(str);
				//广播
				for(int i=0;i<connects.Length;i++){
					if(connects[i]==null){
						continue;
					}
					if(!connects[i].isUse){
						continue;
					}
					Console.WriteLine("将消息转播给"+connects[i].GetAdress());
					connects[i].socket.Send(bytes);
				}
				//继续接收
				connect.socket.BeginReceive(connect.readBuff,connect.buffCount,connect.BuffRemain(),SocketFlags.None,ReceiveCb,connect);
			}catch(Exception e){
				Console.WriteLine ("AcceptCb失败:" + e.Message);
				Console.WriteLine ("收到[" + connect.GetAdress () + "]断开连接");
				connect.Close ();
			}
		}
	}
}
异步服务端示意图如下:


using System;
using System.Net; 
using System.Net.Sockets;
using System.Collections;
using System.Collections.Generic;

namespace AsyncTCPServer
{
	class MainClass
	{
		public static void Main (string[] args)
		{
			Server server = new Server ();
			server.Start ("127.0.0.1",1234);
			while (true) {
				string str = Console.ReadLine ();
				switch (str) {
				case "quit":
					return;
				}
			}
		}
	}
}
2.客户端代码如下:
using System;
using System.Net;
using System.Net.Sockets;

namespace AsyncTCPClient
{
	public class Client
	{
		//Socket和接收缓存区
		private Socket socket;
		private byte[] readBuff;
		private const int BUFFER_SIZE = 1024;

		//启动客户端
		public void Start(string host,int port){
			//Socket
			socket = new Socket (AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
			//Connect
			socket.Connect(host,port);
			//Receive
			readBuff=new byte[BUFFER_SIZE];
			socket.BeginReceive (readBuff, 0, BUFFER_SIZE, SocketFlags.None, ReceiveCb, null);
		}
		//接收回调
		private void ReceiveCb(IAsyncResult ar){
			try {
				//count是接收数据的大小
				int count = socket.EndReceive (ar);
				//数据处理
				string str = System.Text.Encoding.UTF8.GetString (readBuff, 0, count);
				Console.WriteLine(str);
				//继续接收
				socket.BeginReceive (readBuff, 0, BUFFER_SIZE, SocketFlags.None, ReceiveCb, null);
			} catch (Exception e) {
				Console.WriteLine (e.Message);
				Console.WriteLine ("连接已断开");
				socket.Close ();
			}
		}
		//发送回调
		public void Send(string str){
			byte[] bytes = System.Text.Encoding.Default.GetBytes (str);
			try {
				socket.Send (bytes);
			} catch {
			}
		}
	}
}

using System;
using System.Net;
using System.Net.Sockets;

namespace AsyncTCPClient
{
	class MainClass
	{
		public static void Main (string[] args)
		{
			Client client = new Client ();
			client.Start ("127.0.0.1", 1234);
			Console.ReadKey ();

			while (true) {
				string str = Console.ReadLine ();
				if (str == "quit") {
					return;
				} else {
					client.Send (str);
				}
			}
		}
	}
}
3.运行结果如下:


  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值