C#网络编程系列文章(四)之TcpListener实现同步TCP服务器

本文主要是介绍C#网络编程系列文章(四)之TcpListener实现同步TCP服务器,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

原创性声明

本文作者:小竹zz 本文地址http://blog.csdn.net/zhujunxxxxx/article/details/44258719 转载请注明出处

文章系列目录

C#网络编程系列文章(一)之Socket实现异步TCP服务器 

C#网络编程系列文章(二)之Socket实现同步TCP服务器

C#网络编程系列文章(三)之TcpListener实现异步TCP服务器

C#网络编程系列文章(四)之TcpListener实现同步TCP服务器

C#网络编程系列文章(五)之Socket实现异步UDP服务器

C#网络编程系列文章(六)之Socket实现同步UDP服务器

C#网络编程系列文章(七)之UdpClient实现异步UDP服务器

C#网络编程系列文章(八)之UdpClient实现同步UDP服务器

本文介绍

TcpListener 类提供一些简单方法,用于在阻止同步模式下侦听和接受传入连接请求。 可使用 TcpClient 或 Socket 来连接 TcpListener。 可使用 IPEndPoint、本地 IP 地址及端口号或者仅使用端口号,来创建 TcpListener。 可以将本地 IP 地址指定为 Any,将本地端口号指定为 0(如果希望基础服务提供程序为您分配这些值)。 如果您选择这样做,可在连接套接字后使用 LocalEndpoint 属性来标识已指定的信息。使用 Start 方法,可开始侦听传入的连接请求。 Start 将对传入连接进行排队,直至您调用 Stop 方法或它已经完成 MaxConnections 排队为止。 可使用 AcceptSocket 或 AcceptTcpClient 从传入连接请求队列提取连接。 这两种方法将阻止。 如果要避免阻止,可首先使用 Pending 方法来确定队列中是否有可用的连接请求。
虽然TcpListener已经封装的比较不错了,我们于是就使用它在构造一个比较不错的同步TCP服务器,这里依然和前两章一样,给出服务器中的代码,代码中注释很详细,我也会给出相关的封装类。

TcpListener同步TCP服务器

