涛声依旧在 发表于 2025-1-2 00:39:46

C#实现TCP客户端和服务器

本文将介绍怎样利用C#实现TCP客户端和服务器的基本功能,客户端与服务器可以相互发送消息。
效果展示

https://i-blog.csdnimg.cn/direct/440b76f355fb44d8ad318b993c134365.png
服务器端实现

起首,我们实现TCP服务器。以下是服务器端所需的类和代码:
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;

namespace TCPIP_Test {
    public class TcpIp_Server {
      Socket serverSocket; // 服务器端Socket,用于服务器与客户端的通信
      Socket clientSocket; // 客户端Socket,用于与客户端建立连接
      TcpListener tcpListener; // 负责监听客户端的连接请求
      Thread tcpListenerThread; // 监听连接请求的线程
      Dictionary<string, Socket> dicClientSockets = new Dictionary<string, Socket>(); // 存储客户端Socket的集合,以客户端的IP/端口作为键
      Dictionary<string, Thread> dicReceiveMsg = new Dictionary<string, Thread>(); // 存储每个客户端接收消息的线程集合

      string _IP; // 服务器的IP地址
      int _Port; // 服务器的端口
      IPAddress _ipAddress; // 服务器的IPAddress对象
      EndPoint _endPoint; // 服务器的端点,包括IP地址和端口
      bool linked = false; // 标识服务器是否已开始监听客户端连接
      bool unlinked = false; // 标识服务器是否已关闭连接

      // 构造函数,初始化服务器的IP和端口
      public TcpIp_Server(string ip, int port) {
            serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); // 初始化Socket对象,使用TCP协议
            _IP = ip;
            _Port = port;
            _ipAddress = IPAddress.Parse(ip); // 将IP地址字符串转换为IPAddress对象
            _endPoint = new IPEndPoint(_ipAddress, port); // 构造服务器端点
      }

      // 判断服务器是否已绑定到指定的端口
      private bool _IsBound;
      public bool IsBound {
            get { return _IsBound = serverSocket.IsBound; }
      }

      // 判断服务器Socket是否已连接
      private bool _Connected;
      public bool Connected {
            get { return _Connected = serverSocket.Connected; }
      }

      // 绑定服务器并开始监听客户端连接
      public bool Bind(ref string msg) {
            try {
                if (!linked) {
                  tcpListener = new TcpListener(_ipAddress, _Port); // 创建TcpListener对象,绑定IP和端口
                  tcpListener.Start(); // 启动监听
                  linked = true; // 标记已开始监听
                  ThreadStart threadStart = new ThreadStart(ListenConnectRequest); // 创建一个委托,执行监听连接请求的方法
                  tcpListenerThread = new Thread(threadStart); // 创建一个新线程来监听客户端请求
                  tcpListenerThread.IsBackground = true; // 设置为后台线程
                  tcpListenerThread.Start(); // 启动监听线程
                  msg = $" 服务器{tcpListener.LocalEndpoint.ToString()}监听成功!"; // 返回监听成功的消息
                  return true;
                }
                else {
                  msg = $" 已监听"; // 如果已经开始监听,则返回已监听消息
                  return true;
                }
            }
            catch (Exception ex) {
                msg = $" 连接失败!信息={ex}"; // 如果发生异常,返回错误信息
                return false;
            }
      }

      // 断开与指定客户端的连接
      public bool DisConnectClient(string client, ref string msg) {
            try {
                if (dicClientSockets.ContainsKey(client)) {
                  dicClientSockets.Close(); // 关闭与客户端的连接
                  msg = $" 断开客户端{client}连接"; // 返回断开成功的消息
                  return true;
                }
                else {
                  msg = $" 客户端{client}已断开"; // 如果客户端已断开,返回已断开消息
                  return true;
                }
            }
            catch (Exception ex) {
                msg = $" 断开失败!信息={ex}"; // 如果发生异常,返回错误信息
                return false;
            }
      }

