欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C#實(shí)現(xiàn)TCP客戶端和服務(wù)器的基本功能

 更新時(shí)間:2024年12月10日 08:53:59   作者:數(shù)據(jù)的世界01  
本文將介紹如何使用C#實(shí)現(xiàn)TCP客戶端和服務(wù)器的基本功能,客戶端與服務(wù)器可以相互發(fā)送消息,文章通過(guò)代碼講解的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下

效果展示

服務(wù)器端實(shí)現(xiàn)

首先,我們實(shí)現(xiàn)TCP服務(wù)器。以下是服務(wù)器端所需的類和代碼:

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; // 服務(wù)器端Socket,用于服務(wù)器與客戶端的通信
        Socket clientSocket; // 客戶端Socket,用于與客戶端建立連接
        TcpListener tcpListener; // 負(fù)責(zé)監(jiān)聽(tīng)客戶端的連接請(qǐng)求
        Thread tcpListenerThread; // 監(jiān)聽(tīng)連接請(qǐng)求的線程
        Dictionary<string, Socket> dicClientSockets = new Dictionary<string, Socket>(); // 存儲(chǔ)客戶端Socket的集合,以客戶端的IP/端口作為鍵
        Dictionary<string, Thread> dicReceiveMsg = new Dictionary<string, Thread>(); // 存儲(chǔ)每個(gè)客戶端接收消息的線程集合
 
        string _IP; // 服務(wù)器的IP地址
        int _Port; // 服務(wù)器的端口
        IPAddress _ipAddress; // 服務(wù)器的IPAddress對(duì)象
        EndPoint _endPoint; // 服務(wù)器的端點(diǎn),包括IP地址和端口
        bool linked = false; // 標(biāo)識(shí)服務(wù)器是否已開(kāi)始監(jiān)聽(tīng)客戶端連接
        bool unlinked = false; // 標(biāo)識(shí)服務(wù)器是否已關(guān)閉連接
 
        // 構(gòu)造函數(shù),初始化服務(wù)器的IP和端口
        public TcpIp_Server(string ip, int port) {
            serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); // 初始化Socket對(duì)象,使用TCP協(xié)議
            _IP = ip;
            _Port = port;
            _ipAddress = IPAddress.Parse(ip); // 將IP地址字符串轉(zhuǎn)換為IPAddress對(duì)象
            _endPoint = new IPEndPoint(_ipAddress, port); // 構(gòu)造服務(wù)器端點(diǎn)
        }
 
        // 判斷服務(wù)器是否已綁定到指定的端口
        private bool _IsBound;
        public bool IsBound {
            get { return _IsBound = serverSocket.IsBound; }
        }
 
        // 判斷服務(wù)器Socket是否已連接
        private bool _Connected;
        public bool Connected {
            get { return _Connected = serverSocket.Connected; }
        }
 
        // 綁定服務(wù)器并開(kāi)始監(jiān)聽(tīng)客戶端連接
        public bool Bind(ref string msg) {
            try {
                if (!linked) {
                    tcpListener = new TcpListener(_ipAddress, _Port); // 創(chuàng)建TcpListener對(duì)象,綁定IP和端口
                    tcpListener.Start(); // 啟動(dòng)監(jiān)聽(tīng)
                    linked = true; // 標(biāo)記已開(kāi)始監(jiān)聽(tīng)
                    ThreadStart threadStart = new ThreadStart(ListenConnectRequest); // 創(chuàng)建一個(gè)委托,執(zhí)行監(jiān)聽(tīng)連接請(qǐng)求的方法
                    tcpListenerThread = new Thread(threadStart); // 創(chuàng)建一個(gè)新線程來(lái)監(jiān)聽(tīng)客戶端請(qǐng)求
                    tcpListenerThread.IsBackground = true; // 設(shè)置為后臺(tái)線程
                    tcpListenerThread.Start(); // 啟動(dòng)監(jiān)聽(tīng)線程
                    msg = $"[Info] 服務(wù)器{tcpListener.LocalEndpoint.ToString()}監(jiān)聽(tīng)成功!"; // 返回監(jiān)聽(tīng)成功的消息
                    return true;
                }
                else {
                    msg = $"[Info] 已監(jiān)聽(tīng)"; // 如果已經(jīng)開(kāi)始監(jiān)聽(tīng),則返回已監(jiān)聽(tīng)消息
                    return true;
                }
            }
            catch (Exception ex) {
                msg = $"[Err] 連接失敗!信息={ex}"; // 如果發(fā)生異常,返回錯(cuò)誤信息
                return false;
            }
        }
 
        // 斷開(kāi)與指定客戶端的連接
        public bool DisConnectClient(string client, ref string msg) {
            try {
                if (dicClientSockets.ContainsKey(client)) {
                    dicClientSockets[client].Close(); // 關(guān)閉與客戶端的連接
                    msg = $"[Info] 斷開(kāi)客戶端{(lán)client}連接"; // 返回?cái)嚅_(kāi)成功的消息
                    return true;
                }
                else {
                    msg = $"[Info] 客戶端{(lán)client}已斷開(kāi)"; // 如果客戶端已斷開(kāi),返回已斷開(kāi)消息
                    return true;
                }
            }
            catch (Exception ex) {
                msg = $"[Err] 斷開(kāi)失敗!信息={ex}"; // 如果發(fā)生異常,返回錯(cuò)誤信息
                return false;
            }
        }
 
        // 關(guān)閉服務(wù)器監(jiān)聽(tīng)并斷開(kāi)所有客戶端連接
        public bool ShutDown(string[] clientList, ref string msg) {
            try {
                if (linked) {
                    linked = false; // 標(biāo)記服務(wù)器停止監(jiān)聽(tīng)
                    tcpListener.Stop(); // 停止TcpListener監(jiān)聽(tīng)
                    for (int i = 0; i < clientList.Length; i++) {
                        dicClientSockets[clientList[i]].Close(); // 關(guān)閉每個(gè)客戶端的連接
                    }
                    msg = $"[Info] 服務(wù)器監(jiān)聽(tīng)斷開(kāi)"; // 返回關(guān)閉監(jiān)聽(tīng)的消息
                    return true;
                }
                else {
                    unlinked = true; // 標(biāo)記已斷開(kāi)
                    msg = $"[Info] 已斷開(kāi)"; // 返回已斷開(kāi)消息
                    return true;
                }
            }
            catch (Exception ex) {
                tcpListener.Stop(); // 停止TcpListener
                unlinked = true; // 標(biāo)記已斷開(kāi)
                msg = $"[Info] 已斷開(kāi)!!!"; // 返回關(guān)閉連接的消息
                return false;
            }
        }
 
        // 向指定客戶端發(fā)送數(shù)據(jù)
        public bool SendToClient(string client, string cmd, ref string msg) {
            try {
                if (!string.IsNullOrEmpty(cmd)) {
                    dicClientSockets[client].Send(Encoding.UTF8.GetBytes(cmd)); // 將命令數(shù)據(jù)發(fā)送給客戶端
                    msg = $"[Info] 發(fā)送{client}信息={cmd}"; // 返回發(fā)送成功的消息
                    return true;
                }
                else
                    return false; // 如果命令為空,返回發(fā)送失敗
            }
            catch (Exception ex) {
                msg = $"[Err] 發(fā)送信息失敗!信息={ex}"; // 如果發(fā)送失敗,返回錯(cuò)誤信息
                return false;
            }
        }
 
        // 監(jiān)聽(tīng)客戶端的連接請(qǐng)求
        private void ListenConnectRequest() {
            while (linked) {
                try {
                    Socket clientSocket = tcpListener.AcceptSocket(); // 等待并接受客戶端連接
                    ParameterizedThreadStart parameterizedThreadStart = new ParameterizedThreadStart(ReceiveData); // 創(chuàng)建接收數(shù)據(jù)的線程委托
                    Thread receiveMsgThread = new Thread(parameterizedThreadStart); // 創(chuàng)建一個(gè)線程來(lái)接收客戶端數(shù)據(jù)
                    receiveMsgThread.IsBackground = true; // 設(shè)置為后臺(tái)線程
                    receiveMsgThread.Start(clientSocket); // 啟動(dòng)線程并傳入客戶端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] 監(jiān)聽(tīng)失??!信息={ex}"); // 監(jiān)聽(tīng)失敗時(shí)顯示錯(cuò)誤日志
                }
            }
        }
 
        // 接收客戶端發(fā)送的數(shù)據(jù)
        public void ReceiveData(Object obj) {
            Socket clientSocket = (Socket)obj; // 將傳入的參數(shù)轉(zhuǎn)換為Socket
            string str = clientSocket.RemoteEndPoint.ToString(); // 獲取客戶端的遠(yuǎn)程端點(diǎn)(IP+端口)
            while (true) {
                try {
                    byte[] buffer = new byte[1024 * 1024]; // 創(chuàng)建緩存區(qū),大小為1MB
                    int length = clientSocket.Receive(buffer); // 接收客戶端數(shù)據(jù)
                    string message = Encoding.UTF8.GetString(buffer, 0, length); // 將字節(jié)數(shù)組轉(zhuǎn)換為字符串
                    if (length != 0) {
                        Form_Server._ShowServerLogEvent($"[Info] 接收客戶端{(lán)clientSocket.RemoteEndPoint}信息={message}"); // 顯示接收到的消息
                    }
                }
                catch (Exception) {
                    Form_Server._RemoveListEvent(str); // 從UI列表中移除已斷開(kāi)的客戶端
                    dicClientSockets.Remove(str); // 從客戶端字典中移除該客戶端的Socket
                    dicReceiveMsg.Remove(str); // 從接收消息線程字典中移除該客戶端的線程
                    break; // 退出接收數(shù)據(jù)的循環(huán)
                }
            }
        }
    }
}