[csharp]  view plain  copy
  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 System.Threading;  
  8.   
  9. namespace NetFrame.Net.TCP.Listener.Synchronous  
  10. {  
  11.     /// <summary>  
  12.     /// TcpListener实现同步TCP服务器  
  13.     /// </summary>  
  14.     public class TCPServer  
  15.     {  
  16.         #region Fields  
  17.         /// <summary>  
  18.         /// 服务器程序允许的最大客户端连接数  
  19.         /// </summary>  
  20.         private int _maxClient;  
  21.   
  22.         /// <summary>  
  23.         /// 当前的连接的客户端数  
  24.         /// </summary>  
  25.         private int _clientCount;  
  26.   
  27.         /// <summary>  
  28.         /// 服务器使用的异步TcpListener  
  29.         /// </summary>  
  30.         private TcpListener _listener;  
  31.   
  32.         /// <summary>  
  33.         /// 客户端会话列表  
  34.         /// </summary>  
  35.         private List<TCPClientHandle> _clients;  
  36.   
  37.         private bool disposed = false;  
  38.  
  39.         #endregion  
  40.  
  41.         #region Properties  
  42.   
  43.         /// <summary>  
  44.         /// 服务器是否正在运行  
  45.         /// </summary>  
  46.         public bool IsRunning { getprivate set; }  
  47.         /// <summary>  
  48.         /// 监听的IP地址  
  49.         /// </summary>  
  50.         public IPAddress Address { getprivate set; }  
  51.         /// <summary>  
  52.         /// 监听的端口  
  53.         /// </summary>  
  54.         public int Port { getprivate set; }  
  55.         /// <summary>  
  56.         /// 通信使用的编码  
  57.         /// </summary>  
  58.         public Encoding Encoding { getset; }  
  59.  
  60.         #endregion  
  61.  
  62.         #region 构造器  
  63.         /// <summary>  
  64.         /// 同步TCP服务器  
  65.         /// </summary>  
  66.         /// <param name="listenPort">监听的端口</param>  
  67.         public TCPServer(int listenPort)  
  68.             : this(IPAddress.Any, listenPort, 1024)  
  69.         {  
  70.         }  
  71.   
  72.         /// <summary>  
  73.         /// 同步TCP服务器  
  74.         /// </summary>  
  75.         /// <param name="localEP">监听的终结点</param>  
  76.         public TCPServer(IPEndPoint localEP)  
  77.             : this(localEP.Address, localEP.Port, 1024)  
  78.         {  
  79.         }  
  80.   
  81.         /// <summary>  
  82.         /// 同步TCP服务器  
  83.         /// </summary>  
  84.         /// <param name="localIPAddress">监听的IP地址</param>  
  85.         /// <param name="listenPort">监听的端口</param>  
  86.         /// <param name="maxClient">最大客户端数量</param>  
  87.         public TCPServer(IPAddress localIPAddress, int listenPort, int maxClient)  
  88.         {  
  89.             this.Address = localIPAddress;  
  90.             this.Port = listenPort;  
  91.             this.Encoding = Encoding.Default;  
  92.   
  93.             _maxClient = maxClient;  
  94.             _clients = new List<TCPClientHandle>();  
  95.             _listener = new TcpListener(new IPEndPoint(this.Address, this.Port));  
  96.         }  
  97.  
  98.         #endregion  
  99.  
  100.         #region Method  
  101.         /// <summary>  
  102.         /// 启动服务器  
  103.         /// </summary>  
  104.         public void Start()  
  105.         {  
  106.             if (!IsRunning)  
  107.             {  
  108.                 IsRunning = true;  
  109.                 _listener.Start();  
  110.                 Thread thread = new Thread(Accept);  
  111.                 thread.Start();  
  112.             }  
  113.         }  
  114.         /// <summary>  
  115.         /// 开始进行监听  
  116.         /// </summary>  
  117.         private void Accept()  
  118.         {  
  119.             TCPClientHandle handle;  
  120.             while (IsRunning)  
  121.             {  
  122.                 TcpClient client = _listener.AcceptTcpClient();  
  123.                 if (_clientCount >= _maxClient)  
  124.                 {  
  125.                     //TODO 触发事件  
  126.                 }  
  127.                 else  
  128.                 {  
  129.                     handle = new TCPClientHandle(client);  
  130.                     _clientCount++;  
  131.                     _clients.Add(handle);  
  132.   
  133.                     //TODO 创建一个处理客户端的线程并启动  
  134.                     //使用线程池来操作  
  135.                     new Thread(new ThreadStart(handle.RecevieData)).Start();  
  136.                 }  
  137.             }  
  138.   
  139.         }  
  140.         /// <summary>  
  141.         /// 停止服务器  
  142.         /// </summary>  
  143.         public void Stop()  
  144.         {  
  145.             if (IsRunning)  
  146.             {  
  147.                 IsRunning = false;  
  148.                 _listener.Stop();  
  149.                 //TODO 关闭对所有客户端的连接  
  150.             }  
  151.         }  
  152.         /// <summary>  
  153.         /// 发送函数  
  154.         /// </summary>  
  155.         public void Send(string msg, TcpClient client)  
  156.         {  
  157.             //TODO  
  158.         }  
  159.  
  160.         #endregion  
  161.  
  162.         #region 事件  
  163.   
  164.         /// <summary>  
  165.         /// 与客户端的连接已建立事件  
  166.         /// </summary>  
  167.         public event EventHandler<TCPEventArgs> ClientConnected;  
  168.         /// <summary>  
  169.         /// 与客户端的连接已断开事件  
  170.         /// </summary>  
  171.         public event EventHandler<TCPEventArgs> ClientDisconnected;  
  172.   
  173.         /// <summary>  
  174.         /// 触发客户端连接事件  
  175.         /// </summary>  
  176.         /// <param name="state"></param>  
  177.         private void RaiseClientConnected(TCPClientHandle handle)  
  178.         {  
  179.             if (ClientConnected != null)  
  180.             {  
  181.                 ClientConnected(thisnew TCPEventArgs(handle));  
  182.             }  
  183.         }  
  184.         /// <summary>  
  185.         /// 触发客户端连接断开事件  
  186.         /// </summary>  
  187.         /// <param name="client"></param>  
  188.         private void RaiseClientDisconnected(Socket client)  
  189.         {  
  190.             if (ClientDisconnected != null)  
  191.             {  
  192.                 ClientDisconnected(thisnew TCPEventArgs("连接断开"));  
  193.             }  
  194.         }  
  195.   
  196.         /// <summary>  
  197.         /// 接收到数据事件  
  198.         /// </summary>  
  199.         public event EventHandler<TCPEventArgs> DataReceived;  
  200.   
  201.         private void RaiseDataReceived(TCPClientHandle handle)  
  202.         {  
  203.             if (DataReceived != null)  
  204.             {  
  205.                 DataReceived(thisnew TCPEventArgs(handle));  
  206.             }  
  207.         }  
  208.   
  209.         /// <summary>  
  210.         /// 数据发送事件  
  211.         /// </summary>  
  212.         public event EventHandler<TCPEventArgs> CompletedSend;  
  213.   
  214.         /// <summary>  
  215.         /// 触发数据发送事件  
  216.         /// </summary>  
  217.         /// <param name="state"></param>  
  218.         private void RaiseCompletedSend(TCPClientHandle handle)  
  219.         {  
  220.             if (CompletedSend != null)  
  221.             {  
  222.                 CompletedSend(thisnew TCPEventArgs(handle));  
  223.             }  
  224.         }  
  225.   
  226.   
  227.         /// <summary>  
  228.         /// 网络错误事件  
  229.         /// </summary>  
  230.         public event EventHandler<TCPEventArgs> NetError;  
  231.         /// <summary>  
  232.         /// 触发网络错误事件  
  233.         /// </summary>  
  234.         /// <param name="state"></param>  
  235.         private void RaiseNetError(TCPClientHandle handle)  
  236.         {  
  237.             if (NetError != null)  
  238.             {  
  239.                 NetError(thisnew TCPEventArgs(handle));  
  240.             }  
  241.         }  
  242.   
  243.         /// <summary>  
  244.         /// 异常事件  
  245.         /// </summary>  
  246.         public event EventHandler<TCPEventArgs> OtherException;  
  247.         /// <summary>  
  248.         /// 触发异常事件  
  249.         /// </summary>  
  250.         /// <param name="state"></param>  
  251.         private void RaiseOtherException(TCPClientHandle handle, string descrip)  
  252.         {  
  253.             if (OtherException != null)  
  254.             {  
  255.                 OtherException(thisnew TCPEventArgs(descrip, handle));  
  256.             }  
  257.         }  
  258.         private void RaiseOtherException(TCPClientHandle handle)  
  259.         {  
  260.             RaiseOtherException(handle, "");  
  261.         }  
  262.  
  263.         #endregion  
  264.  
  265.         #region Close  
  266.   
  267.         /// <summary>  
  268.         /// 关闭一个与客户端之间的会话  
  269.         /// </summary>  
  270.         /// <param name="handle">需要关闭的客户端会话对象</param>  
  271.         public void Close(TCPClientHandle handle)  
  272.         {  
  273.             if (handle != null)  
  274.             {  
  275.                 _clients.Remove(handle);  
  276.                 handle.Dispose();  
  277.                 _clientCount--;  
  278.                 //TODO 触发关闭事件  
  279.   
  280.             }  
  281.         }  
  282.         /// <summary>  
  283.         /// 关闭所有的客户端会话,与所有的客户端连接会断开  
  284.         /// </summary>  
  285.         public void CloseAllClient()  
  286.         {  
  287.             foreach (TCPClientHandle handle in _clients)  
  288.             {  
  289.                 Close(handle);  
  290.             }  
  291.             _clientCount = 0;  
  292.             _clients.Clear();  
  293.         }  
  294.         #endregion  
  295.  
  296.         #region 释放  
  297.         /// <summary>  
  298.         /// Performs application-defined tasks associated with freeing,   
  299.         /// releasing, or resetting unmanaged resources.  
  300.         /// </summary>  
  301.         public void Dispose()  
  302.         {  
  303.             Dispose(true);  
  304.             GC.SuppressFinalize(this);  
  305.         }  
  306.   
  307.         /// <summary>  
  308.         /// Releases unmanaged and - optionally - managed resources  
  309.         /// </summary>  
  310.         /// <param name="disposing"><c>true</c> to release   
  311.         /// both managed and unmanaged resources; <c>false</c>   
  312.         /// to release only unmanaged resources.</param>  
  313.         protected virtual void Dispose(bool disposing)  
  314.         {  
  315.             if (!this.disposed)  
  316.             {  
  317.                 if (disposing)  
  318.                 {  
  319.                     try  
  320.                     {  
  321.                         Stop();  
  322.                         if (_listener != null)  
  323.                         {  
  324.                             _listener = null;  
  325.                         }  
  326.                     }  
  327.                     catch (SocketException)  
  328.                     {  
  329.                         //TODO 异常  
  330.                     }  
  331.                 }  
  332.                 disposed = true;  
  333.             }  
  334.         }  
  335.         #endregion  
  336.     }  
  337. }  
