C# TCP异步通讯框架封装

2 篇文章 0 订阅
1 篇文章 0 订阅

最近用c#写了一个TCP异步通讯框架TCPHelper,用于服务端客户端通讯,采用异步和事件驱动的方式,使用者只需要初始化和装载事件即可使用,框架图粗略如下所示:
这里写图片描述
使用如下:(本文框架及实例下载地址
服务端

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Net;
using System.Threading;
using TCPHelper;

namespace Socket异步请求Server
{
    class Program
    {       
        static void Main(string[] args)
        {           
            ServerAsync server = new ServerAsync();
            server.Completed += new Action<string, TCPHelper.EnSocketAction>((key, enAction) =>
            {
                switch (enAction)
                {
                    case EnSocketAction.Connect:
                        Console.WriteLine("接收到来自{0}的连接",key);
                        break;
                    case EnSocketAction.SendMsg:
                        Console.WriteLine("对{0}发送了一条消息", key);
                        break;
                    case EnSocketAction.Close:
                        Console.WriteLine("{0}关闭了连接", key);
                        break;
                    default:
                        break;
                }
            });
            server.Received += new Action<string, string>((key, msg) =>
            {
                Console.WriteLine("{0}对我说:{1}", key, msg);
            });
            server.StartAsync(10001);
            Console.Read();

        }    
    }
}

客户端:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using TCPHelper;
using System.Net;
using System.Net.Sockets;

namespace Socket异步请求Client
{
    class Program
    {
        static void Main(string[] args)
        {
            ClientAsync client = new ClientAsync();
            client.Completed += new Action<System.Net.Sockets.TcpClient, EnSocketAction>((c, enAction) =>
            {
                IPEndPoint iep = c.Client.RemoteEndPoint as IPEndPoint;
                string key = string.Format("{0}:{1}", iep.Address.ToString(), iep.Port);
                switch (enAction)
                {
                    case EnSocketAction.Connect:
                        Console.WriteLine("已经与{0}建立连接",key);
                        break;
                    case EnSocketAction.SendMsg:
                        Console.WriteLine("{0}:向{1}发送了一条消息",DateTime.Now,key);
                        break;
                    case EnSocketAction.Close:
                        Console.WriteLine("服务端连接关闭");
                        break;
                    default:
                        break;
                }
            });
            client.Received += new Action<string,string>((key,msg)=>
            {
                Console.WriteLine("{0}对我说:{1}",key,msg);
            });
            client.ConnectAsync(10001);
            while (true)
            {
                string msg = Console.ReadLine();
                client.SendAsync(msg);
            }
        }
    }
}

上面所引用的TCPHelper为所用的框架,下载地址:点击这里下载
框架的源码也贴出来:
ClientAsync.cs:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Net;
using System.Threading;
namespace TCPHelper
{
   public class ClientAsync
    {
       private TcpClient client;
       /// <summary>
       /// 客户端连接完成、发送完成、连接异常或者服务端关闭触发的事件
       /// </summary>
       public event Action<TcpClient,EnSocketAction> Completed;
       /// <summary>
       /// 客户端接收消息触发的事件
       /// </summary>
       public event Action<string,string> Received;
       /// <summary>
       /// 用于控制异步接收消息
       /// </summary>
       private ManualResetEvent doReceive = new ManualResetEvent(false);
       //标识客户端是否关闭
       private bool isClose = false;
       public ClientAsync()
       {
           client = new TcpClient();
       }
       /// <summary>
       /// 异步连接
       /// </summary>
       /// <param name="ip">要连接的服务器的ip地址</param>
       /// <param name="port">要连接的服务器的端口</param>
       public void ConnectAsync(string ip, int port)
       {
           IPAddress ipAddress = null;
           try
           {
               ipAddress = IPAddress.Parse(ip);
           }
           catch (Exception)
           {
               throw new Exception("ip地址格式不正确,请使用正确的ip地址!");
           }
           client.BeginConnect(ipAddress, port,ConnectCallBack, client);
       }
       /// <summary>
       /// 异步连接,连接ip地址为127.0.0.1
       /// </summary>
       /// <param name="port">要连接服务端的端口</param>
       public void ConnectAsync(int port)
       {
           ConnectAsync("127.0.0.1", port);
       }
       /// <summary>
       /// 异步接收消息
       /// </summary>
       private void ReceiveAsync()
       {
           doReceive.Reset();
           StateObject obj=new StateObject();
           obj.Client=client;

           client.Client.BeginReceive(obj.ListData, 0, obj.ListData.Length, SocketFlags.None, ReceiveCallBack, obj);
           doReceive.WaitOne();
       }
       /// <summary>
       /// 异步发送消息
       /// </summary>
       /// <param name="msg"></param>
        public void SendAsync(string msg)
        {
            byte[] listData=Encoding.UTF8.GetBytes(msg);
            client.Client.BeginSend(listData, 0, listData.Length, SocketFlags.None, SendCallBack,client);
        }
       /// <summary>
       /// 异步连接的回调函数
       /// </summary>
       /// <param name="ar"></param>
       private void ConnectCallBack(IAsyncResult ar)
       {
           TcpClient client = ar.AsyncState as TcpClient;
           client.EndConnect(ar);
           OnComplete(client, EnSocketAction.Connect);
       }
       /// <summary>
       /// 异步接收消息的回调函数
       /// </summary>
       /// <param name="ar"></param>
       private void ReceiveCallBack(IAsyncResult ar)
       {
           StateObject obj = ar.AsyncState as StateObject;
           int count=-1;
           try
           {
               count = obj.Client.Client.EndReceive(ar);
               doReceive.Set();
           }
           catch (Exception)
           {
               //如果发生异常,说明客户端失去连接,触发关闭事件
               Close();
               OnComplete(obj.Client, EnSocketAction.Close);
           }
           if (count > 0)
           {
               string msg = Encoding.UTF8.GetString(obj.ListData, 0, count);
               if (!string.IsNullOrEmpty(msg))
               {
                   if (Received != null)
                   {
                       IPEndPoint iep = obj.Client.Client.RemoteEndPoint as IPEndPoint;
                       string key = string.Format("{0}:{1}", iep.Address, iep.Port);
                       Received(key,msg);
                   }
               }
           }
       }
       private void SendCallBack(IAsyncResult ar)
       {
           TcpClient client = ar.AsyncState as TcpClient;
           try
           {
               client.Client.EndSend(ar);
               OnComplete(client, EnSocketAction.SendMsg);
           }
           catch (Exception)
           {
               //如果发生异常,说明客户端失去连接,触发关闭事件
               Close();
               OnComplete(client, EnSocketAction.Close);
           }
       }
       public virtual void OnComplete(TcpClient client, EnSocketAction enAction)
       {
           if (Completed != null)
               Completed(client, enAction);
           if (enAction == EnSocketAction.Connect)//建立连接后,开始接收数据
           {
               ThreadPool.QueueUserWorkItem(x =>
                   {
                       while (!isClose)
                       {
                           try
                           {
                               Thread.Sleep(20);
                               ReceiveAsync();
                               Thread.Sleep(20);
                           }
                           catch (Exception)
                           {
                               Close();
                               OnComplete(client, EnSocketAction.Close);
                           }
                       }
                   });
           }
       }

       public void Close()
       {
           isClose = true;
       }
    }
}

ServerAsync.cs:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Threading;

namespace TCPHelper
{
    public class ServerAsync
    {
        private TcpListener listener = null;

        //用于控制异步接受连接
        private ManualResetEvent doConnect = new ManualResetEvent(false);
        //用于控制异步接收数据
        private ManualResetEvent doReceive=new ManualResetEvent(false);
        //标识服务端连接是否关闭
        private bool isClose = false;
        private Dictionary<string,TcpClient> listClient=new Dictionary<string,TcpClient>();
        /// <summary>
        /// 已建立连接的集合
        /// key:ip:port
        /// value:TcpClient
        /// </summary>
        public Dictionary<string,TcpClient> ListClient
        {
            get{return listClient;}
            private set{listClient=value;}
        }
        /// <summary>
        /// 连接、发送、关闭事件
        /// </summary>
        public event Action<string,EnSocketAction> Completed;
        /// <summary>
        /// 接收到数据事件
        /// </summary>
        public event Action<string,string> Received;
        public ServerAsync()
        {

        }
        /// <summary>
        /// 开始异步监听ip地址的端口
        /// </summary>
        /// <param name="ip"></param>
        /// <param name="port"></param>
        public void StartAsync(string ip, int port)
        {           

            IPAddress ipAddress=null;
            try
            {
                ipAddress=IPAddress.Parse(ip);
            }
            catch(Exception e)
            {
               throw e;
            }
            listener = new TcpListener(new IPEndPoint(ipAddress, port));
            listener.Start();
            ThreadPool.QueueUserWorkItem(x =>
            {
                while (!isClose)
                {
                    doConnect.Reset();
                    listener.BeginAcceptTcpClient(AcceptCallBack, listener);
                    doConnect.WaitOne();
                }
            });


        }
        /// <summary>
        /// 开始异步监听本机127.0.0.1的端口号
        /// </summary>
        /// <param name="port"></param>
        public void StartAsync(int port)
        {
            StartAsync("127.0.0.1", port);
        }
        /// <summary>
        /// 开始异步发送数据
        /// </summary>
        /// <param name="key">客户端的ip地址和端口号</param>
        /// <param name="msg">要发送的内容</param>
        public void SendAsync(string key, string msg)
        {
            if (!ListClient.ContainsKey(key))
            {
                throw new Exception("所用的socket不在字典中,请先连接!");
            }
            TcpClient client = ListClient[key];
            byte[] listData=Encoding.UTF8.GetBytes(msg);
            client.Client.BeginSend(listData, 0, listData.Length, SocketFlags.None, SendCallBack, client);
        }
        /// <summary>
        /// 开始异步接收数据
        /// </summary>
        /// <param name="key">要接收的客户端的ip地址和端口号</param>
        private void ReceiveAsync(string key)
        {
            doReceive.Reset();
            if (ListClient.ContainsKey(key))
            {
                TcpClient client = ListClient[key];
                //if (!client.Connected)
                //{
                //    ListClient.Remove(key);
                //    OnComplete(key, EnSocketAction.Close);
                //    return;
                //}
                StateObject obj = new StateObject();
                obj.Client = client;
                try
                {
                    client.Client.BeginReceive(obj.ListData, 0, obj.ListData.Length, SocketFlags.None, ReceiveCallBack, obj);
                }
                catch (Exception)
                {

                }
                doReceive.WaitOne();
            }
        }
        /// <summary>
        /// 异步接收连接的回调函数
        /// </summary>
        /// <param name="ar"></param>
        private void AcceptCallBack(IAsyncResult ar)
        {

           TcpListener l= ar.AsyncState as TcpListener;
           TcpClient client = l.EndAcceptTcpClient(ar);
           doConnect.Set();

           IPEndPoint iep = client.Client.RemoteEndPoint as IPEndPoint;
           string key = string.Format("{0}:{1}", iep.Address.ToString(), iep.Port);
           if (!ListClient.ContainsKey(key))
           {
               ListClient.Add(key, client);
               OnComplete(key, EnSocketAction.Connect);
           }

        }
        /// <summary>
        /// 异步发送数据的回调函数
        /// </summary>
        /// <param name="ar"></param>
        private void SendCallBack(IAsyncResult ar)
        {
           TcpClient client= ar.AsyncState as TcpClient;
           IPEndPoint iep = client.Client.RemoteEndPoint as IPEndPoint;
           string key = string.Format("{0}:{1}", iep.Address.ToString(), iep.Port);
           if (Completed != null)
           {
               Completed(key, EnSocketAction.SendMsg);
           }

        }
        /// <summary>
        /// 异步接收数据的回调函数
        /// </summary>
        /// <param name="ar"></param>
        private void ReceiveCallBack(IAsyncResult ar)
        {
            StateObject obj =ar.AsyncState as StateObject;

            int count=-1;
            try
            {
                count = obj.Client.Client.EndReceive(ar);
            }
            catch (Exception e)
            {
                if (!obj.Client.Client.Connected)
                {
                    IPEndPoint iep = obj.Client.Client.RemoteEndPoint as IPEndPoint;
                    string key = string.Format("{0}:{1}", iep.Address.ToString(), iep.Port);

                    ListClient.Remove(key);
                    OnComplete(key, EnSocketAction.Close);
                    doReceive.Set();
                    return;
                }
            }
            doReceive.Set();
            if (count > 0)
            {
                string msg = Encoding.UTF8.GetString(obj.ListData, 0, count);
                if (!string.IsNullOrEmpty(msg))
                {
                    if (Received != null)
                    {
                        IPEndPoint iep = obj.Client.Client.RemoteEndPoint as IPEndPoint;
                        string key = string.Format("{0}:{1}", iep.Address.ToString(), iep.Port);
                        Received(key,msg);//触发接收事件
                    }
                }
            }
        }
        public virtual void OnComplete(string key, EnSocketAction enAction)
        {
            if (Completed != null)
                Completed(key, enAction);
            if (enAction == EnSocketAction.Connect)//当连接建立时,则要一直接收
            {
                ThreadPool.QueueUserWorkItem(x =>
                {
                    while (ListClient.ContainsKey(key)&&!isClose)
                    {
                        Thread.Sleep(20);
                        ReceiveAsync(key);
                        Thread.Sleep(20);
                    }
                });

            }
        }
        public void Close()
        {
            isClose=true;
        }
    }

}

其他:

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

namespace TCPHelper
{
    /// <summary>
    /// 接收socket的行为
    /// </summary>
    public enum EnSocketAction
    {
        /// <summary>
        /// socket发生连接
        /// </summary>
        Connect = 1,
        /// <summary>
        /// socket发送数据
        /// </summary>
        SendMsg = 2,
        /// <summary>
        /// socket关闭
        /// </summary>
        Close = 4
    }
    /// <summary>
    /// 对异步接收时的对象状态的封装,将socket与接收到的数据封装在一起
    /// </summary>
    public class StateObject
    {
        public TcpClient Client { get; set; }
        private byte[] listData = new byte[2048];
        /// <summary>
        /// 接收的数据
        /// </summary>
        public byte[] ListData
        {
            get
            {
                return listData;
            }
            set
            {
                listData = value;
            }
        }
    }
}

当然此框架目前只能发送接收字符串,待添加发送接收byte的功能。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值