代碼解析:

服務(wù)器初始化: 在構(gòu)造函數(shù)中,初始化了服務(wù)器的Socket、監(jiān)聽(tīng)端口和IP地址。
綁定與監(jiān)聽(tīng): Bind() 方法會(huì)啟動(dòng)一個(gè)監(jiān)聽(tīng)線程,等待客戶端連接請(qǐng)求。
客戶端連接管理: 客戶端連接通過(guò) ListenConnectRequest() 方法處理。每當(dāng)有客戶端連接時(shí),創(chuàng)建一個(gè)新的線程來(lái)接收客戶端數(shù)據(jù)。
發(fā)送與接收數(shù)據(jù): SendToClient() 方法用于發(fā)送數(shù)據(jù)到指定客戶端,而 ReceiveData() 方法則接收客戶端發(fā)送的數(shù)據(jù)。
斷開(kāi)與關(guān)閉: DisConnectClient() 和 ShutDown() 方法分別用于斷開(kāi)客戶端連接和關(guān)閉服務(wù)器監(jiān)聽(tīng)。

接下來(lái)是服務(wù)器界面的代碼:

using System;
using System.Drawing;
using System.Net;
using System.Net.Sockets;
using System.Windows.Forms;
 
namespace TCPIP_Test {
    // 委托用于更新服務(wù)器日志
    public delegate void ShowServerLogDelegate(string message);
    // 委托用于向客戶端列表中添加客戶端
    public delegate void AddListDelegate(string value);
    // 委托用于從客戶端列表中移除客戶端
    public delegate void RemoveListDelegate(string value);
    
