本文是继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();
要保证服务端不出问题,还需要实现通道的连接事件和释放事件方法,此处不提。