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();
}
#endregion
private 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();
}
#endregion
private 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();
}
#endregion
private 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;
}
}
}