    public partial class Form_Server : Form {
        // 靜態(tài)委托實(shí)例,用于更新日志、添加或移除客戶端
        public static ShowServerLogDelegate _ShowServerLogEvent = null;
        public static AddListDelegate _AddListEvent = null;
        public static RemoveListDelegate _RemoveListEvent = null;
 
        // TCP服務(wù)器實(shí)例
        TcpIp_Server tcpIp_Server;
        string ip;  // 服務(wù)器IP地址
        int port;  // 服務(wù)器端口
        string msg;  // 用于存儲(chǔ)消息
        Form_Client form_Client;  // 客戶端窗體實(shí)例
        String[] clientList;  // 當(dāng)前連接的客戶端列表
 
        // 構(gòu)造函數(shù),初始化窗體
        public Form_Server() {
            InitializeComponent();
        }
 
        // 窗體加載時(shí)執(zhí)行的操作
        private void Form_Server_Load(object sender, EventArgs e) {
            // 訂閱日志、添加客戶端和移除客戶端事件
            _ShowServerLogEvent += ShowServerLog;
            _AddListEvent += AddList;
            _RemoveListEvent += RemoveList;
 
            // 獲取本機(jī)的IP地址并添加到ComboBox控件
            GetIP();
            
            // 設(shè)置默認(rèn)端口為5000
            port = int.Parse(textBox_Port.Text = "5000");
        }
 
        // 獲取本機(jī)所有的IP地址,并將IPv4地址添加到IP地址選擇框
        private void GetIP() {
            string name = Dns.GetHostName();  // 獲取主機(jī)名
            IPAddress[] iPAddress = Dns.GetHostAddresses(name);  // 獲取所有IP地址
            foreach (IPAddress item in iPAddress) {
                // 只添加IPv4地址到ComboBox中
                if (item.AddressFamily == AddressFamily.InterNetwork)
                    comboBox_IP.Items.Add(item.ToString());
            }
            // 設(shè)置默認(rèn)選擇為第一個(gè)IP地址
            comboBox_IP.SelectedIndex = 0;
        }
 
        // 開(kāi)始監(jiān)聽(tīng)按鈕點(diǎn)擊事件
        private void button_Listen_Click(object sender, EventArgs e) {
            // 檢查是否已輸入IP和端口
            if (comboBox_IP.SelectedItem == null || textBox_Port.Text == "")
            {
                MessageBox.Show("請(qǐng)輸入IP和Port!");
                return;
            }
            
            ip = comboBox_IP.SelectedItem.ToString();  // 獲取選擇的IP地址
            port = int.Parse(textBox_Port.Text);  // 獲取端口號(hào)
            
            // 創(chuàng)建TCP服務(wù)器實(shí)例并初始化
            tcpIp_Server = new TcpIp_Server(ip, port);
            _ShowServerLogEvent($"[Info] 服務(wù)器初始化完成");
 
            // 啟動(dòng)服務(wù)器監(jiān)聽(tīng)
            _ShowServerLogEvent($"[Info] 服務(wù)器開(kāi)始監(jiān)聽(tīng)...");
            if(tcpIp_Server.Bind(ref msg))
                button_Listen.BackColor = Color.YellowGreen;  // 設(shè)置監(jiān)聽(tīng)按鈕顏色為綠色
            _ShowServerLogEvent($"{msg}");  // 顯示監(jiān)聽(tīng)狀態(tài)消息
        }
 
