c# 网路通讯TCP 服务端与客户端 简单编写,并能够实现快速断线重连的封装类(适合新手小白参考学习)

本文是本人在做项目期间,简单根据自己所需需求封装的一个TCP通讯的函数类,包含了客户端、服务端,描写的较为简单,很适合新手小白参考学习

服务端:

实现较为简单 主要用于监听客户端等,并将每次连接的客户端套接字,放入了键值对当中,可以通过对用IP地址当键查出套接字,然后发送数据,实现1对1通讯(键值对为TcpKeyValue ),程序中注释部分为心跳包及其他用途。

using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;

namespace DataCollectionSystem.MenuBar
{
    class TcpCommunication
    {
        private TcpListener listener; // 监听器
        private TcpClient client; // 客户端连接
        public NetworkStream stream; // 网络流对象

        private int heartbeatInterval = 5000; // 心跳检测时间间隔
        private byte[] heartBeatMsg = Encoding.ASCII.GetBytes("I am alive!"); // 心跳消息内容
        private DateTime lastHeartBeatTime; // 上次接收到心跳消息的时间

        //线程锁(注意!!!!!)
        private static object myLock = new object();

        //存放所有的网络流对象
        public Dictionary<string, NetworkStream> TcpKeyValue = new Dictionary<string, NetworkStream>();
        //存放所有的客户端连接Client
        List<TcpClient> ClientList = new List<TcpClient>();


        // 事件委托和事件定义
        public delegate void MessageReceivedEventHandler(string message);
        public event MessageReceivedEventHandler OnMessageReceived;

        public delegate void ClientDisconnectedEventHandler(string IP, int prot);
        public event ClientDisconnectedEventHandler OnClientDisconnected;

        // 启动监听器并等待客户端连接
        public void Start(string localIP, int port)
        {
            listener = new TcpListener(IPAddress.Parse(localIP), port);
            listener.Start();

            Console.WriteLine("等待客户端连接...");

            while (true) // 循环等待新的客户端连接
            {
                client = listener.AcceptTcpClient(); // 接受客户端连接请求

                ClientList.Add(client);

                stream = client.GetStream(); // 获取网络流对象

                IPEndPoint remoteIpEndpoint = (IPEndPoint)client.Client.RemoteEndPoint;
                string remoteIpAddress = remoteIpEndpoint.Address.ToString();
                int remotePort = remoteIpEndpoint.Port;

                Console.WriteLine(remoteIpAddress + " " + remotePort);
                lock (myLock)
                {
                    if (!TcpKeyValue.ContainsKey(remoteIpAddress))
                    {
                        TcpKeyValue.Add(remoteIpAddress, stream);
                    }
                    else
                    {
                        TcpKeyValue[remoteIpAddress] = stream;
                    }
                }

                Console.WriteLine("客户端已连接");

                // 初始化心跳检测时间
                lastHeartBeatTime = DateTime.Now;

                // 创建一个新线程处理客户端请求
                Thread t = new Thread(new ThreadStart(HandleClientComm));
                t.Start();

                 启动心跳包线程
                //Thread heartbeatThread = new Thread(SendHeartbeat);
                //heartbeatThread.IsBackground = true;
                //heartbeatThread.Start();

            }
        }

        // 处理客户端消息的方法
        private void HandleClientComm()
        {
            while (true) // 循环接收客户端消息
            {
                // 接收客户端消息
                byte[] buffer = new byte[1024];
                int bytesRead = stream.Read(buffer, 0, buffer.Length);

                if (bytesRead == 0) // 客户端已断开连接
                {
                    IPEndPoint remoteIpEndpoint = (IPEndPoint)client.Client.RemoteEndPoint;
                    string remoteIpAddress = remoteIpEndpoint.Address.ToString();
                    int remotePort = remoteIpEndpoint.Port;

                    OnClientDisconnected?.Invoke(remoteIpAddress, remotePort); // 触发客户端断开连接事件
                    ClientList.Remove(client);
                    TcpKeyValue.Remove(remoteIpAddress);
                    break;
                }

                string data = Encoding.ASCII.GetString(buffer, 0, bytesRead);

                //接收到消息
                OnMessageReceived?.Invoke(data); // 触发收到消息事件

                // 发送响应消息给客户端
                //byte[] response = System.Text.Encoding.ASCII.GetBytes("我已经收到你的消息了!");

                //stream.Write(response, 0, response.Length);
            }
            client.Dispose();
            client.Close();
        }