客户端处理封装类

[csharp]  view plain  copy
  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Linq;  
  4. using System.Text;  
  5. using System.Net.Sockets;  
  6. using System.IO;  
  7.   
  8. namespace NetFrame.Net.TCP.Listener.Synchronous  
  9. {  
  10.     /// <summary>  
  11.     /// TcpListener实现同步TCP服务器 的客户端连接处理类  
  12.     /// </summary>  
  13.     public class TCPClientHandle  
  14.     {  
  15.         private TcpClient _tcpclient;  
  16.   
  17.         private BinaryReader rs;  
  18.   
  19.         private BinaryWriter ws;  
  20.   
  21.         /// <summary>  
  22.         /// 标识是否与客户端相连接  
  23.         /// </summary>  
  24.         private bool _is_connect;  
  25.         public bool IsConnect  
  26.         {  
  27.             get { return _is_connect; }  
  28.             set { _is_connect = value; }  
  29.         }  
  30.   
  31.         /// <summary>  
  32.         /// 数据接受缓冲区  
  33.         /// </summary>  
  34.         private byte[] _recvBuffer;  
  35.   
  36.         public TCPClientHandle(TcpClient client)  
  37.         {  
  38.             _tcpclient = client;  
  39.             rs = new BinaryReader(client.GetStream());  
  40.             ws = new BinaryWriter(client.GetStream());  
  41.             // NetworkStream ns = tmpTcpClient.GetStream();  
  42.             // if(ns.CanRead&&ns.CanWrite)  
  43.             _recvBuffer=new byte[client.ReceiveBufferSize];  
  44.         }  
  45.   
  46.         /// <summary>  
  47.         /// 接受数据  
  48.         /// </summary>  
  49.         public void RecevieData()  
  50.         {  
  51.             int len = 0;  
  52.             while (_is_connect)  
  53.             {  
  54.                 try  
  55.                 {  
  56.                     len = rs.Read(_recvBuffer, 0, _recvBuffer.Length);  
  57.                 }  
  58.                 catch (Exception)  
  59.                 {  
  60.                     break;  
  61.                 }  
  62.                 if (len == 0)  
  63.                 {  
  64.                     //the client has disconnected from server  
  65.                     break;  
  66.                 }  
  67.                 //TODO 处理收到的数据  
  68.                   
  69.             }  
  70.         }  
  71.         /// <summary>  
  72.         /// 向客户端发送数据  
  73.         /// </summary>  
  74.         /// <param name="msg"></param>  
  75.         public void SendData(string msg)  
  76.         {  
  77.             byte[] data = Encoding.Default.GetBytes(msg);  
  78.             try  
  79.             {  
  80.                 ws.Write(data, 0, data.Length);  
  81.                 ws.Flush();  
  82.             }  
  83.             catch (Exception)  
  84.             {  
  85.                 //TODO 处理异常  
  86.             }  
  87.         }  
  88.  
  89.         #region 事件  
  90.   
  91.   
  92.         //TODO 消息发送事件  
  93.         //TODO 数据收到事件  
  94.         //TODO 异常处理事件  
  95.  
  96.         #endregion  
  97.  
  98.         #region 释放  
  99.         /// <summary>  
  100.         /// Performs application-defined tasks associated with freeing,   
  101.         /// releasing, or resetting unmanaged resources.  
  102.         /// </summary>  
  103.         public void Dispose()  
  104.         {  
  105.             _is_connect = false;  
  106.             if (_tcpclient != null)  
  107.             {  
  108.                 _tcpclient.Close();  
  109.                 _tcpclient = null;  
  110.             }  
  111.             GC.SuppressFinalize(this);  
  112.         }  
  113.  
  114.         #endregion  
  115.     }  
  116. }  