        // 停止監(jiān)聽(tīng)按鈕點(diǎn)擊事件
        private void Button_ShutDown_Click(object sender, EventArgs e) {
            // 停止服務(wù)器監(jiān)聽(tīng)
            _ShowServerLogEvent($"[Info] 服務(wù)器停止監(jiān)聽(tīng)...");
            tcpIp_Server.ShutDown(clientList, ref msg);
            listBox_Client.Items.Clear();  // 清空客戶端列表
            label_ClientCount.Text = "0";  // 更新客戶端數(shù)量顯示
            button_Listen.BackColor = Color.LightGray;  // 恢復(fù)監(jiān)聽(tīng)按鈕顏色
            _ShowServerLogEvent($"{msg}");  // 顯示停止監(jiān)聽(tīng)的消息
        }
 
        // 單個(gè)客戶端發(fā)送消息按鈕點(diǎn)擊事件
        private void Button_SendOnce_Click(object sender, EventArgs e) {
            // 檢查是否選擇了客戶端
            if (listBox_Client.SelectedIndex == -1) {
                MessageBox.Show(new Form { TopMost = true }, $"請(qǐng)選擇客戶端!", "Error");
                return;
            }
 
            // 獲取選擇的客戶端和消息內(nèi)容
            _ShowServerLogEvent($"[Info] 服務(wù)器單發(fā)送信息...");
            string client = listBox_Client.SelectedItem.ToString();
            string cmd = textBox_Message.Text;
            
            // 向客戶端發(fā)送消息
            tcpIp_Server.SendToClient(client, cmd, ref msg);
            _ShowServerLogEvent($"{msg}");  // 顯示發(fā)送狀態(tài)消息
        }
 
        // 向所有客戶端發(fā)送消息按鈕點(diǎn)擊事件
        private void button_SendAll_Click(object sender, EventArgs e) {
            _ShowServerLogEvent($"[Info] 服務(wù)器多發(fā)送信息...");
            string cmd = textBox_Message.Text;  // 獲取消息內(nèi)容
            for (int i = 0; i < listBox_Client.Items.Count; i++) {
                // 向所有客戶端發(fā)送消息
                tcpIp_Server.SendToClient(listBox_Client.Items[i].ToString(), cmd, ref msg);
                _ShowServerLogEvent($"{msg}");  // 顯示每次發(fā)送的消息
            }
        }
 
        // 清空日志按鈕點(diǎn)擊事件
        private void Button_Clear_Click(object sender, EventArgs e) {
            richTextBox_Log.Text = "";  // 清空日志框
        }
 
        // 打開(kāi)客戶端按鈕點(diǎn)擊事件(目前被注釋掉)
        private void button_OpenClient_Click(object sender, EventArgs e) {
            // 這里的代碼被注釋掉,表示當(dāng)前功能未啟用
            //if (form_Client == null || form_Client.IsDisposed) {
            //    form_Client = new Form_Client();
            //    form_Client.Show();
            //}
            //else {
            //    form_Client.TopMost = true;
            //}
        }
 
        // 服務(wù)器窗體關(guān)閉時(shí)的處理
        private void Form_Server_FormClosing(object sender, FormClosingEventArgs e) {
            // 確保在窗體關(guān)閉時(shí)關(guān)閉服務(wù)器
            if (tcpIp_Server != null)
                tcpIp_Server.ShutDown(clientList, ref msg);
            _ShowServerLogEvent($"{msg}");  // 顯示服務(wù)器關(guān)閉消息
            _ShowServerLogEvent -= ShowServerLog;  // 取消訂閱日志事件
        }
 
