C#实现TCP客户端和服务器
本文将介绍如何使用C#实现TCP客户端和服务器的基本功能,客户端与服务器可以相互发送消息。
效果展示
服务器端实现
首先,我们实现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 = $"[Info] 服务器{tcpListener.LocalEndpoint.ToString()}监听成功!"; // 返回监听成功的消息
return true;
}
else {
msg = $"[Info] 已监听"; // 如果已经开始监听,则返回已监听消息
return true;
}
}
catch (Exception ex) {
msg = $"[Err] 连接失败!信息={ex}"; // 如果发生异常,返回错误信息
return false;
}
}
// 断开与指定客户端的连接
public bool DisConnectClient(string client, ref string msg) {
try {
if (dicClientSockets.ContainsKey(client)) {
dicClientSockets[client].Close(); // 关闭与客户端的连接
msg = $"[Info] 断开客户端{client}连接"; // 返回断开成功的消息
return true;
}
else {
msg = $"[Info] 客户端{client}已断开"; // 如果客户端已断开,返回已断开消息
return true;
}
}
catch (Exception ex) {
msg = $"[Err] 断开失败!信息={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[clientList[i]].Close(); // 关闭每个客户端的连接
}
msg = $"[Info] 服务器监听断开"; // 返回关闭监听的消息
return true;
}
else {
unlinked = true; // 标记已断开
msg = $"[Info] 已断开"; // 返回已断开消息
return true;
}
}
catch (Exception ex) {
tcpListener.Stop(); // 停止TcpListener
unlinked = true; // 标记已断开
msg = $"[Info] 已断开!!!"; // 返回关闭连接的消息
return false;
}
}
// 向指定客户端发送数据
public bool SendToClient(string client, string cmd, ref string msg) {
try {
if (!string.IsNullOrEmpty(cmd)) {
dicClientSockets[client].Send(Encoding.UTF8.GetBytes(cmd)); // 将命令数据发送给客户端
msg = $"[Info] 发送{client}信息={cmd}"; // 返回发送成功的消息
return true;
}
else
return false; // 如果命令为空,返回发送失败
}
catch (Exception ex) {
msg = $"[Err] 发送信息失败!信息={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($"[Err] 监听失败!信息={ex}"); // 监听失败时显示错误日志
}
}
}
// 接收客户端发送的数据
public void ReceiveData(Object obj) {
Socket clientSocket = (Socket)obj; // 将传入的参数转换为Socket
string str = clientSocket.RemoteEndPoint.ToString(); // 获取客户端的远程端点(IP+端口)
while (true) {
try {
byte[] buffer = new byte[1024 * 1024]; // 创建缓存区,大小为1MB
int length = clientSocket.Receive(buffer); // 接收客户端数据
string message = Encoding.UTF8.GetString(buffer, 0, length); // 将字节数组转换为字符串
if (length != 0) {
Form_Server._ShowServerLogEvent($"[Info] 接收客户端{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($"[Info] 服务器初始化完成");
// 启动服务器监听
_ShowServerLogEvent($"[Info] 服务器开始监听...");
if(tcpIp_Server.Bind(ref msg))
button_Listen.BackColor = Color.YellowGreen; // 设置监听按钮颜色为绿色
_ShowServerLogEvent($"{msg}"); // 显示监听状态消息
}
// 停止监听按钮点击事件
private void Button_ShutDown_Click(object sender, EventArgs e) {
// 停止服务器监听
_ShowServerLogEvent($"[Info] 服务器停止监听...");
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($"[Info] 服务器单发送信息...");
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($"[Info] 服务器多发送信息...");
string cmd = textBox_Message.Text; // 获取消息内容
for (int i = 0; i < listBox_Client.Items.Count; i++) {
// 向所有客户端发送消息
tcpIp_Server.SendToClient(listBox_Client.Items[i].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[0].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[listBox_Client.Items.Count];
int i = 0;
foreach (var item in listBox_Client.Items) {
clientList[i] = 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[i] = 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 = $"[Info] 服务器{clientSocket.LocalEndPoint.ToString()}连接成功!"; // 设置成功消息
ReceiveData(); // 调用方法开始接收数据
return true;
} else { // 如果连接失败
msg = $"[Info] 客户端连接失败!";
return false;
}
} else { // 如果已经连接
msg = $"[Info] 已连接";
return true;
}
}
catch (Exception ex) {
msg = $"[Err] 连接失败!信息={ex}"; // 连接失败时设置错误消息
return false;
}
}
// 断开与服务器的连接
public bool DisConnectServer(ref string msg) {
try {
if (linked) { // 如果已连接
linked = false; // 设置连接状态为未连接
clientSocket.Disconnect(false); // 断开连接并释放资源
unlinked = true; // 标记为已断开
msg = $"[Info] 客户端连接断开";
return true;
} else { // 如果已经是断开状态
msg = $"[Info] 已断开";
return true;
}
}
catch (Exception ex) {
msg = $"[Err] 断开失败!信息={ex}"; // 断开连接失败时设置错误消息
return false;
}
}
// 向服务器发送消息
public bool SendToServer(string cmd, ref string msg) {
try {
if (clientSocket.Connected) { // 如果已连接
clientSocket.Send(Encoding.UTF8.GetBytes(cmd)); // 将命令转换为字节并发送
msg = $"[Info] 发送{clientSocket.LocalEndPoint.ToString()}信息={cmd}"; // 设置发送成功的消息
return true;
} else { // 如果未连接
MessageBox.Show(new Form { TopMost = true }, "未连接!", "Info", MessageBoxButtons.OK); // 弹出提示框
msg = $"未连接!";
return false;
}
}
catch (Exception ex) {
msg = $"[Err] 发送信息失败!信息={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[1024]; // 缓冲区用于接收数据
int length = clientSocket.Receive(data); // 接收服务器发送的数据
string message = Encoding.UTF8.GetString(data, 0, length); // 将接收到的字节数据转换为字符串
if (message != "") {
str = message; // 存储接收到的消息
Form_Client._ShowClientLog($"[Info] 接收服务器{clientSocket.LocalEndPoint.ToString()}信息={message}"); // 显示接收到的消息
}
}
catch (Exception ex) {
Form_Client._ShowClientLog($"[Err] 接收服务器信息失败!信息={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($"[Info] 客户端初始化完成");
_ShowClientLog($"[Info] 客户端开始连接...");
// 尝试连接服务器
if (tcpIp_Client.ConnectServer(ref msg))
button_Connect.BackColor = Color.YellowGreen; // 连接成功后,改变按钮颜色
_ShowClientLog($"{msg}");
}
// 断开连接按钮点击事件处理
private void Button_DisConnect_Click(object sender, EventArgs e)
{
_ShowClientLog($"[Info] 客户端断开连接...");
// 调用断开连接方法
tcpIp_Client.DisConnectServer(ref msg);
button_Connect.BackColor = Color.LightGray; // 断开连接后,恢复按钮颜色
_ShowClientLog($"{msg}");
}
// 发送一次数据按钮点击事件处理
private void Button_SendOnce_Click(object sender, EventArgs e)
{
_ShowClientLog($"[Info] 客户端发送信息...");
// 获取输入框中的信息
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[0].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