C# Tcplistener,Tcp服务端简易封装

2023-12-19

前言

我最近有个需求要写Tcp服务端,我发现Tcp服务端的回调函数比较麻烦,简化Tcp的服务,我打算自己封装一个简单的Tcp服务端。

相关文章

C# TCP应用编程三 异步TCP应用编程

C# Tcpclient Tcplistener 服务器接收多个客户端消息通讯

关于C#Socket断开重连问题

前言

我最近有个Tcp服务端的项目,发现TcpListener 服务端官方写起来很麻烦。而且没有回调函数。现在做个简单的服务端封装

设计

TcpServerService
ShowMsg:打印消息
AddClient_CallBack:新增Tcp客户端回调函数
SendMsg/ReceiveMsg:Tcp客户端发送接受回调
Clients:Tcp客户端集合,连接增加,断开去除
其它函数

代码

 public class TcpServeService
 {
     public string Ip { get; set; }

     public int Port { get; set; }

     public TcpListener Server { get; set; }

     public List<TcpClient> Clients { get; set; }

     /// <summary>
     /// 客户端添加回调函数,如果要重写通讯逻辑需要覆盖
     /// </summary>
     public Action<TcpClient> AddClient_CallBack { get; set; }


     public Action<string> ShowMsg { get; set; }

     /// <summary>
     /// 默认自动回复Tcp服务端
     /// </summary>
     /// <param name="ip"></param>
     /// <param name="port"></param>
     public TcpServeService(string ip, int port)
     {
         Clients = new List<TcpClient>();
         ShowMsg = (msg) => Console.WriteLine(msg);
         AddClient_CallBack = (client) => AutoSendBack(client);
         this.Ip = ip;
         this.Port = port;
         Server = new TcpListener(IPAddress.Parse(ip), port);
     }


     /// <summary>
     /// Tcp添加Client回调
     /// </summary>
     /// <param name="ar"></param>
     private void DoAcceptTcpclient(IAsyncResult ar)
     {
         // Get the listener that handles the client request.
         TcpListener listener = (TcpListener)ar.AsyncState;

         // End the operation and display the received data on 
         // the console.
         TcpClient client = listener.EndAcceptTcpClient(ar);

         Clients.Add(client);

         // Process the connection here. (Add the client to a
         // server table, read data, etc.)
         ShowMsg($"Tcp客户端连接成功!,当前连接数{Clients.Count},Id[{client.Client.RemoteEndPoint.ToString()}]");
         AddClient_CallBack(client);
         //开启线程用来不断接收来自客户端的数据
         Server.BeginAcceptTcpClient(new AsyncCallback(DoAcceptTcpclient), Server);
     }

     /// <summary>
     /// 移除Tcp客户端
     /// </summary>
     /// <param name="client"></param>
     public void RemoveClient(TcpClient client)
     {
         NetworkStream stream = client.GetStream();
         ShowMsg($"Tcp客户端连接断开!,当前连接数{Clients.Count},Id[{client.Client.RemoteEndPoint.ToString()}]");
         stream.Close();
         client.Close();
         Clients.Remove(client);
     }

     /// <summary>
     /// 启动Tcp服务
     /// </summary>
     public void Start()
     {
         Server.Start();
         Server.BeginAcceptTcpClient(new AsyncCallback(DoAcceptTcpclient), Server);
         ShowMsg($"Tcp服务端启动成功!IP[{Ip}],Port[{Port}]");
     }

     /// <summary>
     /// 同步阻塞读取数据
     /// </summary>
     /// <param name="client"></param>
     /// <returns></returns>
     public static (string str, byte[] bytes) ReadMsg(TcpClient client)
     {
         NetworkStream networkStream = client.GetStream();
         var resBytes = new byte[client.ReceiveBufferSize];
         networkStream.Read(resBytes, 0, resBytes.Length);
         var resStr = UnicodeEncoding.ASCII.GetString(resBytes);
         if (!IsConnect(client))
         {
             throw new Exception($"{client.Client.RemoteEndPoint?.ToString()}Tcp连接已断开");
         }
         return (resStr, resBytes);
     }
     /// <summary>
     /// 发送Ascll数据
     /// </summary>
     /// <param name="tcpClient"></param>
     /// <param name="msg"></param>
     public static void SendMsg(TcpClient tcpClient, string msg)
     {
         byte[] arrSendMsg = Encoding.UTF8.GetBytes(msg);
         SendMsg(tcpClient, arrSendMsg);
     }

     /// <summary>
     /// Tcp客户端连接是否断开
     /// </summary>
     /// <param name="tcpClient"></param>
     /// <returns></returns>
     public static bool IsConnect(TcpClient tcpClient)
     {
         if (tcpClient.Client.Poll(1, SelectMode.SelectRead) && tcpClient.Available == 0)
         {
             return false;
         }
         else { return true; }
     }

     /// <summary>
     /// 发送Bytes[]数据
     /// </summary>
     /// <param name="tcpClient"></param>
     /// <param name="msg"></param>
     public static void SendMsg(TcpClient tcpClient, byte[] msg)
     {
         NetworkStream networkStream = tcpClient.GetStream();
         networkStream.Write(msg, 0, msg.Length);
     }


     /// <summary>
     /// 默认自动回复,异常捕捉
     /// </summary>
     /// <param name="tcpClient"></param>
     /// <param name="timeOut">超时时间</param>
     /// <returns></returns>
     public async Task AutoSendBack(TcpClient tcpClient, int timeOut = 10 * 1000)
     {
         //超时时间
         tcpClient.ReceiveTimeout = timeOut;
         tcpClient.SendTimeout = timeOut;
         while (true)
         {
             try
             {
                 if (!Clients.Contains(tcpClient))
                 {
                     throw new Exception("Tcp客户端已被移除!");
                 }
                 var receive = ReadMsg(tcpClient);
                 ShowMsg($"TcpClient[{tcpClient.Client.RemoteEndPoint?.ToString()}]:收到数据{receive.str}");
                 SendMsg(tcpClient, receive.str);
             }
             catch (Exception ex)
             {
                 RemoveClient(tcpClient);
                 ShowMsg("发送失败");
                 ShowMsg(ex.Message);
             }
         }
     }

简单使用

//对tcpServeService进行了默认配置,默认自动回复,自动维护Client集合
TcpServeService tcpServeService = new TcpServeService("192.168.100.21", 10003);

//如果想要自定义回复,需要覆盖AddClient_CallBack函数,使用异步任务处理连接
//tcpServeService.AddClient_CallBack = ((client) => {
//    Task.Run(() =>
//    {
//        //你的客户端连接异步任务
//    });
//});

//如果想要打印在Winfrom/WPF的界面,覆盖此回调
//tcpServeService.ShowMsg = (msg) =>
//{
//    //你的消息打印函数
//};
//tcpServeService.Start();
tcpServeService.Start();

运行结果

在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C# Tcplistener,Tcp服务端简易封装 的相关文章

随机推荐

  • 分享10个高级sql写法

    分享10个高级sql写法 原创 waynaqua waynblog 2023 03 12 23 36 发表于湖北 本文主要介绍博主在以往开发过程中 对于不同业务所对应的 sql 写法进行归纳总结而来 进而分享给大家 本文所讲述 sql 语法
  • 视频剪辑用什么软件?这几款软件或许能帮上你

    现在有很多社交平台都推出了分享视频的功能 大家除了文字和照片外 又多了项分享日常的方式 随着短视频软件的风靡 相信小伙伴在观看视频的同时 也有想过自己动手剪一个视频吧 那如何才能自己制作出一个视频呢 其实网上有很多视频剪辑教程 从讲解视频剪
  • 计算机毕业设计选题推荐,springboot宠物领养系统 46903(赠送源码数据库 )上万套实战教程手把手教学JAVA、PHP,node.js,C++、python、数据可视化等

    本科生毕业设计 论文 题 目 宠物领养系统 的设计与实现 学 院 XXXXX 专业班级 XXXXX 学生姓名 XXXX 指导教师
  • AD7021C 集成触摸感应加单路调光芯片 可实现无极调光和单按键开关功能

    AD7021C触摸感应IC 是为实现人体触摸界面而设计的集成电路 可替代机械式轻触按键 实现防水防尘 密封隔离 坚固美观的操作界面 使用该芯片可以实现 LED 灯光亮度调节 方案所需的外围电路简单 操作方便 确定好灵敏度选择电容 IC 就可
  • SQL常用字符串处理函数及案例

    SQL常用字符串处理函数及案例 MySQL字符串处理函数可以帮助我们对数据库中的字符串数据进行各种操作 包括拼接 截取和替换等 接下来本文将介绍一些常用的MySQL字符串处理函数 并通过案例实践来演示它们的用法 让我们开始吧 01 字符串拼
  • 对Java Stream 进行二次封装

    对Java Stream 进行二次封装 一共整理了10个工具方法 可以满足 Collection List Set Map 之间各种类型转化 例如 将 Collection
  • idea springboot项目运行出错(运行模式问题)

    问题 解决办法 第一步 第二步 DoperatingMode dev
  • Error: T doesn‘t have .length

    Error T doesn t have length 在 TypeScript 中 当我们使用泛型
  • String.class.equals(value.getClass())

    这段代码是在判断变量 value 是否是 String 类型的示例代码 它使用了 Java 中的反射机制 解析该代码的含义如下 String class 表示获取 String 类的 Class 对象 它是描述 String 类的类对象 v
  • R语言采集获取58商铺出租转让信息

    前两篇文章给我一个朋友分析出店铺商品以及地址房源信息 后来去看了下店铺房租有点贵 还是毛坯房 要自己装修 本着节约成本的原则 熬了个通宵 给他采集了一些转租商铺数据 因为数据比较多 过于先进不方便展示 我就将我爬虫程序的模版展示给大家观看
  • 通俗易懂的讲解Java 中的反射机制

    Java 中的反射机制是指在程序运行时动态地获取类的信息 以及在运行时动态操作类和对象的能力 通过反射机制 我们可以在编译时不知道具体类的情况下 获取类的属性 方法 构造函数等信息 并且可以在运行时调用这些属性 方法或创建对象 反射机制提供
  • 说说一次 Dubbo 服务请求流程?

    Dubbo 是一个高性能 轻量级的开源 Java RPC 框架 用于构建服务化应用程序 下面是一个简单的 Dubbo 服务请求流程 客户端发起请求 客户端通过 Dubbo 提供的 RPC 客户端库发送请求到 Dubbo 服务提供者 请求包含
  • 基于SpringBoot+Vue的中山社区医疗综合服务平台设计实现(源码+lw+部署文档+讲解等)

    文章目录 前言 详细视频演示 具体实现截图 技术栈 后端框架SpringBoot 前端框架Vue 持久层框架MyBaitsPlus 系统测试 系统测试目的
  • 智慧排水检测系统,提升城市生命线管理效率

    随着城市化的快速发展 排水系统作为城市生命线的重要组成部分 其管理和维护对于城市的正常运行至关重要 传统的排水系统监测方法往往依赖人工巡查和定期的设备检查 存在效率低下 易出错等问题 为了解决这些问题 智慧排水监测系统应运而生 本文将详细介
  • Vue 条件渲染 v-if

    v if 指令 用于控制元素的显示或隐藏 执行条件 当条件为 false 时 会将元素从 DOM 中删除 应用场景 适用于显示隐藏切换频率较低的场景 语法格式 div 内容 div 基础用法
  • ISO认证的意义以及费用

    ISO认证是国际标准化组织制定的一套标准体系 它对于企业来说具有重要的意义 ISO认证可以帮助企业提高管理水平 提升产品品质 增强市场竞争力 同时也是企业拓展市场 开拓客户的重要手段 一 ISO认证的意义 ISO认证具有以下几个方面的意义
  • ExperimentalWarning: The http2 module is an experimental API.

    错误提示 Node js ExperimentalWarning The fs promises API is experimental 原因是node的版本不是最新的 而在项目引入的模块是最新的 node js的版本低于模块的版本 解决方
  • 一键证件照换底色软件哪个好?这款让你的证件照独具特色!

    在我们生活中 有很多时候需要用到证件照 无论是报名考试还是申请签证 都需要提供一张规格标准的证件照片 然而 有时候我们拍摄的照片可能存在一些问题 比如背景色不符合要求 这时候 如果有一款一键证件照换底色软件 就能够轻松解决这个问题了 首先
  • 基于单片机设计的电子指南针(LSM303DLH模块(三轴磁场 + 三轴加速度)

    一 前言 本项目是基于单片机设计的电子指南针 主要利用STC89C52作为主控芯片和LSM303DLH模块作为指南针模块 通过LCD1602液晶显示屏来展示检测到的指南针信息 在日常生活中 指南针是一种非常实用的工具 可以帮助我们确定方向
  • C# Tcplistener,Tcp服务端简易封装

    文章目录 前言 相关文章 前言 设计 代码 简单使用 运行结果 前言 我最近有个需求要写Tcp服务端 我发现Tcp服务端的回调函数比较麻烦 简化Tcp的服务 我打算自己封装一个简单的Tcp服务端 相关文章 C TCP应用编程三 异步TCP应