        // 顯示服務(wù)器日志的方法(線程安全更新UI)
        private void ShowServerLog(string message) {
            if (InvokeRequired) {
                this.BeginInvoke(new Action(() => ShowServerLog(message)));  // 在UI線程更新日志
            }
            else {
                int maxLine = 100;  // 設(shè)置日志最大行數(shù)
                if (this.richTextBox_Log.Lines.Length > maxLine) {
                    // 如果日志行數(shù)超過(guò)最大行數(shù),刪除最舊的日志
                    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();  // 滾動(dòng)到日志的最新位置
            }
        }
 
        // 向客戶端列表中添加客戶端(線程安全操作)
        private void AddList(string value) {
            if (InvokeRequired) {
                this.BeginInvoke(new Action(() => AddList(value)));  // 在UI線程更新客戶端列表
            }
            else {
                listBox_Client.Items.Add(value);  // 添加客戶端到列表
                // 更新客戶端列表數(shù)組
                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();  // 更新客戶端數(shù)量顯示
            }
        }
 
        // 從客戶端列表中移除客戶端(線程安全操作)
        private void RemoveList(string value) {
            if (InvokeRequired) {
                this.BeginInvoke(new Action(() => RemoveList(value)));  // 在UI線程更新客戶端列表
            }
            else {
                listBox_Client.Items.Remove(value);  // 從列表中移除客戶端
                // 更新客戶端列表數(shù)組
                int i = 0;
                foreach (var item in listBox_Client.Items) {
                    clientList[i] = item.ToString();
                }
                label_ClientCount.Text = clientList.Length.ToString();  // 更新客戶端數(shù)量顯示
            }
        }
    }
}

功能解析:

服務(wù)器配置與啟動(dòng):選擇IP地址和端口,啟動(dòng)服務(wù)器監(jiān)聽(tīng)客戶端連接。
客戶端管理:顯示連接的客戶端,支持單個(gè)或所有客戶端發(fā)送消息。
日志記錄:實(shí)時(shí)顯示服務(wù)器日志,記錄連接、消息發(fā)送等操作。
停止服務(wù)器:停止監(jiān)聽(tīng),清空客戶端列表,斷開(kāi)連接。

客戶端實(shí)現(xiàn)

服務(wù)器端實(shí)現(xiàn)完成后,接下來(lái)我們來(lái)實(shí)現(xiàn)TCP客戶端??蛻舳私缑娲a與服務(wù)器端類似,主要使用以下類:

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對(duì)象,用于與服務(wù)器建立TCP連接
        Socket clientSocket;
        // 服務(wù)器的IP地址
        string _IP;
        // 服務(wù)器的端口
        int _Port;
        // 服務(wù)器的IPAddress對(duì)象
        IPAddress _ipAddress;
        // 服務(wù)器的IPEndPoint對(duì)象,包含IP地址和端口
        IPEndPoint _iPEndPoint;
        // 標(biāo)識(shí)連接狀態(tài)
        bool linked = false;
        // 標(biāo)識(shí)是否曾經(jīng)斷開(kāi)連接
        bool unlinked = false;
 
        // 構(gòu)造函數(shù),初始化IP地址和端口
        public TcpIp_Client(string ip, int port) {
            clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); // 創(chuàng)建TCP連接的Socket對(duì)象
            _IP = ip; // 設(shè)置IP地址
            _Port = port; // 設(shè)置端口號(hào)
            _ipAddress = IPAddress.Parse(ip); // 將字符串IP地址解析為IPAddress對(duì)象
            _iPEndPoint = new IPEndPoint(_ipAddress, port); // 創(chuàng)建端點(diǎn)對(duì)象,包含IP地址和端口
        }
 
        // 當(dāng)前連接狀態(tài)
        private bool _Connected;
        public bool Connected {
            get { return _Connected = clientSocket.Connected; } // 返回Socket的連接狀態(tài)
        }
 
        // 連接到服務(wù)器
        public bool ConnectServer(ref string msg) {
            try {
                if (!linked) { // 如果沒(méi)有連接
                    if (unlinked) {
                        // 如果曾經(jīng)斷開(kāi)連接,重新創(chuàng)建Socket
                        clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                    }
                    // 連接到服務(wù)器
                    clientSocket.Connect(_iPEndPoint);
                    if (clientSocket.Connected) { // 如果連接成功
                        linked = true; // 設(shè)置連接狀態(tài)為已連接
                        msg = $"[Info] 服務(wù)器{clientSocket.LocalEndPoint.ToString()}連接成功!"; // 設(shè)置成功消息
                        ReceiveData(); // 調(diào)用方法開(kāi)始接收數(shù)據(jù)
                        return true;
                    } else { // 如果連接失敗
                        msg = $"[Info] 客戶端連接失?。?;
                        return false;
                    }
                } else { // 如果已經(jīng)連接
                    msg = $"[Info] 已連接";
                    return true;
                }
            }
            catch (Exception ex) {
                msg = $"[Err] 連接失??!信息={ex}"; // 連接失敗時(shí)設(shè)置錯(cuò)誤消息
                return false;
            }
        }
 
        // 斷開(kāi)與服務(wù)器的連接
        public bool DisConnectServer(ref string msg) {
            try {
                if (linked) { // 如果已連接
                    linked = false; // 設(shè)置連接狀態(tài)為未連接
                    clientSocket.Disconnect(false); // 斷開(kāi)連接并釋放資源
                    unlinked = true; // 標(biāo)記為已斷開(kāi)
                    msg = $"[Info] 客戶端連接斷開(kāi)";
                    return true;
                } else { // 如果已經(jīng)是斷開(kāi)狀態(tài)
                    msg = $"[Info] 已斷開(kāi)";
                    return true;
                }
            }
            catch (Exception ex) {
                msg = $"[Err] 斷開(kāi)失??!信息={ex}"; // 斷開(kāi)連接失敗時(shí)設(shè)置錯(cuò)誤消息
                return false;
            }
        }
 
        // 向服務(wù)器發(fā)送消息
        public bool SendToServer(string cmd, ref string msg) {
            try {
                if (clientSocket.Connected) { // 如果已連接
                    clientSocket.Send(Encoding.UTF8.GetBytes(cmd)); // 將命令轉(zhuǎn)換為字節(jié)并發(fā)送
                    msg = $"[Info] 發(fā)送{clientSocket.LocalEndPoint.ToString()}信息={cmd}"; // 設(shè)置發(fā)送成功的消息
                    return true;
                } else { // 如果未連接
                    MessageBox.Show(new Form { TopMost = true }, "未連接!", "Info", MessageBoxButtons.OK); // 彈出提示框
                    msg = $"未連接!";
                    return false;
                }
            }
            catch (Exception ex) {
                msg = $"[Err] 發(fā)送信息失?。⌒畔?{ex}"; // 發(fā)送失敗時(shí)設(shè)置錯(cuò)誤消息
                return false;
            }
        }
 
        // 接收來(lái)自服務(wù)器的數(shù)據(jù)
        private void ReceiveData() {
            string str = ""; // 存儲(chǔ)接收到的消息
            Task.Run(() => {
                while (linked) { // 只要連接保持有效,就持續(xù)接收數(shù)據(jù)
                    try {
                        if (clientSocket.Connected) {
                            Thread.Sleep(10); // 為了避免占用過(guò)多的CPU時(shí)間,稍微暫停一下
                        } else {
                            continue; // 如果連接斷開(kāi),繼續(xù)檢查連接狀態(tài)
                        }
                        byte[] data = new byte[1024]; // 緩沖區(qū)用于接收數(shù)據(jù)
                        int length = clientSocket.Receive(data); // 接收服務(wù)器發(fā)送的數(shù)據(jù)
                        string message = Encoding.UTF8.GetString(data, 0, length); // 將接收到的字節(jié)數(shù)據(jù)轉(zhuǎn)換為字符串
                        if (message != "") {
                            str = message; // 存儲(chǔ)接收到的消息
                            Form_Client._ShowClientLog($"[Info] 接收服務(wù)器{clientSocket.LocalEndPoint.ToString()}信息={message}"); // 顯示接收到的消息
                        }
                    }
                    catch (Exception ex) {
                        Form_Client._ShowClientLog($"[Err] 接收服務(wù)器信息失??!信息={ex}"); // 如果接收失敗,顯示錯(cuò)誤信息
                    }
                }
            });
        }
    }
}