      // 关闭服务器监听并断开所有客户端连接
      public bool ShutDown(string[] clientList, ref string msg) {
            try {
                if (linked) {
                  linked = false; // 标记服务器停止监听
                  tcpListener.Stop(); // 停止TcpListener监听
                  for (int i = 0; i < clientList.Length; i++) {
                        dicClientSockets].Close(); // 关闭每个客户端的连接
                  }
                  msg = $" 服务器监听断开"; // 返回关闭监听的消息
                  return true;
                }
                else {
                  unlinked = true; // 标记已断开
                  msg = $" 已断开"; // 返回已断开消息
                  return true;
                }
            }
            catch (Exception ex) {
                tcpListener.Stop(); // 停止TcpListener
                unlinked = true; // 标记已断开
                msg = $" 已断开!!!"; // 返回关闭连接的消息
                return false;
            }
      }

      // 向指定客户端发送数据
      public bool SendToClient(string client, string cmd, ref string msg) {
            try {
                if (!string.IsNullOrEmpty(cmd)) {
                  dicClientSockets.Send(Encoding.UTF8.GetBytes(cmd)); // 将命令数据发送给客户端
                  msg = $" 发送{client}信息={cmd}"; // 返回发送成功的消息
                  return true;
                }
                else
                  return false; // 如果命令为空,返回发送失败
            }
            catch (Exception ex) {
                msg = $" 发送信息失败!信息={ex}"; // 如果发送失败,返回错误信息
                return false;
            }
      }

      // 监听客户端的连接请求
      private void ListenConnectRequest() {
            while (linked) {
                try {
                  Socket clientSocket = tcpListener.AcceptSocket(); // 等待并接受客户端连接
                  ParameterizedThreadStart parameterizedThreadStart = new ParameterizedThreadStart(ReceiveData); // 创建接收数据的线程委托
                  Thread receiveMsgThread = new Thread(parameterizedThreadStart); // 创建一个线程来接收客户端数据
                  receiveMsgThread.IsBackground = true; // 设置为后台线程
                  receiveMsgThread.Start(clientSocket); // 启动线程并传入客户端Socket
                  dicClientSockets.Add(clientSocket.RemoteEndPoint.ToString(), clientSocket); // 将客户端Socket加入字典
                  dicReceiveMsg.Add(clientSocket.RemoteEndPoint.ToString(), receiveMsgThread); // 将接收消息线程加入字典
                  Form_Server._AddListEvent(clientSocket.RemoteEndPoint.ToString()); // 更新UI列表,显示已连接的客户端
                }
                catch (Exception ex) {
                  Form_Server._ShowServerLogEvent($" 监听失败!信息={ex}"); // 监听失败时显示错误日志
                }
            }
      }

      // 接收客户端发送的数据
      public void ReceiveData(Object obj) {
            Socket clientSocket = (Socket)obj; // 将传入的参数转换为Socket
            string str = clientSocket.RemoteEndPoint.ToString(); // 获取客户端的远程端点(IP+端口)
            while (true) {
                try {
                  byte[] buffer = new byte; // 创建缓存区,大小为1MB
                  int length = clientSocket.Receive(buffer); // 接收客户端数据
                  string message = Encoding.UTF8.GetString(buffer, 0, length); // 将字节数组转换为字符串
                  if (length != 0) {
                        Form_Server._ShowServerLogEvent($" 接收客户端{clientSocket.RemoteEndPoint}信息={message}"); // 显示接收到的消息
                  }
                }
                catch (Exception) {
                  Form_Server._RemoveListEvent(str); // 从UI列表中移除已断开的客户端
                  dicClientSockets.Remove(str); // 从客户端字典中移除该客户端的Socket
                  dicReceiveMsg.Remove(str); // 从接收消息线程字典中移除该客户端的线程
                  break; // 退出接收数据的循环
                }
            }
      }
    }
} 代码剖析:
服务器初始化: 在构造函数中,初始化了服务器的Socket、监听端口和IP地址。
绑定与监听: Bind() 方法会启动一个监听线程,等待客户端连接请求。
客户端连接受理: 客户端连接通过 ListenConnectRequest() 方法处理。每当有客户端连接时,创建一个新的线程来接收客户端数据。
发送与接收数据: SendToClient() 方法用于发送数据到指定客户端,而 ReceiveData() 方法则接收客户端发送的数据。
断开与关闭: DisConnectClient() 和 ShutDown() 方法分别用于断开客户端连接和关闭服务器监听。