        //发送心跳
        private void SendHeartbeat()
        {
            while (true)
            {
                byte[] heartbeat = Encoding.UTF8.GetBytes("heartbeat");

                foreach (KeyValuePair<string, NetworkStream> pair in TcpKeyValue)
                {
                    Console.WriteLine("{0}: {1}", pair.Key, pair.Value);
                    try
                    {
                        // 在这里调用 Write 方法
                        pair.Value.Write(heartBeatMsg, 0, heartBeatMsg.Length);
                    }
                    catch (SocketException ex)
                    {
                        IPEndPoint remoteIpEndpoint = (IPEndPoint)client.Client.RemoteEndPoint;
                        string remoteIpAddress = remoteIpEndpoint.Address.ToString();
                        int remotePort = remoteIpEndpoint.Port;

                        OnClientDisconnected?.Invoke(remoteIpAddress, remotePort);
                         获取引起异常的 TcpClient 对象
                        //TcpClient client = (TcpClient)ex.SocketErrorCode;

                         获取连接断开的客户端的 IP 地址
                        //string clientIP = ((IPEndPoint)client.RemoteEndPoint).Address.ToString();

                         输出客户端 IP 地址
                        //Console.WriteLine("客户端 {0} 连接已断开", clientIP);
                    }

                }

                Thread.Sleep(heartbeatInterval); // 每隔 5 秒发送一次心跳包
            }
        }

        //结束所有的客户端
        public void ClientDispose()
        {
            foreach (KeyValuePair<string, NetworkStream> pair in TcpKeyValue)
            {
                pair.Value.Close();
            }
            foreach (TcpClient client in ClientList)
            {
                client.Close();
            }
        }
    }
}

服务端使用说明:

服务端代码示例:

客户端:

此为客户端代码,增加了断线重连及提醒委托。

using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using Tools;


namespace DataCollectionSystem_attach.Subpage
{
    public class TcpClientWrapper
    {
        private readonly string _serverAddress;   //IP地址
        private readonly int _port;               //端口号
        private TcpClient _client;                //套接字
        private NetworkStream _stream;            //网络字节流
        private Thread _receiveThread;            //线程
        public bool _isConnected = false;                //判断网络连接
        public bool _isRunning;                  //判断线程是否在运行
        string Heartbeat_Data = "OK";      //发送心跳的内容

        public delegate void MessageReceivedHandler(string message); 
        public event MessageReceivedHandler MessageReceived;         //接收信息委托

        public delegate void CommunicationStatus_NO();
        public event CommunicationStatus_NO CStatus_NO;         //通讯状态

        public delegate void CommunicationStatus_OK();
        public event CommunicationStatus_OK CStatus_OK;         //接收信息委托



        public TcpClientWrapper(string serverAddress, int port)
        {
            _serverAddress = serverAddress;
            _port = port;
        }

        //连接函数
        public void Connect()
        {
            _client = new TcpClient();
            try
            {
                _client.Connect(_serverAddress, _port);

                _stream = _client.GetStream();
                _isConnected = true;
                _isRunning = true;

                //启动心跳检测线程
                var heartbeatThread = new Thread(SendHeartbeat);
                heartbeatThread.IsBackground = true;
                heartbeatThread.Start();
            }
            catch (Exception)
            {
                Thread.Sleep(1000);
                Reconnect1();
                //Console.WriteLine("aaa");
            }


            启动接收线程
            //_receiveThread = new Thread(ReceiveMessage);
            //_receiveThread.IsBackground = true;
            //_receiveThread.Start();

        }

        //断开连接释放资源
        public void Disconnect()
        {
            _isConnected = false;
            _isRunning = false;
            try
            {
                if (_client != null)
                {
                    _client.Close();
                }
            }
            catch (Exception)
            {
            }

        }