代碼解析:

TcpIp_Client類:該類用于實(shí)現(xiàn)一個(gè)TCP客戶端,提供連接服務(wù)器、斷開(kāi)連接、發(fā)送消息、接收消息等功能。
構(gòu)造函數(shù):接受服務(wù)器的IP地址和端口號(hào),初始化Socket并創(chuàng)建連接端點(diǎn)(IPEndPoint)。
ConnectServer方法:建立與服務(wù)器的TCP連接。連接成功后,啟動(dòng)接收數(shù)據(jù)的線程。
DisConnectServer方法:斷開(kāi)與服務(wù)器的連接并釋放相關(guān)資源。
SendToServer方法:將給定的命令發(fā)送到服務(wù)器。
ReceiveData方法:接收來(lái)自服務(wù)器的消息,并在接收到數(shù)據(jù)時(shí)將其打印到客戶端界面或日志中。
關(guān)鍵技術(shù):
Socket編程:使用Socket類進(jìn)行TCP連接的建立、數(shù)據(jù)的發(fā)送和接收。
多線程:ReceiveData方法通過(guò)Task.Run()啟動(dòng)一個(gè)新的線程來(lái)異步接收數(shù)據(jù)。
消息編碼:使用UTF8對(duì)消息進(jìn)行編碼和解碼。

客戶端界面的實(shí)現(xiàn)代碼如下:

using System;
using System.Drawing;
using System.Net;
using System.Net.Sockets;
using System.Windows.Forms;
 
namespace TCPIP_Test
{
    // 定義一個(gè)委托,用于顯示客戶端日志信息
    public delegate void EventShowClientLog(string message);
 
    // 客戶端窗口類
    public partial class Form_Client : Form
    {
        // 聲明委托實(shí)例,用于日志顯示
        public static EventShowClientLog _ShowClientLog = null;
        
        // TCP客戶端實(shí)例
        TcpIp_Client tcpIp_Client;
        
        // 存儲(chǔ)IP地址和端口
        string ip;
        int port;
        string msg;
        
        // 服務(wù)器窗口實(shí)例
        Form_Server form_Server;
 
        // 構(gòu)造函數(shù),初始化組件
        public Form_Client()
        {
            InitializeComponent();
        }
 
        // 窗體加載時(shí)的事件處理
        private void Form1_Load(object sender, EventArgs e)
        {
            // 綁定委托到日志顯示方法
            _ShowClientLog += ShowClientLog;
 
            // 獲取本機(jī)IP地址并填充到下拉框中
            GetIP();
 
            // 默認(rèn)端口5000
            port = int.Parse(textBox_Port.Text = "5000");
        }
 
