C#编写的Socket基于通道的服务端

本文是继C#编写的Socket客户端通道发送队列的续集。有客户端还需要服务端,服务端也要采用通道的方式来创建。

 连接服务类基类

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

namespace Network
{
    /// <summary>
    /// 连接服务类基类
    /// </summary>
    public abstract class Server
    {
        #region 属性
        /// <summary>
        /// 通道连接事件
        /// </summary>
        public virtual event EventChannelConnect ChannelConnect;
        /// <summary>
        /// 通道断开事件
        /// </summary>
        public virtual event EventChannelDispose ChannelDispose;
        /// <summary>
        /// 通道错误事件
        /// </summary>
        public virtual event EventChannelError ChannelError;
        /// <summary>
        /// 获取本地套接字
        /// </summary>
        public Socket LocalSocket { get; protected set; }
        /// <summary>
        /// 获取服务器本地监听IP地址
        /// </summary>
        public string LocalHost { get; protected set; }
        /// <summary>
        /// 获取服务器本地绑定或监听端口
        /// </summary>
        public int LocalPort { get; protected set; }
        /// <summary>
        /// 获取连接客户端管理实例
        /// </summary>
        public ListLocker<Channel> Channels { get; protected set; }
        /// <summary>
        /// 用户标识对象
        /// </summary>
        public object Tag { get; set; }
        #endregion

        #region 事件处理
        /// <summary>
        /// 通道连接事件处理
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="arg"></param>
        protected virtual void OnChannelConnect(object sender, ChannelConnectArg arg)
        {
#if FUNCINLOG
			Log.WriteLog4("TCPServer.OnChannelConnect(sender, arg) in.", LOGTYPE.DEBUG);
#endif
            if (ChannelConnect != null)
            {
                try
                {
                    ChannelConnect(sender, arg);
                }
                catch (Exception ex)
                {
                    Log.WriteLog4Ex("Network Server event error", ex);
                    if (ex.Message == "等待连接超时!")
                    {
                        arg.SocketError = SocketError.SocketError;
                    }
                }
            }

            if (arg.SocketError == SocketError.Success)
            {
                try
                {
                    Channels.Enter();
                    Channels.Add(arg.Channel);
                }
                finally
                {
                    Channels.Exit();
                }
            }
#if FUNCOUTLOG
			Log.WriteLog4("TCPServer.OnChannelConnect(sender, arg) out.", LOGTYPE.DEBUG);
#endif
        }

        /// <summary>
        /// 通道释放事件处理
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="arg"></param>
        protected virtual void OnChannelDispose(object sender, ChannelDisposeArg arg)
        {
#if FUNCINLOG
			Log.WriteLog4("TCPServer.OnChannelDispose(sender, arg) in.", LOGTYPE.DEBUG);
#endif
            if (ChannelDispose != null)
            {
                try
                {
                    ChannelDispose(this, arg);
                }
                catch (Exception ex)
                {
                    Log.WriteLog4Ex("Network Server event error", ex);
                }
            }
            try
            {
                Channels.Enter();
                Channels.Remove(arg.Channel);
            }
            finally
            {
                Channels.Exit();
            }
#if FUNCOUTLOG
			Log.WriteLog4("TCPServer.OnChannelDispose(sender, arg) out.", LOGTYPE.DEBUG);
#endif
        }

        /// <summary>
        /// 通道异常事件处理
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="arg"></param>
        protected virtual void OnChannelError(object sender, ChannelErrorArg arg)
        {
#if FUNCINLOG
			Log.WriteLog4("TCPServer.OnChannelError(sender, arg) in.", LOGTYPE.DEBUG);
#endif
            if (ChannelError != null)
            {
                try
                {
                    ChannelError(this, arg);
                }
                catch (Exception ex)
                {
                    Log.WriteLog4Ex("Network Server event error", ex);
                }
            }
            try
            {
                Channels.Enter();
                Channels.Remove(arg.Channel);
            }
            finally
            {
                Channels.Exit();
            }
#if FUNCOUTLOG
			Log.WriteLog4("TCPServer.OnChannelError(sender, arg) out.", LOGTYPE.DEBUG);
#endif
        }
        #endregion

        #region 公共方法
        /// <summary>
        /// 构造方法
        /// </summary>
        public Server()
        {
            Channels = new ListLocker<Channel>();
            LocalSocket = null;
        }

        /// <summary>
        /// 开启服务器
        /// </summary>
        /// <returns>成功返回true,否则返回false</returns>
        public virtual bool Start()
        {
            return true;
        }

        /// <summary>
        /// 停止服务器
        /// </summary>
        public virtual void Stop()
        {
            Channel[] channels;
            try
            {
                Channels.Enter();
                channels = Channels.ToArray();
                Channels.Clear();
            }
            finally
            {
                Channels.Exit();
            }

            foreach (var channel in channels)
            {
                channel.Close();
            }
        }
        #endregion

        #region 内部方法
        /// <summary>
        /// 通过连接套接字创建通道
        /// </summary>
        /// <param name="socket">连接套接字</param>
        /// <param name="channel">子类已创建通道.如果非空,则基类在现有通道实例上处理</param>
        /// <returns>创建的通道实例.非空进创建成功,否则失败</returns>
        protected virtual Channel CreateChannelBySocket(Socket socket, Channel channel = null)
        {
            if (channel == null)
                return null;
            else
            {
                channel.ChannelDispose += OnChannelDispose;
                channel.ChannelError += OnChannelError;
                return channel;
            }
        }
        #endregion
    }
}