        //发送消息
        public void SendMessage(byte[] message)
        {
            if (!_isConnected) return;
            try
            {
                _stream.Write(message, 0, message.Length);
            }
            catch (Exception e)
            {
                _isConnected = false;
                //Console.WriteLine($"发送消息失败:{e.Message}");
                LogHelper.AddErrorLog($"发送消息失败: {e.Message}.");
            }
        }


        //读取消息
        private void ReceiveMessage()
        {
            while (_isRunning)
            {
                try
                {
                    if (_client.Available > 0)
                    {
                        var buffer = new byte[_client.Available];
                        _stream.Read(buffer, 0, buffer.Length);
                        //Console.WriteLine($"接收到消息:{Encoding.UTF8.GetString(buffer)}");
                        MessageReceived?.Invoke(Encoding.UTF8.GetString(buffer)); //委托消息
                    }
                }
                catch (Exception e)
                {
                    Console.WriteLine($"接收消息失败:{e.Message}");
                    Reconnect();
                }

                Thread.Sleep(50);
            }
        }

        //发送心跳消息
        private void SendHeartbeat()
        {
            while (_isRunning)
            {
                Thread.Sleep(50);
                try
                {
                    //SendMessage(Encoding.UTF8.GetBytes("Heartbeat"));
                    _stream.Write(Encoding.UTF8.GetBytes(Heartbeat_Data), 0, Heartbeat_Data.Length);
                    //CStatus_OK?.Invoke();
                }
                catch (Exception e)
                {
                    //Console.WriteLine($"发送心跳失败:{e.Message}");
                    CStatus_NO?.Invoke();
                    Reconnect();
                    break;
                }

                Thread.Sleep(5950); //10秒钟发送一次心跳包
            }
        }

        //重连函数
        public void Reconnect()
        {
            Disconnect();
            while (!_isConnected)
            {
                try
                {
                    Connect();
                }
                catch (Exception e)
                {
                    //Console.WriteLine($"重连失败:{e.Message}");
                }

                Thread.Sleep(3000); //3秒钟尝试重新连接一次
            }
        }

        //重连函数
        public void Reconnect1()
        {
            Disconnect();
            try
            {
                Connect();
            }
            catch (Exception e)
            {
                //Console.WriteLine($"重连失败:{e.Message}");
            }
        }

    }
}

客户端使用说明:

本文中注释部分是预留部分,其中服务端心跳包部分被注释。

本代码只用于互相讨论学习适合新手研究编写网络通讯方面代码,不对之处请大家指正修改。

  • 22
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
C是计算机科学中的一种编程语言。C语言是一种高级的编程语言,由贝尔实验室的Dennis Ritchie在20世纪70年代开发出来。它是一种通用的、过程化的编程语言,广泛应用于操作系统、嵌入式系统和游戏开发等领域。 C语言与其他编程语言相比,具有高效、灵活和强大的特性。它提供了许多底层的编程工具,例如指针和位操作,使得程序员能够直接访问内存和硬件资源。这使得C语言在开发底层系统和设备驱动程序时非常有用。 C语言的语法简洁明了,易于学习和理解。它采用了结构化编程的思想,可以将程序分成多个模块,提高了代码的可读性和可维护性。C语言还具备跨平台的特性,能够在不同的操作系统上运行,为软件开发提供了便利。 C语言的应用非常广泛。它在操作系统中扮演着重要角色,例如Unix、Linux和Windows等。此外,许多嵌入式系统和微控制器都是用C语言编写的。C语言也是编写游戏和图形应用程序的首选语言,许多著名的游戏引擎如Unity和Unreal Engine都是用C语言编写的。 虽然C语言强大且灵活,但也存在一些缺点。由于它较为底层,编写复杂的程序时可能需要花费更多的时间和精力。另外,C语言对于错误处理和内存管理等方面需要程序员自行负责,因此在编写大型应用程序时需要更谨慎。 总之,C语言是一种广泛应用于计算机科学领域的编程语言。它具有高效、灵活和强大的特性,适用于开发各种型的软件和系统。无论是初学者还是专业程序员,掌握C语言都是非常有价值的。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值