接下来是服务器界面的代码:
using System;
using System.Drawing;
using System.Net;
using System.Net.Sockets;
using System.Windows.Forms;

namespace TCPIP_Test {
    // 委托用于更新服务器日志
    public delegate void ShowServerLogDelegate(string message);
    // 委托用于向客户端列表中添加客户端
    public delegate void AddListDelegate(string value);
    // 委托用于从客户端列表中移除客户端
    public delegate void RemoveListDelegate(string value);
   
    public partial class Form_Server : Form {
      // 静态委托实例,用于更新日志、添加或移除客户端
      public static ShowServerLogDelegate _ShowServerLogEvent = null;
      public static AddListDelegate _AddListEvent = null;
      public static RemoveListDelegate _RemoveListEvent = null;

      // TCP服务器实例
      TcpIp_Server tcpIp_Server;
      string ip;// 服务器IP地址
      int port;// 服务器端口
      string msg;// 用于存储消息
      Form_Client form_Client;// 客户端窗体实例
      String[] clientList;// 当前连接的客户端列表

      // 构造函数,初始化窗体
      public Form_Server() {
            InitializeComponent();
      }

      // 窗体加载时执行的操作
      private void Form_Server_Load(object sender, EventArgs e) {
            // 订阅日志、添加客户端和移除客户端事件
            _ShowServerLogEvent += ShowServerLog;
            _AddListEvent += AddList;
            _RemoveListEvent += RemoveList;

            // 获取本机的IP地址并添加到ComboBox控件
            GetIP();
            
            // 设置默认端口为5000
            port = int.Parse(textBox_Port.Text = "5000");
      }

      // 获取本机所有的IP地址,并将IPv4地址添加到IP地址选择框
      private void GetIP() {
            string name = Dns.GetHostName();// 获取主机名
            IPAddress[] iPAddress = Dns.GetHostAddresses(name);// 获取所有IP地址
            foreach (IPAddress item in iPAddress) {
                // 只添加IPv4地址到ComboBox中
                if (item.AddressFamily == AddressFamily.InterNetwork)
                  comboBox_IP.Items.Add(item.ToString());
            }
            // 设置默认选择为第一个IP地址
            comboBox_IP.SelectedIndex = 0;
      }

      // 开始监听按钮点击事件
      private void button_Listen_Click(object sender, EventArgs e) {
            // 检查是否已输入IP和端口
            if (comboBox_IP.SelectedItem == null || textBox_Port.Text == "")
            {
                MessageBox.Show("请输入IP和Port!");
                return;
            }
            
            ip = comboBox_IP.SelectedItem.ToString();// 获取选择的IP地址
            port = int.Parse(textBox_Port.Text);// 获取端口号
            
            // 创建TCP服务器实例并初始化
            tcpIp_Server = new TcpIp_Server(ip, port);
            _ShowServerLogEvent($" 服务器初始化完成");

            // 启动服务器监听
            _ShowServerLogEvent($" 服务器开始监听...");
            if(tcpIp_Server.Bind(ref msg))
                button_Listen.BackColor = Color.YellowGreen;// 设置监听按钮颜色为绿色
            _ShowServerLogEvent($"{msg}");// 显示监听状态消息
      }

      // 停止监听按钮点击事件
      private void Button_ShutDown_Click(object sender, EventArgs e) {
            // 停止服务器监听
            _ShowServerLogEvent($" 服务器停止监听...");
            tcpIp_Server.ShutDown(clientList, ref msg);
            listBox_Client.Items.Clear();// 清空客户端列表
            label_ClientCount.Text = "0";// 更新客户端数量显示
            button_Listen.BackColor = Color.LightGray;// 恢复监听按钮颜色
            _ShowServerLogEvent($"{msg}");// 显示停止监听的消息
      }