Tcp服务器事件参数类

[csharp]  view plain  copy
  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Linq;  
  4. using System.Text;  
  5.   
  6. namespace NetFrame.Net.TCP.Listener.Synchronous  
  7. {  
  8.     /// <summary>  
  9.     /// 同步TcpListener TCP服务器事件类  
  10.     /// </summary>  
  11.     public class TCPEventArgs : EventArgs  
  12.     {  
  13.         /// <summary>  
  14.         /// 提示信息  
  15.         /// </summary>  
  16.         public string _msg;  
  17.   
  18.         /// <summary>  
  19.         /// 客户端状态封装类  
  20.         /// </summary>  
  21.         public TCPClientHandle _handle;  
  22.   
  23.         /// <summary>  
  24.         /// 是否已经处理过了  
  25.         /// </summary>  
  26.         public bool IsHandled { getset; }  
  27.   
  28.         public TCPEventArgs(string msg)  
  29.         {  
  30.             this._msg = msg;  
  31.             IsHandled = false;  
  32.         }  
  33.         public TCPEventArgs(TCPClientHandle handle)  
  34.         {  
  35.             this._handle = handle;  
  36.             IsHandled = false;  
  37.         }  
  38.         public TCPEventArgs(string msg, TCPClientHandle handle)  
  39.         {  
  40.             this._msg = msg;  
  41.             this._handle = handle;  
  42.             IsHandled = false;  
  43.         }  
  44.     }  
  45. }  

