关键词搜索

源码搜索 ×
×

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

发布2018-01-08浏览1075次

详情内容

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

 连接服务类基类

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Net.Sockets;
  6. using System.Net;
  7. using SQ.Base;
  8. namespace Network
  9. {
  10. /// <summary>
  11. /// 连接服务类基类
  12. /// </summary>
  13. public abstract class Server
  14. {
  15. #region 属性
  16. /// <summary>
  17. /// 通道连接事件
  18. /// </summary>
  19. public virtual event EventChannelConnect ChannelConnect;
  20. /// <summary>
  21. /// 通道断开事件
  22. /// </summary>
  23. public virtual event EventChannelDispose ChannelDispose;
  24. /// <summary>
  25. /// 通道错误事件
  26. /// </summary>
  27. public virtual event EventChannelError ChannelError;
  28. /// <summary>
  29. /// 获取本地套接字
  30. /// </summary>
  31. public Socket LocalSocket { get; protected set; }
  32. /// <summary>
  33. /// 获取服务器本地监听IP地址
  34. /// </summary>
  35. public string LocalHost { get; protected set; }
  36. /// <summary>
  37. /// 获取服务器本地绑定或监听端口
  38. /// </summary>
  39. public int LocalPort { get; protected set; }
  40. /// <summary>
  41. /// 获取连接客户端管理实例
  42. /// </summary>
  43. public ListLocker<Channel> Channels { get; protected set; }
  44. /// <summary>
  45. /// 用户标识对象
  46. /// </summary>
  47. public object Tag { get; set; }
  48. #endregion
  49. #region 事件处理
  50. /// <summary>
  51. /// 通道连接事件处理
  52. /// </summary>
  53. /// <param name="sender"></param>
  54. /// <param name="arg"></param>
  55. protected virtual void OnChannelConnect(object sender, ChannelConnectArg arg)
  56. {
  57. #if FUNCINLOG
  58. Log.WriteLog4("TCPServer.OnChannelConnect(sender, arg) in.", LOGTYPE.DEBUG);
  59. #endif
  60. if (ChannelConnect != null)
  61. {
  62. try
  63. {
  64. ChannelConnect(sender, arg);
  65. }
  66. catch (Exception ex)
  67. {
  68. Log.WriteLog4Ex("Network Server event error", ex);
  69. if (ex.Message == "等待连接超时!")
  70. {
  71. arg.SocketError = SocketError.SocketError;
  72. }
  73. }
  74. }
  75. if (arg.SocketError == SocketError.Success)
  76. {
  77. try
  78. {
  79. Channels.Enter();
  80. Channels.Add(arg.Channel);
  81. }
  82. finally
  83. {
  84. Channels.Exit();
  85. }
  86. }
  87. #if FUNCOUTLOG
  88. Log.WriteLog4("TCPServer.OnChannelConnect(sender, arg) out.", LOGTYPE.DEBUG);
  89. #endif
  90. }
  91. /// <summary>
  92. /// 通道释放事件处理
  93. /// </summary>
  94. /// <param name="sender"></param>
  95. /// <param name="arg"></param>
  96. protected virtual void OnChannelDispose(object sender, ChannelDisposeArg arg)
  97. {
  98. #if FUNCINLOG
  99. Log.WriteLog4("TCPServer.OnChannelDispose(sender, arg) in.", LOGTYPE.DEBUG);
  100. #endif
  101. if (ChannelDispose != null)
  102. {
  103. try
  104. {
  105. ChannelDispose(this, arg);
  106. }
  107. catch (Exception ex)
  108. {
  109. Log.WriteLog4Ex("Network Server event error", ex);
  110. }
  111. }
  112. try
  113. {
  114. Channels.Enter();
  115. Channels.Remove(arg.Channel);
  116. }
  117. finally
  118. {
  119. Channels.Exit();
  120. }
  121. #if FUNCOUTLOG
  122. Log.WriteLog4("TCPServer.OnChannelDispose(sender, arg) out.", LOGTYPE.DEBUG);
  123. #endif
  124. }
  125. /// <summary>
  126. /// 通道异常事件处理
  127. /// </summary>
  128. /// <param name="sender"></param>
  129. /// <param name="arg"></param>
  130. protected virtual void OnChannelError(object sender, ChannelErrorArg arg)
  131. {
  132. #if FUNCINLOG
  133. Log.WriteLog4("TCPServer.OnChannelError(sender, arg) in.", LOGTYPE.DEBUG);
  134. #endif
  135. if (ChannelError != null)
  136. {
  137. try
  138. {
  139. ChannelError(this, arg);
  140. }
  141. catch (Exception ex)
  142. {
  143. Log.WriteLog4Ex("Network Server event error", ex);
  144. }
  145. }
  146. try
  147. {
  148. Channels.Enter();
  149. Channels.Remove(arg.Channel);
  150. }
  151. finally
  152. {
  153. Channels.Exit();
  154. }
  155. #if FUNCOUTLOG
  156. Log.WriteLog4("TCPServer.OnChannelError(sender, arg) out.", LOGTYPE.DEBUG);
  157. #endif
  158. }
  159. #endregion
  160. #region 公共方法
  161. /// <summary>
  162. /// 构造方法
  163. /// </summary>
  164. public Server()
  165. {
  166. Channels = new ListLocker<Channel>();
  167. LocalSocket = null;
  168. }
  169. /// <summary>
  170. /// 开启服务器
  171. /// </summary>
  172. /// <returns>成功返回true,否则返回false</returns>
  173. public virtual bool Start()
  174. {
  175. return true;
  176. }
  177. /// <summary>
  178. /// 停止服务器
  179. /// </summary>
  180. public virtual void Stop()
  181. {
  182. Channel[] channels;
  183. try
  184. {
  185. Channels.Enter();
  186. channels = Channels.ToArray();
  187. Channels.Clear();
  188. }
  189. finally
  190. {
  191. Channels.Exit();
  192. }
  193. foreach (var channel in channels)
  194. {
  195. channel.Close();
  196. }
  197. }
  198. #endregion
  199. #region 内部方法
  200. /// <summary>
  201. /// 通过连接套接字创建通道
  202. /// </summary>
  203. /// <param name="socket">连接套接字</param>
  204. /// <param name="channel">子类已创建通道.如果非空,则基类在现有通道实例上处理</param>
  205. /// <returns>创建的通道实例.非空进创建成功,否则失败</returns>
  206. protected virtual Channel CreateChannelBySocket(Socket socket, Channel channel = null)
  207. {
  208. if (channel == null)
  209. return null;
  210. else
  211. {
  212. channel.ChannelDispose += OnChannelDispose;
  213. channel.ChannelError += OnChannelError;
  214. return channel;
  215. }
  216. }
  217. #endregion
  218. }
  219. }