      // 单个客户端发送消息按钮点击事件
      private void Button_SendOnce_Click(object sender, EventArgs e) {
            // 检查是否选择了客户端
            if (listBox_Client.SelectedIndex == -1) {
                MessageBox.Show(new Form { TopMost = true }, $"请选择客户端!", "Error");
                return;
            }

            // 获取选择的客户端和消息内容
            _ShowServerLogEvent($" 服务器单发送信息...");
            string client = listBox_Client.SelectedItem.ToString();
            string cmd = textBox_Message.Text;
            
            // 向客户端发送消息
            tcpIp_Server.SendToClient(client, cmd, ref msg);
            _ShowServerLogEvent($"{msg}");// 显示发送状态消息
      }

      // 向所有客户端发送消息按钮点击事件
      private void button_SendAll_Click(object sender, EventArgs e) {
            _ShowServerLogEvent($" 服务器多发送信息...");
            string cmd = textBox_Message.Text;// 获取消息内容
            for (int i = 0; i < listBox_Client.Items.Count; i++) {
                // 向所有客户端发送消息
                tcpIp_Server.SendToClient(listBox_Client.Items.ToString(), cmd, ref msg);
                _ShowServerLogEvent($"{msg}");// 显示每次发送的消息
            }
      }

      // 清空日志按钮点击事件
      private void Button_Clear_Click(object sender, EventArgs e) {
            richTextBox_Log.Text = "";// 清空日志框
      }

      // 打开客户端按钮点击事件(目前被注释掉)
      private void button_OpenClient_Click(object sender, EventArgs e) {
            // 这里的代码被注释掉,表示当前功能未启用
            //if (form_Client == null || form_Client.IsDisposed) {
            //    form_Client = new Form_Client();
            //    form_Client.Show();
            //}
            //else {
            //    form_Client.TopMost = true;
            //}
      }

      // 服务器窗体关闭时的处理
      private void Form_Server_FormClosing(object sender, FormClosingEventArgs e) {
            // 确保在窗体关闭时关闭服务器
            if (tcpIp_Server != null)
                tcpIp_Server.ShutDown(clientList, ref msg);
            _ShowServerLogEvent($"{msg}");// 显示服务器关闭消息
            _ShowServerLogEvent -= ShowServerLog;// 取消订阅日志事件
      }

      // 显示服务器日志的方法(线程安全更新UI)
      private void ShowServerLog(string message) {
            if (InvokeRequired) {
                this.BeginInvoke(new Action(() => ShowServerLog(message)));// 在UI线程更新日志
            }
            else {
                int maxLine = 100;// 设置日志最大行数
                if (this.richTextBox_Log.Lines.Length > maxLine) {
                  // 如果日志行数超过最大行数,删除最旧的日志
                  this.richTextBox_Log.Text = richTextBox_Log.Text.Substring(richTextBox_Log.Lines.Length + 1);
                }
                // 在日志框中追加新的日志
                richTextBox_Log.AppendText($"{DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss(fff)")} {message}\r\n");
                richTextBox_Log.SelectionStart = richTextBox_Log.Text.Length;
                richTextBox_Log.ScrollToCaret();// 滚动到日志的最新位置
            }
      }

      // 向客户端列表中添加客户端(线程安全操作)
      private void AddList(string value) {
            if (InvokeRequired) {
                this.BeginInvoke(new Action(() => AddList(value)));// 在UI线程更新客户端列表
            }
            else {
                listBox_Client.Items.Add(value);// 添加客户端到列表
                // 更新客户端列表数组
                clientList = new String;
                int i = 0;
                foreach (var item in listBox_Client.Items) {
                  clientList = item.ToString();
                }
                label_ClientCount.Text = clientList.Length.ToString();// 更新客户端数量显示
            }
      }

      // 从客户端列表中移除客户端(线程安全操作)
      private void RemoveList(string value) {
            if (InvokeRequired) {
                this.BeginInvoke(new Action(() => RemoveList(value)));// 在UI线程更新客户端列表
            }
            else {
                listBox_Client.Items.Remove(value);// 从列表中移除客户端
                // 更新客户端列表数组
                int i = 0;
                foreach (var item in listBox_Client.Items) {
                  clientList = item.ToString();
                }
                label_ClientCount.Text = clientList.Length.ToString();// 更新客户端数量显示
            }
      }
    }
} 功能剖析:
服务器配置与启动:选择IP地址和端口,启动服务器监听客户端连接。
客户端管理:显示连接的客户端,支持单个或全部客户端发送消息。
日志记载:实时显示服务器日志,记载连接、消息发送等操作。
制止服务器:制止监听,清空客户端列表,断开连接。