        // 獲取本機(jī)IP地址的方法
        private void GetIP()
        {
            // 獲取本機(jī)的計(jì)算機(jī)名
            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());
            }
 
            // 默認(rèn)選擇第一個(gè)IP地址
            comboBox_IP.SelectedIndex = 0;
        }
 
        // 連接按鈕點(diǎn)擊事件處理
        private void Button_Connect_Click(object sender, EventArgs e)
        {
            // 判斷是否選擇了IP地址和端口
            if (comboBox_IP.SelectedItem == null || textBox_Port.Text == "")
            {
                MessageBox.Show("請(qǐng)輸入IP和Port!");
                return;
            }
 
            // 獲取選擇的IP和端口
            ip = comboBox_IP.SelectedItem.ToString();
            port = int.Parse(textBox_Port.Text);
 
            // 創(chuàng)建TCP客戶端實(shí)例并嘗試連接到服務(wù)器
            tcpIp_Client = new TcpIp_Client(ip, port);
            _ShowClientLog($"[Info] 客戶端初始化完成");
 
            _ShowClientLog($"[Info] 客戶端開(kāi)始連接...");
 
            // 嘗試連接服務(wù)器
            if (tcpIp_Client.ConnectServer(ref msg))
                button_Connect.BackColor = Color.YellowGreen; // 連接成功后,改變按鈕顏色
            _ShowClientLog($"{msg}");
        }
 
        // 斷開(kāi)連接按鈕點(diǎn)擊事件處理
        private void Button_DisConnect_Click(object sender, EventArgs e)
        {
            _ShowClientLog($"[Info] 客戶端斷開(kāi)連接...");
            
            // 調(diào)用斷開(kāi)連接方法
            tcpIp_Client.DisConnectServer(ref msg);
            
            button_Connect.BackColor = Color.LightGray; // 斷開(kāi)連接后,恢復(fù)按鈕顏色
            _ShowClientLog($"{msg}");
        }
 
        // 發(fā)送一次數(shù)據(jù)按鈕點(diǎn)擊事件處理
        private void Button_SendOnce_Click(object sender, EventArgs e)
        {
            _ShowClientLog($"[Info] 客戶端發(fā)送信息...");
 
            // 獲取輸入框中的信息
            string cmd = textBox_Message.Text;
 
            // 發(fā)送數(shù)據(jù)到服務(wù)器
            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
            {
                // 最大顯示行數(shù)限制
                int maxLine = 100;
 
                // 如果超過(guò)最大行數(shù),刪除最舊的日志行
                if (this.richTextBox_Log.Lines.Length > maxLine)
                {
                    this.richTextBox_Log.Text = richTextBox_Log.Text.Substring(richTextBox_Log.Lines[0].Length + 1);
                }
 
                // 添加日志到文本框,并顯示當(dāng)前時(shí)間戳
                richTextBox_Log.AppendText($"{DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss(fff)")} {message}\r\n");
 
                // 滾動(dòng)到文本框底部
                richTextBox_Log.SelectionStart = richTextBox_Log.Text.Length;
                richTextBox_Log.ScrollToCaret();
            }
        }
 
        // 清除日志按鈕點(diǎn)擊事件處理
        private void Button_Clear_Click(object sender, EventArgs e)
        {
            // 清空日志顯示框
            richTextBox_Log.Text = "";
        }
 
        // 打開(kāi)服務(wù)器窗口按鈕點(diǎn)擊事件處理
        private void button_OpenServer_Click(object sender, EventArgs e)
        {
            // 如果服務(wù)器窗口不存在或已關(guān)閉,則新建一個(gè)服務(wù)器窗口
            if (form_Server == null || form_Server.IsDisposed)
            {
                form_Server = new Form_Server();
                form_Server.Show();
            }
            else
            {
                // 如果服務(wù)器窗口已經(jīng)打開(kāi),確保它位于最前面
                form_Server.TopMost = true;
            }
        }
    }
}

代碼解析:

  • 1.EventShowClientLog 委托   用于線程安全地更新客戶端日志。
  • 2.Form1_Load()   加載時(shí)獲取本機(jī)IP地址并填充IP選擇框,設(shè)置默認(rèn)端口。
  • 3.GetIP()   獲取并顯示本機(jī)所有IPv4地址。
  • 4.Button_Connect_Click()連接服務(wù)器,成功后更新UI顯示連接信息。
  • 5.Button_DisConnect_Click()斷開(kāi)與服務(wù)器的連接,并顯示斷開(kāi)信息。
  • 6.Button_SendOnce_Click()   發(fā)送文本框內(nèi)容到服務(wù)器,并顯示發(fā)送結(jié)果。
  • 7.ShowClientLog()   顯示日志信息,超出限制時(shí)自動(dòng)刪除最舊日志。
  • 8.Button_Clear_Click()  清空日志框內(nèi)容。
  • 9.button_OpenServer_Click()   打開(kāi)或顯示服務(wù)器窗口。

