C#基于MVC模式实现TCP三次握手,附带简易日志管理模块
C#基于MVC模式实现TCP三次握手
- 1 Model
- 1.1 ServerModel
- 1.2 ClientModel
- 1.3 配置参数模块
- 1.4 日志管理模块
- 1.4.1 数据结构
- 1.4.1 日志管理工具类
- 1.4.1 日志视图展示
- 1.4.1.1 UcLogManage.cs
- 1.4.1.2 UcLogManage.Designer.cs
- 2 视图(View)
- 2.1 ViewServer
- 2.1.1 ViewServer.cs
- 2.1.1 ViewServer.Designer.cs
- 2.2 ViewClient
- 2.2.1 ViewClient.cs
- 2.2.1 ViewClient.Designer.cs
- 3 控制器(Controller)
- 3.1 ServerController
- 3.2 ClientController
- 4 工具类
友情资料链接: TCP三次握手
1 Model
1.1 ServerModel
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;namespace DemoThreeTimesHandshake.Model
{public class ServerModel{private TcpListener _server;private bool _isRunning;public Action<TcpClient, Config.MyEnum, string> EventAddLog;~ServerModel(){CloseServer();}public void OpenServer(){//创建一个 TCP 监听器,监听本地 IP 地址和端口_server = new TcpListener(IPAddress.Any, Config.Server.Port);// 启动服务器_server.Start();_isRunning = true;new Task(() =>{while (_isRunning){Thread.Sleep(1000);ListeningClient();}}).Start();}public void CloseServer(){if (_isRunning){// 停止服务器_server.Stop();}}/// <summary>/// 监听接入客户端,三次握手/// </summary>private void ListeningClient(){TcpClient client = null;try{//等待客户端连接client = _server.AcceptTcpClient();AddLog(client, Config.MyEnum.State, "已连接");//获取网络流NetworkStream stream = client.GetStream();//第一次握手:接收客户端的 SYN 包byte[] buffer = new byte[1024];int bytesRead = stream.Read(buffer, 0, buffer.Length);string synMessage = Encoding.ASCII.GetString(buffer, 0, bytesRead);AddLog(client, Config.MyEnum.Receive, synMessage);//第二次握手:发送 SYN+ACK 包string synAckMessage = "SYN+ACK";byte[] synAckBuffer = Encoding.ASCII.GetBytes(synAckMessage);stream.Write(synAckBuffer, 0, synAckBuffer.Length);AddLog(client, Config.MyEnum.Send, synAckMessage);//第三次握手:接收客户端的 ACK 包bytesRead = stream.Read(buffer, 0, buffer.Length);string ackMessage = Encoding.ASCII.GetString(buffer, 0, bytesRead);AddLog(client, Config.MyEnum.Receive, ackMessage);AddLog(client, Config.MyEnum.State, "三次握手完成,连接建立成功。");//为(每个)客户端创建线程处理通信new Task(() => HandleClient(client)).Start();}catch (Exception ex){AddLog(client, Config.MyEnum.State, $"发生错误: {ex.Message}");}}private void HandleClient(TcpClient client){try{NetworkStream stream = client.GetStream();byte[] buffer = new byte[1024];while (_isRunning){// 异步读取客户端发送的消息int bytesRead = stream.Read(buffer, 0, buffer.Length);if (bytesRead == 0){// 客户端断开连接break;}string message = Encoding.ASCII.GetString(buffer, 0, bytesRead);AddLog(client, Config.MyEnum.Receive, message);// 将接收到消息回发给客户端string synMessage = message;byte[] synBuffer = System.Text.Encoding.ASCII.GetBytes(synMessage);stream.Write(synBuffer, 0, synBuffer.Length);AddLog(client, Config.MyEnum.Send, synMessage);}}catch (Exception ex){AddLog(client, Config.MyEnum.State, ex.Message);}}private void AddLog(TcpClient client, Config.MyEnum type, string description){EventAddLog?.Invoke(client, type, description);}}
}
1.2 ClientModel
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;namespace DemoThreeTimesHandshake.Model
{public class ClientModel{public Action<TcpClient, Config.MyEnum, string> EventAddLog;private TcpClient _client;private bool _isRunning;~ClientModel(){CloseServer();}public void OpenServer(){StartClient();}public void CloseServer(){if (_isRunning){_client.Close();}}private void StartClient(){try{// 创建一个 TCP 客户端,连接到服务器的 IP 地址和端口 8888_client = new TcpClient();_client.Connect(IPAddress.Parse(Config.Server.IP), Config.Server.Port);AddMsg(Config.MyEnum.State, "已连接到服务器。");_isRunning = true;// 获取网络流NetworkStream stream = _client.GetStream();// 第一次握手:发送 SYN 包string synMessage = "SYN";byte[] synBuffer = System.Text.Encoding.ASCII.GetBytes(synMessage);stream.Write(synBuffer, 0, synBuffer.Length);AddMsg(Config.MyEnum.Send, $"发送 SYN 包: {synMessage}");// 第二次握手:接收服务器的 SYN+ACK 包byte[] buffer = new byte[1024];int bytesRead = stream.Read(buffer, 0, buffer.Length);string synAckMessage = System.Text.Encoding.ASCII.GetString(buffer, 0, bytesRead);AddMsg(Config.MyEnum.Receive, $"收到服务器的 SYN+ACK 包: {synAckMessage}");// 第三次握手:发送 ACK 包string ackMessage = "ACK";byte[] ackBuffer = System.Text.Encoding.ASCII.GetBytes(ackMessage);stream.Write(ackBuffer, 0, ackBuffer.Length);AddMsg(Config.MyEnum.Send, $"发送 ACK 包: {ackMessage}");AddMsg(Config.MyEnum.State, "三次握手完成,连接建立成功。");// 客户端创建一个新的线程来处理通信new Task(HandleClient).Start();}catch (Exception ex){AddMsg(Config.MyEnum.State, $"异常: {ex.Message}");}}private void HandleClient(){try{NetworkStream stream = _client.GetStream();byte[] buffer = new byte[1024];while (_isRunning){// 异步读取客户端发送的消息int bytesRead = stream.Read(buffer, 0, buffer.Length);if (bytesRead == 0) break;string message = Encoding.ASCII.GetString(buffer, 0, bytesRead);AddMsg(Config.MyEnum.Receive, message);}}catch (Exception ex){AddMsg(Config.MyEnum.State, $"异常: {ex.Message}");}}private void AddMsg(Config.MyEnum type, string message){EventAddLog?.Invoke(_client, type, message);}public void Send(string textAsc){if (_client == null) return;// 获取网络流NetworkStream stream = _client.GetStream();byte[] synBuffer = Encoding.ASCII.GetBytes(textAsc);stream.Write(synBuffer, 0, synBuffer.Length);AddMsg(Config.MyEnum.Send, $"发送包长度: {synBuffer.Length}");}public void GetClientInfo(out string ip, out int port){try{IPEndPoint clientEndPoint = (IPEndPoint)_client.Client.RemoteEndPoint;ip = clientEndPoint.Address.ToString();port = clientEndPoint.Port;}catch (Exception ex){ip = "";port = 0;}}}
}
1.3 配置参数模块
using System;
using System.ComponentModel;namespace DemoThreeTimesHandshake.Model
{public class Config{public class Server{public const string IP = "127.0.0.1";public const int Port = 1234;}[Serializable]public enum MyEnum{[Description("状态信息")]State,[Description("发送")]Send,[Description("接受")]Receive}}
}
1.4 日志管理模块
1.4.1 数据结构
using System;
using System.ComponentModel;namespace DemoThreeTimesHandshake.Model.LogDS
{[Serializable]public class Log{[Description("时间")]public string Time { get; set; }[Description("IP")]public string IP { get; set; }[Description("类型")]public Config.MyEnum Type { get; set; }[Description("端口")]public int Port { get; set; }[Description("内容")]public string Description { get; set; }public Log(string time, string ip, int port, Config.MyEnum type, string description){Time = time;IP = ip;Port = port;Type = type;Description = description;}}
}
1.4.1 日志管理工具类
using System;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Windows.Forms;
using DemoThreeTimesHandshake.Tool;namespace DemoThreeTimesHandshake.Model.LogDS
{public class LogUtil{public enum ELog { First, Previous, Next, Last, Clear, Save }/// <summary>/// 记录日志信息/// </summary>private List<Log> _list = new List<Log>();/// <summary>/// 当前页索引/// </summary>private int _curPageIndex;private int _pageCount = 12;/// <summary>/// 日志元素数/// </summary>public int LogCount => _list.Count;/// <summary>/// 每页展示的数据量/// </summary>public int PageCount{get => _pageCount;set{_curPageIndex = 0;_pageCount = value;}}/// <summary>/// 总页数/// </summary>private int PageSum{get{int count = LogCount / PageCount;if (LogCount % PageCount > 0) count += 1;return count;}}/// <summary>/// 获取当前页(List)/// </summary>public List<Log> GetCurPage{get{var list = new List<Log>();for (int i = 0, index = _curPageIndex * PageCount; i < PageCount && index >= 0 && index < LogCount; i++, index++){list.Add(_list[index].DeepCopy());}return list;}}/// <summary>/// 获取当前页(DataTable)/// </summary>public DataTable GetCurPageTable{get{DataTable table = new DataTable();table.Columns.Add("序号");table.Columns.Add(nameof(Log.Time));table.Columns.Add(nameof(Log.IP));table.Columns.Add(nameof(Log.Type));table.Columns.Add(nameof(Log.Port));table.Columns.Add(nameof(Log.Description));for (int i = 0, index = _curPageIndex * PageCount; i < PageCount && index >= 0 && index < LogCount; i++, index++){var t = _list[index];table.Rows.Add(index + 1, t.Time, t.IP, t.Type, t.Port, t.Description);}return table;}}/// <summary>/// 当前页页码信息/// </summary>public string PageInfo => $"第{_curPageIndex + 1}页,共{PageSum}页";/// <summary>/// 添加日志/// </summary>/// <param name="ip"></param>/// <param name="port"></param>/// <param name="type"></param>/// <param name="description"></param>public void AddLog(string ip, int port, Config.MyEnum type, string description){var time = DateTime.Now.ToString("F");_list.Add(new Log(time, ip, port, type, description));_curPageIndex = PageSum - 1;}public void LogManage(ELog type){switch (type){case ELog.First:_curPageIndex = 0;break;case ELog.Previous:if (PageSum > 0){_curPageIndex -= 1;if (_curPageIndex < 0) _curPageIndex = PageSum - 1;}break;case ELog.Next:if (PageSum > 0) _curPageIndex = (_curPageIndex + 1) % PageSum;break;case ELog.Last:_curPageIndex = PageSum - 1;break;case ELog.Clear:_list.Clear();_curPageIndex = 0;break;case ELog.Save:SaveLog();break;}if (PageSum <= 0) _curPageIndex = 0;}public void SaveLog(){try{SaveFileDialog dialog = new SaveFileDialog();dialog.FileName = $"日志_{DateTime.Now:F}";dialog.Filter = "|*.csv";if (dialog.ShowDialog() != DialogResult.OK) return;string split = ",";StringBuilder builder = new StringBuilder();builder.Append("序号" + split);builder.Append(nameof(Log.Time) + split);builder.Append(nameof(Log.IP) + split);builder.Append(nameof(Log.Type) + split);builder.Append(nameof(Log.Port) + split);builder.Append(nameof(Log.Description));builder.AppendLine();int num = 1;foreach (var log in _list){builder.Append(num++ + split);builder.Append(log.Time + split);builder.Append(log.IP + split);builder.Append(log.Type + split);builder.Append(log.Port + split);builder.Append(log.Description);builder.AppendLine();}File.WriteAllText(dialog.FileName, builder.ToString());Process.Start(dialog.FileName);}catch (Exception ex){MessageBox.Show("保存日志文件失败:" + ex.Message);}}}
}
1.4.1 日志视图展示

1.4.1.1 UcLogManage.cs
using System;
using System.Linq;
using System.Windows.Forms;
using DemoThreeTimesHandshake.Tool;namespace DemoThreeTimesHandshake.Model.LogDS
{public partial class UcLogManage : UserControl{private LogUtil _logUtil;private string[] _hideColumnName;public UcLogManage(LogUtil logUtil, params string[] hideColumnName){InitializeComponent();_hideColumnName = hideColumnName;_logUtil = logUtil;menu_FirstPage.Click += (o, args) => ClickManage(LogUtil.ELog.First);menu_PreviousPage.Click += (o, args) => ClickManage(LogUtil.ELog.Previous);menu_NextPage.Click += (o, args) => ClickManage(LogUtil.ELog.Next);menu_LastPage.Click += (o, args) => ClickManage(LogUtil.ELog.Last);menu_ClearLog.Click += (o, args) => ClickManage(LogUtil.ELog.Clear);menu_SaveLog.Click += (o, args) => ClickManage(LogUtil.ELog.Save);com_PageCount.Text = logUtil.PageCount.ToString();com_PageCount.TextChanged += (o, args) =>{if (!int.TryParse(com_PageCount.Text, out var count)) return;_logUtil.PageCount = count;RefreshDataGridView();};menu_PageInfo.Text = string.Empty;}private void ClickManage(LogUtil.ELog type){_logUtil.LogManage(type);RefreshDataGridView();}private void RefreshDataGridView(){if (InvokeRequired){Invoke(new EventHandler(delegate { RefreshDataGridView(); }));return;}menu_PageInfo.Text = _logUtil.PageInfo;if (true){dataGridView1.DataSource = _logUtil.GetCurPageTable;}else{dataGridView1.DataSource = _logUtil.GetCurPage.ToList();}dataGridView1.Columns["序号"].FillWeight = 1;SetDataGridViewStyle(nameof(Log.Time), 2);SetDataGridViewStyle(nameof(Log.IP), 1);SetDataGridViewStyle(nameof(Log.Port), 1);SetDataGridViewStyle(nameof(Log.Type), 1);SetDataGridViewStyle(nameof(Log.Description), 5);for (int i = 0; i < _hideColumnName.Length; i++){dataGridView1.Columns[_hideColumnName[i]].Visible = false;}Utility.SetDgvStyle(dataGridView1);}private void SetDataGridViewStyle(string propertyName, int fillWeight){string headerText = Utility.GetPropertyDescription<Log>(propertyName);dataGridView1.Columns[propertyName].HeaderText = headerText;dataGridView1.Columns[propertyName].FillWeight = fillWeight;}public void DisplayResult(){RefreshDataGridView();}}
}
1.4.1.2 UcLogManage.Designer.cs
namespace DemoThreeTimesHandshake.Model.LogDS
{partial class UcLogManage{/// <summary> /// 必需的设计器变量。/// </summary>private System.ComponentModel.IContainer components = null;/// <summary> /// 清理所有正在使用的资源。/// </summary>/// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param>protected override void Dispose(bool disposing){if (disposing && (components != null)){components.Dispose();}base.Dispose(disposing);}#region 组件设计器生成的代码/// <summary> /// 设计器支持所需的方法 - 不要修改/// 使用代码编辑器修改此方法的内容。/// </summary>private void InitializeComponent(){this.menuStrip1 = new System.Windows.Forms.MenuStrip();this.menu_FirstPage = new System.Windows.Forms.ToolStripMenuItem();this.menu_PreviousPage = new System.Windows.Forms.ToolStripMenuItem();this.menu_NextPage = new System.Windows.Forms.ToolStripMenuItem();this.menu_LastPage = new System.Windows.Forms.ToolStripMenuItem();this.menu_ClearLog = new System.Windows.Forms.ToolStripMenuItem();this.menu_PageInfo = new System.Windows.Forms.ToolStripMenuItem();this.menu_LogManage = new System.Windows.Forms.ToolStripMenuItem();this.dataGridView1 = new System.Windows.Forms.DataGridView();this.menu_SaveLog = new System.Windows.Forms.ToolStripMenuItem();this.每页显示日志条数ToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();this.com_PageCount = new System.Windows.Forms.ToolStripComboBox();this.menuStrip1.SuspendLayout();((System.ComponentModel.ISupportInitialize)(this.dataGridView1)).BeginInit();this.SuspendLayout();// // menuStrip1// this.menuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {this.menu_LogManage,this.menu_FirstPage,this.menu_PreviousPage,this.menu_NextPage,this.menu_LastPage,this.menu_ClearLog,this.menu_PageInfo});this.menuStrip1.Location = new System.Drawing.Point(0, 0);this.menuStrip1.Name = "menuStrip1";this.menuStrip1.Size = new System.Drawing.Size(703, 25);this.menuStrip1.TabIndex = 9;this.menuStrip1.Text = "menuStrip1";// // menu_FirstPage// this.menu_FirstPage.Name = "menu_FirstPage";this.menu_FirstPage.Size = new System.Drawing.Size(44, 21);this.menu_FirstPage.Text = "首页";// // menu_PreviousPage// this.menu_PreviousPage.Name = "menu_PreviousPage";this.menu_PreviousPage.Size = new System.Drawing.Size(56, 21);this.menu_PreviousPage.Text = "上一页";// // menu_NextPage// this.menu_NextPage.Name = "menu_NextPage";this.menu_NextPage.Size = new System.Drawing.Size(56, 21);this.menu_NextPage.Text = "下一页";// // menu_LastPage// this.menu_LastPage.Name = "menu_LastPage";this.menu_LastPage.Size = new System.Drawing.Size(44, 21);this.menu_LastPage.Text = "尾页";// // menu_ClearLog// this.menu_ClearLog.Name = "menu_ClearLog";this.menu_ClearLog.Size = new System.Drawing.Size(68, 21);this.menu_ClearLog.Text = "清空日志";// // menu_PageInfo// this.menu_PageInfo.Name = "menu_PageInfo";this.menu_PageInfo.Padding = new System.Windows.Forms.Padding(100, 0, 4, 0);this.menu_PageInfo.Size = new System.Drawing.Size(164, 21);this.menu_PageInfo.Text = "页码信息";// // menu_LogManage// this.menu_LogManage.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {this.menu_SaveLog,this.每页显示日志条数ToolStripMenuItem});this.menu_LogManage.Name = "menu_LogManage";this.menu_LogManage.Padding = new System.Windows.Forms.Padding(50, 0, 4, 0);this.menu_LogManage.Size = new System.Drawing.Size(114, 21);this.menu_LogManage.Text = "管理日志";// // dataGridView1// this.dataGridView1.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;this.dataGridView1.Dock = System.Windows.Forms.DockStyle.Fill;this.dataGridView1.Location = new System.Drawing.Point(0, 25);this.dataGridView1.Name = "dataGridView1";this.dataGridView1.RowTemplate.Height = 23;this.dataGridView1.Size = new System.Drawing.Size(703, 304);this.dataGridView1.TabIndex = 10;// // menu_SaveLog// this.menu_SaveLog.Name = "menu_SaveLog";this.menu_SaveLog.Size = new System.Drawing.Size(180, 22);this.menu_SaveLog.Text = "保存日志";// // 每页显示日志条数ToolStripMenuItem// this.每页显示日志条数ToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {this.com_PageCount});this.每页显示日志条数ToolStripMenuItem.Name = "每页显示日志条数ToolStripMenuItem";this.每页显示日志条数ToolStripMenuItem.Size = new System.Drawing.Size(180, 22);this.每页显示日志条数ToolStripMenuItem.Text = "每页显示日志条数";// // com_PageCount// this.com_PageCount.Items.AddRange(new object[] {"5","10","15","20","25","30"});this.com_PageCount.Name = "com_PageCount";this.com_PageCount.Size = new System.Drawing.Size(121, 25);// // UcLogManage// this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;this.Controls.Add(this.dataGridView1);this.Controls.Add(this.menuStrip1);this.Name = "UcLogManage";this.Size = new System.Drawing.Size(703, 329);this.menuStrip1.ResumeLayout(false);this.menuStrip1.PerformLayout();((System.ComponentModel.ISupportInitialize)(this.dataGridView1)).EndInit();this.ResumeLayout(false);this.PerformLayout();}#endregionprivate System.Windows.Forms.MenuStrip menuStrip1;private System.Windows.Forms.ToolStripMenuItem menu_PreviousPage;private System.Windows.Forms.ToolStripMenuItem menu_NextPage;private System.Windows.Forms.DataGridView dataGridView1;private System.Windows.Forms.ToolStripMenuItem menu_ClearLog;private System.Windows.Forms.ToolStripMenuItem menu_PageInfo;private System.Windows.Forms.ToolStripMenuItem menu_FirstPage;private System.Windows.Forms.ToolStripMenuItem menu_LastPage;private System.Windows.Forms.ToolStripMenuItem menu_LogManage;private System.Windows.Forms.ToolStripMenuItem menu_SaveLog;private System.Windows.Forms.ToolStripMenuItem 每页显示日志条数ToolStripMenuItem;private System.Windows.Forms.ToolStripComboBox com_PageCount;}
}
2 视图(View)
2.1 ViewServer
2.1.1 ViewServer.cs
using System;
using System.Windows.Forms;
using DemoThreeTimesHandshake.Controller;
using DemoThreeTimesHandshake.Model;
using DemoThreeTimesHandshake.Model.LogDS;namespace DemoThreeTimesHandshake.View
{public partial class ViewServer : Form{public readonly LogUtil Log = new LogUtil();public Action EventStartServer;public Action EventDisplayLog;public ViewServer(){InitializeComponent();this.WindowState = FormWindowState.Maximized;var ucLogManage = new UcLogManage(Log) { Dock = DockStyle.Fill };EventDisplayLog += ucLogManage.DisplayResult;panel1.Controls.Add(ucLogManage);_ = new ServerController(this, new ServerModel());}private void menu_OpenClientForm_Click(object sender, EventArgs e) => new ViewClient().Show();private void menu_StartServer_Click(object sender, EventArgs e){EventStartServer?.Invoke();}public void DisplayResult(){menu_StartServer.Enabled = false;this.Text = "服务器,状态:已启动,等待客户端连接...";}}
}
2.1.1 ViewServer.Designer.cs
namespace DemoThreeTimesHandshake.View
{partial class ViewServer{/// <summary>/// Required designer variable./// </summary>private System.ComponentModel.IContainer components = null;/// <summary>/// Clean up any resources being used./// </summary>/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>protected override void Dispose(bool disposing){if (disposing && (components != null)){components.Dispose();}base.Dispose(disposing);}#region Windows Form Designer generated code/// <summary>/// Required method for Designer support - do not modify/// the contents of this method with the code editor./// </summary>private void InitializeComponent(){this.menuStrip1 = new System.Windows.Forms.MenuStrip();this.menu_StartServer = new System.Windows.Forms.ToolStripMenuItem();this.menu_OpenClientForm = new System.Windows.Forms.ToolStripMenuItem();this.panel1 = new System.Windows.Forms.Panel();this.menuStrip1.SuspendLayout();this.SuspendLayout();// // menuStrip1// this.menuStrip1.Font = new System.Drawing.Font("Microsoft YaHei UI", 12F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(134)));this.menuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {this.menu_StartServer,this.menu_OpenClientForm});this.menuStrip1.Location = new System.Drawing.Point(0, 0);this.menuStrip1.Name = "menuStrip1";this.menuStrip1.Size = new System.Drawing.Size(824, 30);this.menuStrip1.TabIndex = 10;this.menuStrip1.Text = "menuStrip1";// // menu_StartServer// this.menu_StartServer.Name = "menu_StartServer";this.menu_StartServer.Size = new System.Drawing.Size(102, 26);this.menu_StartServer.Text = "开启服务器";this.menu_StartServer.Click += new System.EventHandler(this.menu_StartServer_Click);// // menu_OpenClientForm// this.menu_OpenClientForm.Name = "menu_OpenClientForm";this.menu_OpenClientForm.Size = new System.Drawing.Size(134, 26);this.menu_OpenClientForm.Text = "打开客户端窗口";this.menu_OpenClientForm.Click += new System.EventHandler(this.menu_OpenClientForm_Click);// // panel1// this.panel1.Dock = System.Windows.Forms.DockStyle.Fill;this.panel1.Location = new System.Drawing.Point(0, 30);this.panel1.Name = "panel1";this.panel1.Size = new System.Drawing.Size(824, 402);this.panel1.TabIndex = 11;// // ViewServer// this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;this.ClientSize = new System.Drawing.Size(824, 432);this.Controls.Add(this.panel1);this.Controls.Add(this.menuStrip1);this.Name = "ViewServer";this.Text = "服务器,状态:未开启";this.menuStrip1.ResumeLayout(false);this.menuStrip1.PerformLayout();this.ResumeLayout(false);this.PerformLayout();}#endregionprivate System.Windows.Forms.MenuStrip menuStrip1;private System.Windows.Forms.ToolStripMenuItem menu_StartServer;private System.Windows.Forms.ToolStripMenuItem menu_OpenClientForm;private System.Windows.Forms.Panel panel1;}
}
2.2 ViewClient
2.2.1 ViewClient.cs
using System;
using System.Windows.Forms;
using DemoThreeTimesHandshake.Controller;
using DemoThreeTimesHandshake.Model;
using DemoThreeTimesHandshake.Model.LogDS;namespace DemoThreeTimesHandshake.View
{public partial class ViewClient : Form{public EventHandler<ClientEventManage> EventManage;public Action EventDisplayLog;public readonly LogUtil LogUtil = new LogUtil();public ViewClient(){InitializeComponent();this.TopMost = true;_ = new ClientController(this, new ClientModel());var ucLogManage = new UcLogManage(LogUtil, nameof(Log.IP), nameof(Log.Port)) { Dock = DockStyle.Fill };EventDisplayLog += ucLogManage.DisplayResult;panel1.Controls.Add(ucLogManage);}private void menu_StartClient_Click(object sender, EventArgs e){EventManage?.Invoke(this, new ClientEventManage(EEventType.Open));}private void button1_Click(object sender, EventArgs e){EventManage?.Invoke(this, new ClientEventManage(EEventType.Send, textBox1.Text));}public void DisplayResult(string ip, int port){if (InvokeRequired){Invoke(new EventHandler(delegate { DisplayResult(ip, port); }));}else{menu_StartClient.Enabled = false;this.Text = $"客户端,状态:已连接,IP = {ip},端口 = {port}";}}}public enum EEventType { Open, Send }public class ClientEventManage : EventArgs{public EEventType Type { get; set; }public string Message { get; set; }public ClientEventManage(EEventType type, string message){Type = type;Message = message;}public ClientEventManage(EEventType type){Type = type;}}
}
2.2.1 ViewClient.Designer.cs
namespace DemoThreeTimesHandshake.View
{partial class ViewClient{/// <summary>/// Required designer variable./// </summary>private System.ComponentModel.IContainer components = null;/// <summary>/// Clean up any resources being used./// </summary>/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>protected override void Dispose(bool disposing){if (disposing && (components != null)){components.Dispose();}base.Dispose(disposing);}#region Windows Form Designer generated code/// <summary>/// Required method for Designer support - do not modify/// the contents of this method with the code editor./// </summary>private void InitializeComponent(){this.button1 = new System.Windows.Forms.Button();this.menuStrip1 = new System.Windows.Forms.MenuStrip();this.menu_StartClient = new System.Windows.Forms.ToolStripMenuItem();this.textBox1 = new System.Windows.Forms.TextBox();this.panel1 = new System.Windows.Forms.Panel();this.menuStrip1.SuspendLayout();this.SuspendLayout();// // button1// this.button1.Location = new System.Drawing.Point(210, 40);this.button1.Name = "button1";this.button1.Size = new System.Drawing.Size(78, 21);this.button1.TabIndex = 5;this.button1.Text = "发送";this.button1.UseVisualStyleBackColor = true;this.button1.Click += new System.EventHandler(this.button1_Click);// // menuStrip1// this.menuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {this.menu_StartClient});this.menuStrip1.Location = new System.Drawing.Point(0, 0);this.menuStrip1.Name = "menuStrip1";this.menuStrip1.Size = new System.Drawing.Size(793, 25);this.menuStrip1.TabIndex = 6;this.menuStrip1.Text = "menuStrip1";// // menu_StartClient// this.menu_StartClient.Name = "menu_StartClient";this.menu_StartClient.Size = new System.Drawing.Size(80, 21);this.menu_StartClient.Text = "启动客户端";this.menu_StartClient.Click += new System.EventHandler(this.menu_StartClient_Click);// // textBox1// this.textBox1.Location = new System.Drawing.Point(35, 40);this.textBox1.Name = "textBox1";this.textBox1.Size = new System.Drawing.Size(148, 21);this.textBox1.TabIndex = 7;// // panel1// this.panel1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right)));this.panel1.Location = new System.Drawing.Point(35, 99);this.panel1.Name = "panel1";this.panel1.Size = new System.Drawing.Size(731, 365);this.panel1.TabIndex = 8;// // ViewClient// this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;this.ClientSize = new System.Drawing.Size(793, 494);this.Controls.Add(this.panel1);this.Controls.Add(this.textBox1);this.Controls.Add(this.button1);this.Controls.Add(this.menuStrip1);this.MainMenuStrip = this.menuStrip1;this.Name = "ViewClient";this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;this.Text = "客户端,状态:未连接";this.menuStrip1.ResumeLayout(false);this.menuStrip1.PerformLayout();this.ResumeLayout(false);this.PerformLayout();}#endregionprivate System.Windows.Forms.Button button1;private System.Windows.Forms.MenuStrip menuStrip1;private System.Windows.Forms.ToolStripMenuItem menu_StartClient;private System.Windows.Forms.TextBox textBox1;private System.Windows.Forms.Panel panel1;}
}
3 控制器(Controller)
3.1 ServerController
using System.Net.Sockets;
using DemoThreeTimesHandshake.Model;
using DemoThreeTimesHandshake.Tool;
using DemoThreeTimesHandshake.View;namespace DemoThreeTimesHandshake.Controller
{public class ServerController{private readonly ViewServer _view;private readonly ServerModel _model;public ServerController(ViewServer view, ServerModel model){_view = view;_model = model;_view.EventStartServer += OnEventStartServer;_model.EventAddLog += OnAddLog;}private void OnEventStartServer(){_model.OpenServer();_view.DisplayResult();}private void OnAddLog(TcpClient client, Config.MyEnum type, string description){Utility.GetClientInfo(client, out string ip, out int port);_view.Log.AddLog(ip, port, type, description);_view.EventDisplayLog?.Invoke();}}
}
3.2 ClientController
using System.Net.Sockets;
using System.Threading.Tasks;
using DemoThreeTimesHandshake.Model;
using DemoThreeTimesHandshake.View;namespace DemoThreeTimesHandshake.Controller
{public class ClientController{private readonly ViewClient _view;private readonly ClientModel _model;public ClientController(ViewClient view, ClientModel model){_view = view;_model = model;_view.EventManage += OnEventStartClient;_model.EventAddLog += OnAddLog;}private void OnEventStartClient(object obj, ClientEventManage e){switch (e.Type){case EEventType.Open:new Task(() =>{_model.OpenServer();_model.GetClientInfo(out string ip, out int port);_view.DisplayResult(ip, port);}).Start();break;case EEventType.Send:_model.Send(e.Message);break;}}private void OnAddLog(TcpClient client, Config.MyEnum type, string description){_model.GetClientInfo(out string ip, out int port);_view.LogUtil.AddLog(ip, port, type, description);_view.EventDisplayLog?.Invoke();}}
}
4 工具类
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Reflection;
using System.Runtime.Serialization.Formatters.Binary;
using System.Windows.Forms;namespace DemoThreeTimesHandshake.Tool
{public static class Utility{private static readonly Dictionary<string, string> descriptionCache = new Dictionary<string, string>();/// <summary>/// 获取属性/枚举成员的Description/// </summary>public static string GetPropertyDescription<T>(string propertyName){string cacheKey = $"{typeof(T).FullName}.{propertyName}";if (descriptionCache.TryGetValue(cacheKey, out string description)){return description;}Type type = typeof(T);PropertyInfo property = type.GetProperty(propertyName);if (property != null){DescriptionAttribute descriptionAttribute = property.GetCustomAttribute<DescriptionAttribute>();if (descriptionAttribute != null){description = descriptionAttribute.Description;descriptionCache[cacheKey] = description;return description;}}FieldInfo field = type.GetField(propertyName);if (field != null){DescriptionAttribute descriptionAttribute = field.GetCustomAttribute<DescriptionAttribute>();if (descriptionAttribute != null){description = descriptionAttribute.Description;descriptionCache[cacheKey] = description;return description;}}return null;}/// <summary>/// 设置DataGridView样式/// </summary>public static void SetDgvStyle(DataGridView table){try{table.ClearSelection();//int index = dgvStandard.CurrentCell.RowIndex;//获取选中行table.MultiSelect = false; //不可多选table.AllowUserToAddRows = false; //设置不显示添加行table.AllowUserToDeleteRows = false; //设置不允许删除行table.AllowUserToResizeColumns = false; //设置列不可调整table.ColumnHeadersDefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter; //列名居中table.AllowUserToResizeRows = false; //设置行不可调整table.RowHeadersVisible = false; //设置表头不显示行标题table.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill; //列填充控件显示区域table.CausesValidation = false; //焦点table.ColumnHeadersBorderStyle = DataGridViewHeaderBorderStyle.Single; //边框样式table.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.AutoSize; //列高调整table.RowsDefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter; //单元格内容居中table.ReadOnly = false; //只读设置table.RowHeadersWidth = 4; //列宽设置(按照权重设置时需要先添加列)table.RowHeadersWidthSizeMode = DataGridViewRowHeadersWidthSizeMode.AutoSizeToAllHeaders; //设置列表头不可调整table.RowTemplate.Height = 28; //设置行高table.ScrollBars = ScrollBars.Vertical; //显示垂直滚动条table.TabStop = false; //设置无Tab焦点table.VirtualMode = true; //设置可进行数据管理//table.Rows[lastTableHeadRow].Frozen = true;//冻结指定行for (var i = 0; i < table.Columns.Count; i++){//table.Columns[i].SortMode = DataGridViewColumnSortMode.NotSortable; //禁止点击列名排序//table.Columns[i].FillWeight = 1; //按权重分配列宽//设置图像列的布局//var column = table.Columns[i] as DataGridViewImageColumn;//if (column != null)//{// column.ImageLayout = DataGridViewImageCellLayout.Zoom;//}}}catch (Exception){// ignored}}/// <summary>/// 获取客户端信息/// </summary>public static void GetClientInfo(TcpClient client, out string ip, out int port){try{IPEndPoint clientEndPoint = (IPEndPoint)client.Client.RemoteEndPoint;ip = clientEndPoint.Address.ToString();port = clientEndPoint.Port;}catch{ip = "";port = 0;}}/// <summary>/// 深度拷贝/// </summary>public static T DeepCopy<T>(this T obj){if (!obj.GetType().IsSerializable){return default(T);}using (MemoryStream ms = new MemoryStream()){BinaryFormatter formatter = new BinaryFormatter();formatter.Serialize(ms, obj);ms.Position = 0;return (T)formatter.Deserialize(ms);}}/// <summary>/// 获取时间戳/// </summary>/// <returns></returns>public static long GetTimeLong(){long unixTimestampMs = (long)(DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalMilliseconds;return unixTimestampMs;}}
}
相关文章:
C#基于MVC模式实现TCP三次握手,附带简易日志管理模块
C#基于MVC模式实现TCP三次握手 1 Model1.1 ServerModel1.2 ClientModel1.3 配置参数模块1.4 日志管理模块1.4.1 数据结构1.4.1 日志管理工具类1.4.1 日志视图展示1.4.1.1 UcLogManage.cs1.4.1.2 UcLogManage.Designer.cs 2 视图(View)2.1 ViewServer2.1.…...
6、linux c 线程 -下
1. 线程的取消 意义 随时终止一个线程的执行。 函数 #include <pthread.h> int pthread_cancel(pthread_t thread); pthread_t thread:要取消的线程 ID。 返回值 成功时返回 0。 失败时返回非零错误码。 注意 线程的取消需要有取消点,…...
分布式算法:Paxos Raft 两种共识算法
1. Paxos算法 Paxos算法是 Leslie Lamport(莱斯利兰伯特)在 1990 年提出的一种分布式系统共识算法。也是第一个被证明完备的共识算法(前提是不存在恶意节点)。 1.1 简介 Paxos算法是第一个被证明完备的分布式系统共识算法。共识…...
什么是数据库监控
数据库监控是一个综合的过程,涉及观察、分析和优化组织内数据库的性能、运行状况和可用性。通过持续跟踪查询执行时间、CPU使用率、内存消耗和存储I/O等指标,数据库监控使管理员能够主动识别和解决潜在问题。这种对数据库操作的实时可见性对于确保应用程…...
Java学习总结-泛型
什么是泛型? 定义 类、接口、方法时,同时声明了一个或多个类型变量(如:<E>),称为泛型类、泛型接口、泛型方法、他们统称为泛型。public class ArrayList<E>{ }。 有什么作用呢…...
基于深度学习的相位调制算法步骤
1.构建网络结构 2.制作数据集 3.训练网络 4.引入评价指标 5.迭代优化 总结 通过以上步骤,可以实现基于深度学习的相位调制算法: 使用 U-Net 构建神经网络。 生成数据集并训练网络。 使用训练好的网络预测相位分布。 通过相关系数 γ 评估调制效果&…...
curl使用报错error LNK2001: 无法解析的外部符号 __imp__CertCloseStore@8
使用curl静态库libcurl_a.lib 时报错,内容如下: 1>libcurl_a.lib(openssl.obj) : error LNK2001: 无法解析的外部符号 __imp__CertCloseStore8 1>libcrypto.lib(libcrypto-lib-e_capi.obj) : error LNK2001: 无法解析的外部符号 __imp__CertClose…...
Go语言的基础类型
一基础数据类型 一、布尔型(Bool) 定义:表示逻辑真 / 假,仅有两个值:true 和 false内存占用:1 字节使用场景:条件判断、逻辑运算 二、数值型(Numeric) 1. 整数类型&…...
动力保护板测试仪:电池安全的坚实守护者
在新能源技术日新月异的今天,电池作为各类电子设备的心脏,其安全性与可靠性成为了行业内外关注的焦点。而动力保护板,作为电池系统中的重要组成部分,承担着精准调控电池充放电、防止电池过充、过放、短路等危险情况的重任。然而&a…...
Lineageos 22.1(Android 15)制定应用强制横屏
一、前言 有时候需要系统的某个应用强制衡平显示,不管他是如何配置的。我们只需要简单的拿到top的Task下面的ActivityRecord,并判断包名来强制实现。 二、调整wms com.android.server.wm.DisplayRotation /*** Given an orientation constant, return…...
【Python】【PyQt5】设置事件绑定(例为按钮点击显示提示框)
前言 上篇文章我们讲了如何创作一个UI界面,并将其使用代码显示出来,这篇文章我们来讲讲事件的绑定 为增加文章趣味性,此篇文章我们将以点击窗口中的按钮来后并显示一个提示框 修改上次代码(优化) 上篇文章我所讲的要…...
node-ddk, electron组件, 自定义本地文件协议,打开本地文件
node-ddk 文件协议 https://blog.csdn.net/eli960/article/details/146207062 也可以下载demo直接演示 http://linuxmail.cn/go#node-ddk 安全 考虑到安全, 本系统禁止使用 file:/// 在主窗口, 自定义文件协议,可以多个 import main, { NODEDDK } from "node-ddk/m…...
SpringBoot-3-JWT令牌
目录 引入 引入依赖 拦截器 创建工具类 创建拦截器的包及拦截器 注册拦截器 修改一下登录成功后token的代码 测试 引入 试想一下,以上我们的访问都是直接访问对应的接口。比如说用户登录的时候就访问登录的接口。 那么如果有人他不访问你的登录接口&#…...
ChatGPT vs DeepSeek vs Copilot vs Claude:谁将问鼎AI王座?
李升伟 整理 2025年的人工智能领域创新涌动,ChatGPT、DeepSeek、Copilot和Claude四大模型各领风骚。这些AI系统各具特色,分别专注于编程、创意写作、技术推理和AI伦理等不同领域。本文将深入解析这些AI模型的功能特性及其优势领域。 核心AI模型解析 C…...
git使用经验(一)
git使用经验(一) 我之前已经下载了别人的代码,我想在此基础上进行修改,并移动到自己的私有仓库,方便上传到自己的私有仓库自己进行版本控制 git clone下来别人的代码,删除有关git的隐藏文件 进入到自己的…...
文件上传的小点总结
1.文件上传漏洞 服务器端脚本语言对上传文件没有严格的验证和过滤,就可以给攻击者上传恶意脚本文件的可能。 文件上传检测绕过: 简单思路:(这里以前端上传图片为例) ①开启phpstudy,启动apache即可&…...
基于WebRtc,GB28181,Rtsp/Rtmp,SIP,JT1078,H265/WEB融合视频会议接入方案
智能融合视频会议系统方案—多协议、多场景、全兼容的一站式视频协作平台 OvMeet,LiveMeet针对用户核心痛点实现功能与用户价值 ,Web平台实现MCU多协议,H265/H264等不同编码监控,直播,会议,调度资源统一融合在一套界…...
Python常用库全解析:从数据处理到机器学习
适合人群:Python初学者 | 数据分析师 | 机器学习爱好者 目录 一、NumPy:科学计算的核心库 1. 核心功能 2. 应用领域 3. 常用方法示例 二、Pandas:数据分析的瑞士军刀 1. 核心功能 2. 应用领域 3. 常用方法示例 三、Matplotlib&#…...
基于漂浮式海上风电场系统的浮式风力发电机matlab仿真
目录 1.课题概述 2.系统仿真结果 3.核心程序与模型 4.系统原理简介 5.完整工程文件 1.课题概述 基于漂浮式海上风电场系统的浮式风力发电机matlab仿真,通过MATLAB数值仿真对浮式风力发电机的性能做模拟与仿真。 2.系统仿真结果 3.核心程序与模型 版本&#x…...
深入探索ArkUI中的@LocalBuilder装饰器:构建高效可维护的UI组件
在ArkUI框架中,组件化开发是提升代码复用性和维护性的关键手段。随着项目复杂度的增加,开发者常常面临如何在保持组件封装性的同时,灵活处理组件内部逻辑的问题。传统的Builder装饰器虽然提供了强大的自定义构建能力,但在某些场景…...
【QA】外观模式在Qt中有哪些应用?
1. QWidget及其布局管理系统 外观模式体现 QWidget 是Qt中所有用户界面对象的基类,而布局管理系统(如 QVBoxLayout、QHBoxLayout、QGridLayout 等)就像是一个外观类。客户端代码(开发者编写的界面代码)通常不需要直接…...
在ASP.NET Core中使用NLog:配置与性能优化指南
在ASP.NET Core中使用NLog:配置与性能优化指南 在ASP.NET Core中使用NLog:配置与性能优化指南1. 安装NLog包2. 基础配置2.1 创建nlog.config文件2.2 程序启动配置 3. 在代码中使用日志4. 性能优化配置4.1 异步日志处理4.2 自动清理旧日志4.3 缓冲写入优化…...
yaffs
YAFFS(Yet Another Flash File System)是专为NAND闪存设计的日志结构文件系统,其核心原理围绕NAND闪存的特性优化数据管理。以下是其关键原理的详细说明: 1. NAND闪存适配 写入限制:NAND闪存需按页写入(通…...
快速查询手机是否处于联网状态?
手机是否处于联网状态对于我们日常生活中的沟通、工作和娱乐都至关重要。有时候我们需要迅速了解一个手机号码的在网状态,例如是正常使用、停机、不在网等。而要实现这一功能,我们可以利用挖数据平台提供的在线查询工具,通过API接口来查询手机…...
使用 .NET Core 的本地 DeepSeek-R1
使用 .NET 在我的 MacBook Pro 上与当地 LLM 聊天的历程。 如今,只需使用浏览器即可轻松使用 ChatGPT 或其他 genAI。作为开发人员,我们可以通过直接集成 OpenAI API 等来做更复杂的事情。如果我们想在自己的机器上运行 LLM,只是为了找人聊天…...
LeetCode 206 Reverse Linked List 反转链表 Java
举例1: 输入: [1,2,3,4,5], 输出: [5,4,3,2,1]. 举例2: 输入: [] 输出:[] 思路:方法有三种,分别是递归,栈,双指针,本篇使用栈&a…...
SQL Server查询计划操作符(7.3)——查询计划相关操作符(11)
7.3. 查询计划相关操作符 98)Table Scan:该操作符从查询计划参数列确定的表中获取所有数据行。如果其参数列中出现WHERE:()谓词,则只返回满足该谓词的数据行。该操作符为逻辑操作符和物理操作符。该操作符具体如图7.3-98节点1所示。 图 7.3-…...
xy轴不等比缩放问题——AUTOCAD c#二次开发
在 AutoCAD .net api里,部分实体,像文字、属性、插入块等,是不支持非等比缩放的。 如需对AutoCAD中图形进行xyz方向不等比缩放,则需进行额外的函数封装。 选择图元,指定缩放基准点,scaleX 0.5, scaleY …...
【原创首发】开源基于AT32 SIP/VOIP电话
前言 本次为了反馈各位粉丝的关注,特此分享 AT32_VOIP 工程,此功能其实跟我之前发过的《STM32F429的VOIP功能》是一样的,只是用了AT32F437。 其实那个工程是一个比较Demo中的Demo,很多功能和硬件依赖性太大了。后面项目中发现AT…...
本地部署 LangManus
本地部署 LangManus 0. 引言1. 部署 LangManus2. 部署 LangManus Web UI 0. 引言 LangManus 是一个社区驱动的 AI 自动化框架,它建立在开源社区的卓越工作基础之上。我们的目标是将语言模型与专业工具(如网络搜索、爬虫和 Python 代码执行)相…...