客户端实现

服务器端实现完成后,接下来我们来实现TCP客户端。客户端界面代码与服务器端类似,主要利用以下类:
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace TCPIP_Test {
    // 定义TCP客户端类
    public class TcpIp_Client {
      // 客户端Socket对象,用于与服务器建立TCP连接
      Socket clientSocket;
      // 服务器的IP地址
      string _IP;
      // 服务器的端口
      int _Port;
      // 服务器的IPAddress对象
      IPAddress _ipAddress;
      // 服务器的IPEndPoint对象,包含IP地址和端口
      IPEndPoint _iPEndPoint;
      // 标识连接状态
      bool linked = false;
      // 标识是否曾经断开连接
      bool unlinked = false;

      // 构造函数,初始化IP地址和端口
      public TcpIp_Client(string ip, int port) {
            clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); // 创建TCP连接的Socket对象
            _IP = ip; // 设置IP地址
            _Port = port; // 设置端口号
            _ipAddress = IPAddress.Parse(ip); // 将字符串IP地址解析为IPAddress对象
            _iPEndPoint = new IPEndPoint(_ipAddress, port); // 创建端点对象,包含IP地址和端口
      }

      // 当前连接状态
      private bool _Connected;
      public bool Connected {
            get { return _Connected = clientSocket.Connected; } // 返回Socket的连接状态
      }

      // 连接到服务器
      public bool ConnectServer(ref string msg) {
            try {
                if (!linked) { // 如果没有连接
                  if (unlinked) {
                        // 如果曾经断开连接,重新创建Socket
                        clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                  }
                  // 连接到服务器
                  clientSocket.Connect(_iPEndPoint);
                  if (clientSocket.Connected) { // 如果连接成功
                        linked = true; // 设置连接状态为已连接
                        msg = $" 服务器{clientSocket.LocalEndPoint.ToString()}连接成功!"; // 设置成功消息
                        ReceiveData(); // 调用方法开始接收数据
                        return true;
                  } else { // 如果连接失败
                        msg = $" 客户端连接失败!";
                        return false;
                  }
                } else { // 如果已经连接
                  msg = $" 已连接";
                  return true;
                }
            }
            catch (Exception ex) {
                msg = $" 连接失败!信息={ex}"; // 连接失败时设置错误消息
                return false;
            }
      }

      // 断开与服务器的连接
      public bool DisConnectServer(ref string msg) {
            try {
                if (linked) { // 如果已连接
                  linked = false; // 设置连接状态为未连接
                  clientSocket.Disconnect(false); // 断开连接并释放资源
                  unlinked = true; // 标记为已断开
                  msg = $" 客户端连接断开";
                  return true;
                } else { // 如果已经是断开状态
                  msg = $" 已断开";
                  return true;
                }
            }
            catch (Exception ex) {
                msg = $" 断开失败!信息={ex}"; // 断开连接失败时设置错误消息
                return false;
            }
      }

      // 向服务器发送消息
      public bool SendToServer(string cmd, ref string msg) {
            try {
                if (clientSocket.Connected) { // 如果已连接
                  clientSocket.Send(Encoding.UTF8.GetBytes(cmd)); // 将命令转换为字节并发送
                  msg = $" 发送{clientSocket.LocalEndPoint.ToString()}信息={cmd}"; // 设置发送成功的消息
                  return true;
                } else { // 如果未连接
                  MessageBox.Show(new Form { TopMost = true }, "未连接!", "Info", MessageBoxButtons.OK); // 弹出提示框
                  msg = $"未连接!";
                  return false;
                }
            }
            catch (Exception ex) {
                msg = $" 发送信息失败!信息={ex}"; // 发送失败时设置错误消息
                return false;
            }
      }

      // 接收来自服务器的数据
      private void ReceiveData() {
            string str = ""; // 存储接收到的消息
            Task.Run(() => {
                while (linked) { // 只要连接保持有效,就持续接收数据
                  try {
                        if (clientSocket.Connected) {
                            Thread.Sleep(10); // 为了避免占用过多的CPU时间,稍微暂停一下
                        } else {
                            continue; // 如果连接断开,继续检查连接状态
                        }
                        byte[] data = new byte; // 缓冲区用于接收数据
                        int length = clientSocket.Receive(data); // 接收服务器发送的数据
                        string message = Encoding.UTF8.GetString(data, 0, length); // 将接收到的字节数据转换为字符串
                        if (message != "") {
                            str = message; // 存储接收到的消息
                            Form_Client._ShowClientLog($" 接收服务器{clientSocket.LocalEndPoint.ToString()}信息={message}"); // 显示接收到的消息
                        }
                  }
                  catch (Exception ex) {
                        Form_Client._ShowClientLog($" 接收服务器信息失败!信息={ex}"); // 如果接收失败,显示错误信息
                  }
                }
            });
      }
    }
} 代码剖析:
TcpIp_Client类:该类用于实现一个TCP客户端,提供连接服务器、断开连接、发送消息、接收消息等功能。
构造函数:担当服务器的IP地址和端标语,初始化Socket并创建连接端点(IPEndPoint)。
ConnectServer方法:建立与服务器的TCP连接。连接成功后,启动接收数据的线程。
DisConnectServer方法:断开与服务器的连接并释放相关资源。
SendToServer方法:将给定的下令发送到服务器。
ReceiveData方法:接收来自服务器的消息,并在接收到数据时将其打印到客户端界面或日志中。
关键技术:
Socket编程:利用Socket类进行TCP连接的建立、数据的发送和接收。
多线程:ReceiveData方法通过Task.Run()启动一个新的线程来异步接收数据。
消息编码:利用UTF8对消息进行编码息争码。