TCP 连接服务类

TCPServer 继承自Server类:

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

namespace Network
{
	/// <summary>
	/// TCP通道服务
	/// </summary>
	/// <remarks>内部方法注释请参照基类</remarks>
	public class TCPServer : Server
	{
		#region 公共方法
		/// <summary>
		/// TCP通道服务构造函数
		/// </summary>
		/// <param name="localHost">本地绑定网卡地址</param>
		/// <param name="localPort">本地端口号</param>
		public TCPServer(string localHost, int localPort)
		{
			LocalHost = localHost;
			LocalPort = localPort;
		}

		/// <summary>
		/// 开启服务器
		/// </summary>
		/// <returns>成功返回true,否则返回false</returns>
		public override bool Start()
		{
			try
			{
				if (LocalSocket == null)
				{
					LocalSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
					LocalSocket.Bind(new IPEndPoint(IPAddress.Parse(LocalHost), LocalPort));
					LocalSocket.Listen(64);

					SocketAsyncEventArgs e = Managers.SocketArgManager.Allocate(false);
					e.Completed += IO_Completed;
					if (LocalSocket != null && !LocalSocket.AcceptAsync(e))
					{
						OnConnect(e);
					}
					return base.Start();
				}
				else
					return false;
			}
			catch (Exception ex)
			{
				Log.WriteLog4Ex("Server启动失败", ex);
				return false;
			}
		}

		/// <summary>
		/// 停止服务器
		/// </summary>
		public override void Stop()
		{
			try
			{
				if (LocalSocket != null)
				{
					LocalSocket.Close();
					LocalSocket.Dispose();
					LocalSocket = null;

					base.Stop();
				}
				else
					Log.WriteLog4("Server停止失败.服务已停止.", LOGTYPE.WARN);
			}
			catch (Exception ex)
			{
				Log.WriteLog4Ex("Server停止失败", ex);
			}
		}
		#endregion

		#region 异步请求结果处理
		/// <summary>
		/// 通道连接IO完成时调用
		/// </summary>
		/// <param name="e"></param>
		private void OnConnect(SocketAsyncEventArgs e)
		{
#if FUNCINLOG
			Log.WriteLog4("TCPServer.OnConnect(e) in.", LOGTYPE.DEBUG);
#endif
			Channel channel = null;
			if (e.SocketError == SocketError.Success)
				channel = CreateChannelBySocket(e.AcceptSocket);
			e.AcceptSocket = null;
			OnChannelConnect(this, new ChannelConnectArg(channel, e.SocketError));

			while (LocalSocket != null && !LocalSocket.AcceptAsync(e))
			{
				channel = null;
				if (e.SocketError == SocketError.Success)
					channel = CreateChannelBySocket(e.AcceptSocket);
				e.AcceptSocket = null;
				OnChannelConnect(this, new ChannelConnectArg(channel, e.SocketError));
			}
#if FUNCOUTLOG
			Log.WriteLog4("TCPServer.OnConnect(e) out.", LOGTYPE.DEBUG);
#endif
		}
		#endregion

		#region 内部方法
		/// <summary>
		/// 异步请求回调处理方法
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void IO_Completed(object sender, SocketAsyncEventArgs e)
		{
#if FUNCINLOG
			Log.WriteLog4("TCPServer.IO_Completed(sender, e) in.", LOGTYPE.DEBUG);
#endif
			try
			{
				switch (e.LastOperation)
				{
					case SocketAsyncOperation.Accept:
						OnConnect(e);
						break;
				}
			}
			catch (Exception ex)
			{
				Log.WriteLog4Ex("TCPServer.IO_Completed(sender, e) error", ex);
			}
#if FUNCOUTLOG
			Log.WriteLog4("TCPServer.IO_Completed(sender, e) out.", LOGTYPE.DEBUG);
#endif
		}

		/// <summary>
		/// 通过连接套接字创建通道
		/// </summary>
		/// <param name="socket">连接套接字</param>
		/// <param name="channel">子类已创建通道.如果非空,则基类在现有通道实例上处理</param>
		/// <returns>创建的通道实例.非空进创建成功,否则失败</returns>
		protected override Channel CreateChannelBySocket(Socket socket, Channel channel = null)
		{
#if FUNCINLOG
			Log.WriteLog4("TCPServer.CreateChannelBySocket(socket) in.", LOGTYPE.DEBUG);
#endif
			if (channel == null)
				channel = new TCPChannel(socket);
#if FUNCOUTLOG
			Log.WriteLog4("TCPServer.CreateChannelBySocket(socket) out.", LOGTYPE.DEBUG);
#endif
			return base.CreateChannelBySocket(socket, channel);
		}
		#endregion
	}
}

如何使用初始化服务端

建立一个本地服务端连接:

 Network.TCPServer ser = new Network.TCPServer("0.0.0.0", 9999);

启动Socket连接:

 ser.ChannelConnect += new Network.EventChannelConnect(ser_ChannelConnect);
 ser.ChannelDispose += new Network.EventChannelDispose(ser_ChannelDispose);
 ser.Start();

要保证服务端不出问题,还需要实现通道的连接事件和释放事件方法,此处不提。



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值