这篇关于C#网络编程系列文章(四)之TcpListener实现同步TCP服务器的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/319925

相关文章

Spring Security 从入门到进阶系列教程

Spring Security 入门系列 《保护 Web 应用的安全》 《Spring-Security-入门(一):登录与退出》 《Spring-Security-入门(二):基于数据库验证》 《Spring-Security-入门(三):密码加密》 《Spring-Security-入门(四):自定义-Filter》 《Spring-Security-入门(五):在 Sprin

基于MySQL Binlog的Elasticsearch数据同步实践

一、为什么要做 随着马蜂窝的逐渐发展,我们的业务数据越来越多,单纯使用 MySQL 已经不能满足我们的数据查询需求,例如对于商品、订单等数据的多维度检索。 使用 Elasticsearch 存储业务数据可以很好的解决我们业务中的搜索需求。而数据进行异构存储后,随之而来的就是数据同步的问题。 二、现有方法及问题 对于数据同步,我们目前的解决方案是建立数据中间表。把需要检索的业务数据,统一放到一张M

服务器集群同步时间手记

1.时间服务器配置(必须root用户) (1)检查ntp是否安装 [root@node1 桌面]# rpm -qa|grep ntpntp-4.2.6p5-10.el6.centos.x86_64fontpackages-filesystem-1.41-1.1.el6.noarchntpdate-4.2.6p5-10.el6.centos.x86_64 (2)修改ntp配置文件 [r

hdu1043(八数码问题,广搜 + hash(实现状态压缩) )

利用康拓展开将一个排列映射成一个自然数,然后就变成了普通的广搜题。 #include<iostream>#include<algorithm>#include<string>#include<stack>#include<queue>#include<map>#include<stdio.h>#include<stdlib.h>#include<ctype.h>#inclu

2. c#从不同cs的文件调用函数

1.文件目录如下: 2. Program.cs文件的主函数如下 using System;using System.Collections.Generic;using System.Linq;using System.Threading.Tasks;using System.Windows.Forms;namespace datasAnalysis{internal static

【C++】_list常用方法解析及模拟实现

相信自己的力量,只要对自己始终保持信心,尽自己最大努力去完成任何事,就算事情最终结果是失败了,努力了也不留遗憾。💓💓💓 目录   ✨说在前面 🍋知识点一:什么是list? •🌰1.list的定义 •🌰2.list的基本特性 •🌰3.常用接口介绍 🍋知识点二:list常用接口 •🌰1.默认成员函数 🔥构造函数(⭐) 🔥析构函数 •🌰2.list对象

【Prometheus】PromQL向量匹配实现不同标签的向量数据进行运算

✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。 🏆《博客》:Python全栈,前后端开发,小程序开发,人工智能,js逆向,App逆向,网络系统安全,数据分析,Django,fastapi

让树莓派智能语音助手实现定时提醒功能

最初的时候是想直接在rasa 的chatbot上实现,因为rasa本身是带有remindschedule模块的。不过经过一番折腾后,忽然发现,chatbot上实现的定时,语音助手不一定会有响应。因为,我目前语音助手的代码设置了长时间无应答会结束对话,这样一来,chatbot定时提醒的触发就不会被语音助手获悉。那怎么让语音助手也具有定时提醒功能呢? 我最后选择的方法是用threading.Time

Linux 网络编程 --- 应用层

一、自定义协议和序列化反序列化 代码: 序列化反序列化实现网络版本计算器 二、HTTP协议 1、谈两个简单的预备知识 https://www.baidu.com/ --- 域名 --- 域名解析 --- IP地址 http的端口号为80端口,https的端口号为443 url为统一资源定位符。CSDNhttps://mp.csdn.net/mp_blog/creation/editor

【Python编程】Linux创建虚拟环境并配置与notebook相连接

1.创建 使用 venv 创建虚拟环境。例如,在当前目录下创建一个名为 myenv 的虚拟环境: python3 -m venv myenv 2.激活 激活虚拟环境使其成为当前终端会话的活动环境。运行: source myenv/bin/activate 3.与notebook连接 在虚拟环境中,使用 pip 安装 Jupyter 和 ipykernel: pip instal