客户端界面的实今世码如下:
using System;
using System.Drawing;
using System.Net;
using System.Net.Sockets;
using System.Windows.Forms;

namespace TCPIP_Test
{
    // 定义一个委托,用于显示客户端日志信息
    public delegate void EventShowClientLog(string message);

    // 客户端窗口类
    public partial class Form_Client : Form
    {
      // 声明委托实例,用于日志显示
      public static EventShowClientLog _ShowClientLog = null;
      
      // TCP客户端实例
      TcpIp_Client tcpIp_Client;
      
      // 存储IP地址和端口
      string ip;
      int port;
      string msg;
      
      // 服务器窗口实例
      Form_Server form_Server;

      // 构造函数,初始化组件
      public Form_Client()
      {
            InitializeComponent();
      }

      // 窗体加载时的事件处理
      private void Form1_Load(object sender, EventArgs e)
      {
            // 绑定委托到日志显示方法
            _ShowClientLog += ShowClientLog;

            // 获取本机IP地址并填充到下拉框中
            GetIP();

            // 默认端口5000
            port = int.Parse(textBox_Port.Text = "5000");
      }

      // 获取本机IP地址的方法
      private void GetIP()
      {
            // 获取本机的计算机名
            string name = Dns.GetHostName();

            // 获取所有IP地址
            IPAddress[] iPAddress = Dns.GetHostAddresses(name);

            // 遍历所有IP地址,只添加IPv4地址到下拉框中
            foreach (IPAddress item in iPAddress)
            {
                if (item.AddressFamily == AddressFamily.InterNetwork)
                  comboBox_IP.Items.Add(item.ToString());
            }

            // 默认选择第一个IP地址
            comboBox_IP.SelectedIndex = 0;
      }

      // 连接按钮点击事件处理
      private void Button_Connect_Click(object sender, EventArgs e)
      {
            // 判断是否选择了IP地址和端口
            if (comboBox_IP.SelectedItem == null || textBox_Port.Text == "")
            {
                MessageBox.Show("请输入IP和Port!");
                return;
            }

            // 获取选择的IP和端口
            ip = comboBox_IP.SelectedItem.ToString();
            port = int.Parse(textBox_Port.Text);

            // 创建TCP客户端实例并尝试连接到服务器
            tcpIp_Client = new TcpIp_Client(ip, port);
            _ShowClientLog($" 客户端初始化完成");

            _ShowClientLog($" 客户端开始连接...");

            // 尝试连接服务器
            if (tcpIp_Client.ConnectServer(ref msg))
                button_Connect.BackColor = Color.YellowGreen; // 连接成功后,改变按钮颜色
            _ShowClientLog($"{msg}");
      }