TCP 连接服务类

TCPServer 继承自Server类:

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Net.Sockets;
  6. using System.Net;
  7. using SQ.Base;
  8. namespace Network
  9. {
  10. /// <summary>
  11. /// TCP通道服务
  12. /// </summary>
  13. /// <remarks>内部方法注释请参照基类</remarks>
  14. public class TCPServer : Server
  15. {
  16. #region 公共方法
  17. /// <summary>
  18. /// TCP通道服务构造函数
  19. /// </summary>
  20. /// <param name="localHost">本地绑定网卡地址</param>
  21. /// <param name="localPort">本地端口号</param>
  22. public TCPServer(string localHost, int localPort)
  23. {
  24. LocalHost = localHost;
  25. LocalPort = localPort;
  26. }
  27. /// <summary>
  28. /// 开启服务器
  29. /// </summary>
  30. /// <returns>成功返回true,否则返回false</returns>
  31. public override bool Start()
  32. {
  33. try
  34. {
  35. if (LocalSocket == null)
  36. {
  37. LocalSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
  38. LocalSocket.Bind(new IPEndPoint(IPAddress.Parse(LocalHost), LocalPort));
  39. LocalSocket.Listen(64);
  40. SocketAsyncEventArgs e = Managers.SocketArgManager.Allocate(false);
  41. e.Completed += IO_Completed;
  42. if (LocalSocket != null && !LocalSocket.AcceptAsync(e))
  43. {
  44. OnConnect(e);
  45. }
  46. return base.Start();
  47. }
  48. else
  49. return false;
  50. }
  51. catch (Exception ex)
  52. {
  53. Log.WriteLog4Ex("Server启动失败", ex);
  54. return false;
  55. }
  56. }
  57. /// <summary>
  58. /// 停止服务器
  59. /// </summary>
  60. public override void Stop()
  61. {
  62. try
  63. {
  64. if (LocalSocket != null)
  65. {
  66. LocalSocket.Close();
  67. LocalSocket.Dispose();
  68. LocalSocket = null;
  69. base.Stop();
  70. }
  71. else
  72. Log.WriteLog4("Server停止失败.服务已停止.", LOGTYPE.WARN);
  73. }
  74. catch (Exception ex)
  75. {
  76. Log.WriteLog4Ex("Server停止失败", ex);
  77. }
  78. }
  79. #endregion
  80. #region 异步请求结果处理
  81. /// <summary>
  82. /// 通道连接IO完成时调用
  83. /// </summary>
  84. /// <param name="e"></param>
  85. private void OnConnect(SocketAsyncEventArgs e)
  86. {
  87. #if FUNCINLOG
  88. Log.WriteLog4("TCPServer.OnConnect(e) in.", LOGTYPE.DEBUG);
  89. #endif
  90. Channel channel = null;
  91. if (e.SocketError == SocketError.Success)
  92. channel = CreateChannelBySocket(e.AcceptSocket);
  93. e.AcceptSocket = null;
  94. OnChannelConnect(this, new ChannelConnectArg(channel, e.SocketError));
  95. while (LocalSocket != null && !LocalSocket.AcceptAsync(e))
  96. {
  97. channel = null;
  98. if (e.SocketError == SocketError.Success)
  99. channel = CreateChannelBySocket(e.AcceptSocket);
  100. e.AcceptSocket = null;
  101. OnChannelConnect(this, new ChannelConnectArg(channel, e.SocketError));
  102. }
  103. #if FUNCOUTLOG
  104. Log.WriteLog4("TCPServer.OnConnect(e) out.", LOGTYPE.DEBUG);
  105. #endif
  106. }
  107. #endregion
  108. #region 内部方法
  109. /// <summary>
  110. /// 异步请求回调处理方法
  111. /// </summary>
  112. /// <param name="sender"></param>
  113. /// <param name="e"></param>
  114. private void IO_Completed(object sender, SocketAsyncEventArgs e)
  115. {
  116. #if FUNCINLOG
  117. Log.WriteLog4("TCPServer.IO_Completed(sender, e) in.", LOGTYPE.DEBUG);
  118. #endif
  119. try
  120. {
  121. switch (e.LastOperation)
  122. {
  123. case SocketAsyncOperation.Accept:
  124. OnConnect(e);
  125. break;
  126. }
  127. }
  128. catch (Exception ex)
  129. {
  130. Log.WriteLog4Ex("TCPServer.IO_Completed(sender, e) error", ex);
  131. }
  132. #if FUNCOUTLOG
  133. Log.WriteLog4("TCPServer.IO_Completed(sender, e) out.", LOGTYPE.DEBUG);
  134. #endif
  135. }
  136. /// <summary>
  137. /// 通过连接套接字创建通道
  138. /// </summary>
  139. /// <param name="socket">连接套接字</param>
  140. /// <param name="channel">子类已创建通道.如果非空,则基类在现有通道实例上处理</param>
  141. /// <returns>创建的通道实例.非空进创建成功,否则失败</returns>
  142. protected override Channel CreateChannelBySocket(Socket socket, Channel channel = null)
  143. {
  144. #if FUNCINLOG
  145. Log.WriteLog4("TCPServer.CreateChannelBySocket(socket) in.", LOGTYPE.DEBUG);
  146. #endif
  147. if (channel == null)
  148. channel = new TCPChannel(socket);
  149. #if FUNCOUTLOG
  150. Log.WriteLog4("TCPServer.CreateChannelBySocket(socket) out.", LOGTYPE.DEBUG);
  151. #endif
  152. return base.CreateChannelBySocket(socket, channel);
  153. }
  154. #endregion
  155. }
  156. }

如何使用初始化服务端

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

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

启动Socket连接:

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

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



相关技术文章

点击QQ咨询
开通会员
返回顶部
×
微信扫码支付
微信扫码支付
确定支付下载
请使用微信描二维码支付
×

提示信息

×

选择支付方式

  • 微信支付
  • 支付宝付款
确定支付下载