總結(jié)

本文介紹了如何使用C#實(shí)現(xiàn)TCP客戶端和服務(wù)器,并通過(guò)簡(jiǎn)單的代碼示例展示了如何設(shè)置客戶端與服務(wù)器的通信。通過(guò)設(shè)置監(jiān)聽(tīng)端口和獲取客戶端IP地址,您可以在客戶端和服務(wù)器之間建立連接并互相發(fā)送消息。通過(guò)進(jìn)一步的優(yōu)化和擴(kuò)展,您可以實(shí)現(xiàn)更為復(fù)雜的網(wǎng)絡(luò)通信功能。

以上就是C#實(shí)現(xiàn)TCP客戶端和服務(wù)器的基本功能的詳細(xì)內(nèi)容,更多關(guān)于C# TCP客戶端和服務(wù)器的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • C#獲取視頻某一幀的縮略圖的方法

    C#獲取視頻某一幀的縮略圖的方法

    這篇文章主要介紹了C#獲取視頻某一幀的縮略圖的方法,涉及執(zhí)行CMD命令及針對(duì)視頻文件操作的技巧,具有一定的實(shí)用價(jià)值,需要的朋友可以參考下
    2014-11-11
  • C#中LinkedList<T>的存儲(chǔ)結(jié)構(gòu)詳解

    C#中LinkedList<T>的存儲(chǔ)結(jié)構(gòu)詳解

    這篇文章主要介紹了深度解析C#中LinkedList<T>的存儲(chǔ)結(jié)構(gòu),本文將從鏈表的基礎(chǔ)特性、C#中LinkedList的底層實(shí)現(xiàn)邏輯,.NET的不同版本對(duì)于Queue的不同實(shí)現(xiàn)方式的原因分析等幾個(gè)視角進(jìn)行簡(jiǎn)單的解讀,需要的朋友可以參考下
    2023-12-12
  • C++中#include頭文件的示例詳解

    C++中#include頭文件的示例詳解

    在C++中,所有的文件操作,都是以流(stream)的方式進(jìn)行的,fstream也就是文件流file stream。這篇文章主要介紹了C++中#include頭文件,需要的朋友可以參考下
    2020-02-02
  • C#字體池技術(shù)實(shí)現(xiàn)代碼詳解

    C#字體池技術(shù)實(shí)現(xiàn)代碼詳解

    在本篇文章里小編給大家整理的是關(guān)于C#字體池技術(shù)實(shí)現(xiàn)代碼詳解內(nèi)容,有需要的朋友們可以學(xué)習(xí)下。
    2019-11-11
  • 獲取字符串中的漢字拼音首字母

    獲取字符串中的漢字拼音首字母

    獲取字符串中的漢字拼音首字母...
    2007-03-03
  • c#中值類型和引用類型的基礎(chǔ)教程

    c#中值類型和引用類型的基礎(chǔ)教程

    這篇文章主要給大家介紹了關(guān)于c#中值類型和引用類型的基礎(chǔ)教程,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-06-06
  • c#操作xml文件示例

    c#操作xml文件示例

    對(duì)于XML讀寫(xiě)操作,項(xiàng)目中經(jīng)常要用到,之前木有好好總結(jié)過(guò),例如LINQ TO XML也用過(guò),這次無(wú)意發(fā)現(xiàn)XPATH對(duì)于XML的查詢極為方便,索性把XML的操作總結(jié)以便后續(xù)方便使用
    2014-03-03
  • 使用C#實(shí)現(xiàn)讀取PDF中所有文本內(nèi)容

    使用C#實(shí)現(xiàn)讀取PDF中所有文本內(nèi)容

    這篇文章主要為大家詳細(xì)介紹了如何使用C#實(shí)現(xiàn)讀取PDF中所有文本內(nèi)容,文中的示例代碼簡(jiǎn)潔易懂,具有一定的學(xué)習(xí)價(jià)值,有需要的小伙伴可以了解下
    2024-02-02
  • C#byte數(shù)組傳入C操作方法

    C#byte數(shù)組傳入C操作方法

    在本篇內(nèi)容中小編給大家分享了關(guān)于C#byte數(shù)組傳入C操作方法以及相關(guān)知識(shí)點(diǎn),需要的朋友們學(xué)習(xí)下。
    2019-02-02
  • 詳解C#中Helper類的使用

    詳解C#中Helper類的使用

    項(xiàng)目中用戶頻繁訪問(wèn)數(shù)據(jù)庫(kù)會(huì)導(dǎo)致程序的卡頓,甚至堵塞。使用緩存可以有效的降低用戶訪問(wèn)數(shù)據(jù)庫(kù)的頻次,有效的減少并發(fā)的壓力。而helper類對(duì)緩存有了封裝,本文展示了封裝的示例代碼,需要的可以參考一下
    2022-04-04

最新評(píng)論