      // 断开连接按钮点击事件处理
      private void Button_DisConnect_Click(object sender, EventArgs e)
      {
            _ShowClientLog($" 客户端断开连接...");
            
            // 调用断开连接方法
            tcpIp_Client.DisConnectServer(ref msg);
            
            button_Connect.BackColor = Color.LightGray; // 断开连接后,恢复按钮颜色
            _ShowClientLog($"{msg}");
      }

      // 发送一次数据按钮点击事件处理
      private void Button_SendOnce_Click(object sender, EventArgs e)
      {
            _ShowClientLog($" 客户端发送信息...");

            // 获取输入框中的信息
            string cmd = textBox_Message.Text;

            // 发送数据到服务器
            tcpIp_Client.SendToServer(cmd, ref msg);
            _ShowClientLog($"{msg}");
      }

      // 显示日志信息的方法
      private void ShowClientLog(string message)
      {
            // 判断是否需要在UI线程中更新
            if (richTextBox_Log.InvokeRequired)
            {
                EventShowClientLog d = new EventShowClientLog(ShowClientLog);
                richTextBox_Log.Invoke(d, new object[] { message });
            }
            else
            {
                // 最大显示行数限制
                int maxLine = 100;

                // 如果超过最大行数,删除最旧的日志行
                if (this.richTextBox_Log.Lines.Length > maxLine)
                {
                  this.richTextBox_Log.Text = richTextBox_Log.Text.Substring(richTextBox_Log.Lines.Length + 1);
                }

                // 添加日志到文本框,并显示当前时间戳
                richTextBox_Log.AppendText($"{DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss(fff)")} {message}\r\n");

                // 滚动到文本框底部
                richTextBox_Log.SelectionStart = richTextBox_Log.Text.Length;
                richTextBox_Log.ScrollToCaret();
            }
      }

      // 清除日志按钮点击事件处理
      private void Button_Clear_Click(object sender, EventArgs e)
      {
            // 清空日志显示框
            richTextBox_Log.Text = "";
      }

      // 打开服务器窗口按钮点击事件处理
      private void button_OpenServer_Click(object sender, EventArgs e)
      {
            // 如果服务器窗口不存在或已关闭,则新建一个服务器窗口
            if (form_Server == null || form_Server.IsDisposed)
            {
                form_Server = new Form_Server();
                form_Server.Show();
            }
            else
            {
                // 如果服务器窗口已经打开,确保它位于最前面
                form_Server.TopMost = true;
            }
      }
    }
} 代码剖析:
1.EventShowClientLog 委托   用于线程安全地更新客户端日志。
2.Form1_Load()   加载时获取本机IP地址并填充IP选择框,设置默认端口。
3.GetIP()   获取并显示本机全部IPv4地址。
4.Button_Connect_Click()连接服务器,成功后更新UI显示连接信息。
5.Button_DisConnect_Click()断开与服务器的连接,并显示断开信息。
6.Button_SendOnce_Click()   发送文本框内容到服务器,并显示发送结果。
7.ShowClientLog()   显示日志信息,超出限定时自动删除最旧日志。
8.Button_Clear_Click()  清空日志框内容。
9.button_OpenServer_Click()   打开或显示服务器窗口。

总结

本文介绍了怎样利用C#实现TCP客户端和服务器,并通过简朴的代码示例展示了怎样设置客户端与服务器的通信。通过设置监听端口和获取客户端IP地址,您可以在客户端和服务器之间建立连接并相互发送消息。通过进一步的优化和扩展,您可以实现更为复杂的网络通信功能。

源码地址:https://download.csdn.net/download/weixin_44643352/90058182

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: C#实现TCP客户端和服务器