TCP的调试助手开发笔记

news/2024/11/13 9:16:33/文章来源:https://www.cnblogs.com/StephenYoung/p/18381337

动图:

1 先利用VS自带的socket类来写好TCP_CORE:

类目录如下:

点击查看代码
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows.Forms;namespace WindowsFormsApp1
{//【01】声明委托public delegate void SetListBoxDelegate(string str);class TCP_Core{//【02】创建委托对象public SetListBoxDelegate SetLibxBoxDelegate;private Socket _socket;//定义私有字段存放soket句柄private string IP;private int port;private int receiveCount = 0;private int sendCount = 0;private Boolean isConnected = false;public Boolean IsConnected {get { return isConnected; }set { isConnected = value; }}public int SendCount { get { return sendCount; } }public int RecieveCount {get { return receiveCount; } }public void ResetCount( ) {sendCount = 0;receiveCount = 0;}public Socket Socket{//提供给外部访问的属性get { return _socket; }set { _socket = value; }}private void GetIP_PortByParameter( string par ) {//从参数获取到IP和portstring st = par.Trim( );string[] sArray = st.Split(':');// 一定是单引  IP = sArray[0];port =Convert.ToInt32(sArray[1]);}public int TCP_Open( string par ) {try{Socket client_socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);GetIP_PortByParameter(par);IPAddress ipAdress = IPAddress.Parse(IP);//网络端点:为待请求连接的IP地址和端口号IPEndPoint ipEndpoint = new IPEndPoint(ipAdress, port);//connect()向服务端发出连接请求。客户端不需要bind()绑定ip和端口号,//因为系统会自动生成一个随机的地址(具体应该为本机IP+随机端口号)client_socket.Connect(ipEndpoint);_socket = client_socket;isConnected = true;return 0;}catch (Exception){_socket = null;return -1;}}public int TCP_Send( Socket sk,string sd ) {try{if (isConnected){sk.Send(Encoding.UTF8.GetBytes(sd));sendCount += sd.Length;return 0;}return -1;}catch (Exception){return -1;}}public enum EndChar{None=0,OD=1,OA=2,ODOA=3,}public int TCP_Read( Socket sk, string match, EndChar endChar, int timeout_ms,out string str) {str = "NullYK";if (isConnected){Stopwatch stopwatch = new Stopwatch( );string recvStr = "";byte[] recvBytes = new byte[1024];int bytes;stopwatch.Start( );sk.ReceiveTimeout = timeout_ms;while (true){try{bytes = sk.Receive(recvBytes, recvBytes.Length, SocketFlags.None);//从客户端接受信息recvStr += Encoding.ASCII.GetString(recvBytes, 0, bytes);receiveCount += bytes;if (recvStr.Length != 0 ){SetListBox(recvStr);break;}else if (stopwatch.ElapsedMilliseconds > timeout_ms);//超时退出while;){break;}}catch (Exception){break;}}if (match != null){if (recvStr.Contains(match)){str = recvStr;return 0;}}else//没有match标志就判断结束符;{switch (endChar){case EndChar.None:break;case EndChar.OD:if (recvStr.Contains("\r")){str = recvStr;return 0;}break;case EndChar.OA:if (recvStr.Contains("\n")){str = recvStr;return 0;}break;case EndChar.ODOA:if (recvStr.Contains("\r\n")){str = recvStr;return 0;}break;default:break;}}str = recvStr;}return 0;}private void SetListBox(string dataREC ) {if (dataREC.Length > 0){String  str = $"{CommonTool.GetShortTimeMillisecond( )}←⯁{dataREC}";SetLibxBoxDelegate?.Invoke(str);//【执行委托】}}public int TCP_Close( Socket sk ) {if (isConnected){sk.Close( );sk.Dispose( );}return 0;}}
}
说明下:这个委托的目的,用来在此类中能操作触发对界面控件的刷新。

2 Form1的编程:

点击查看代码
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;namespace WindowsFormsApp1
{public partial class Form1 : Form{Form2 form2=null;readonly TCP_Core TCP_Core1 = new TCP_Core( );readonly CommonTool commonTool = new CommonTool();private  string dataREC = "";const int Intervaltime = 2000;//读取中断时间public Boolean AppIsRun = false;/// <summary>/// 具体刷新Listbox的函数/// </summary>/// <param name="str"></param>/// 定义一个委托(delegate),委托(delegate)可以将参数与方法传递给控件所在的线程,并由控件所在的线程执行,通过Invoke来调用,这样可以完美的解决此类问题。public void RefreshLisBox(String str ) {//【03】委托函数(匿名委托),否则独立线程中试图刷新界面,会报错Action action = ( ) =>{listBox1.Items.Add(str);ScrollListBox(listBox1);toolStripStatusLabelSendcount.Text = TCP_Core1.SendCount.ToString( );toolStripStatusLabelReceive.Text = TCP_Core1.RecieveCount.ToString( );//更新数据到Form2的dataGridView控件上if (form2!=null){form2.newString = str;form2.SetNewString( );}};Invoke(action);}public Form1( ) {InitializeComponent( );//【04】委托绑定TCP_Core1.SetLibxBoxDelegate+= RefreshLisBox;}private void button1_Click( object sender, EventArgs e ) {if (TCP_Core1.TCP_Open(textBox1.Text) == 0){listBox1.Items.Add($"Connect [{textBox1.Text}] Successfully.");btn_send.Enabled = true;btn_close.Enabled = true;this.toolStripStatusLabel0.Text = "Ready";//Task task = new Task(TaskReadLoop);//task.Start( );Thread thread1 = new Thread(TaskReadLoop);//独立线程运行TCP接受函数,此函数内部有 执行委托TCP_Core1.SetLibxBoxDelegate 动作thread1.Start( );timer1.Start( );}else{listBox1.Items.Add("Connect Failed.");this.toolStripStatusLabel0.Text = "Error";timer1.Stop( );}}private void btnSend_Click( object sender, EventArgs e ) {string data = $"{CommonTool.GetShortTimeMillisecond( )}→⟐{textBox2.Text}";listBox1.Items.Add(data);TCP_Core1.TCP_Send(TCP_Core1.Socket,textBox2.Text );ScrollListBox( listBox1);if (form2!=null){form2.newString = data;form2.SetNewString( );}}private void button3_Click( object sender, EventArgs e ) {timer1.Stop( );btn_open.Enabled = true;btn_send.Enabled = false;btn_close.Enabled = false;TCP_Core1.IsConnected = false;TCP_Core1.TCP_Close( TCP_Core1.Socket);}private void Form1_Load( object sender, EventArgs e ) {textBox1.Text = "127.0.0.1:7200";textBox2.Text = "yk test TCP CORE";tableLayoutPanel1.Dock = DockStyle.Fill;timer1.Interval =100;this.Text = "TCP Debug Tool";label1.Text = "Log:";label2.Text = "IP:port";label3.Text = "Send:";listBox1.Items.Clear( );listBox1.GetType( ).GetProperty("DoubleBuffered", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic).SetValue(listBox1, true, null);btn_open.Enabled = true;btn_send.Enabled = false;btn_close.Enabled = false;this.toolStripStatusLabel0.Text = "Please Open a connection";AppIsRun = true;}private void ScrollListBox(ListBox listBox ) {//在添加新记录前,先计算滚动条是否在底部,从而决定添加后是否自动滚动。
// 既可以在需要时实现自动滚动,又不会在频繁添加记录时干扰用户对滚动条的控制。int ctl_rows =Convert.ToInt32( listBox1.Height / this.listBox1.ItemHeight);if (listBox1.Items.Count > (ctl_rows - 1)){listBox1.TopIndex = listBox1.Items.Count - ctl_rows+3;}else {listBox1.TopIndex = 0;}}public void TaskReadLoop( ) {while (AppIsRun){TCP_Core1.TCP_Read(TCP_Core1.Socket, null, TCP_Core.EndChar.ODOA, Intervaltime, out dataREC);}}private void timer1_Tick( object sender, EventArgs e ) {//在timer里面来接受数据会造成界面卡顿。}private void btn_clear_Click( object sender, EventArgs e ) {listBox1.Items.Clear( );if (form2!=null){form2.CleardataGridView( );}TCP_Core1.ResetCount( );}private void checkBox1_CheckedChanged( object sender, EventArgs e ) {commonTool.Enable= checkBox1.Checked;}private void button1_Click_1( object sender, EventArgs e ) {}private void groupBox1_Enter( object sender, EventArgs e ) {}private void openTestWindowToolStripMenuItem_Click( object sender, EventArgs e ) {if (form2==null){form2 = new Form2( );form2.NewDataIn += form2.OnNewString;//[A4]挂接委托form2.Show( );}else{form2.Visible = true;}}private void tb_time_TextChanged( object sender, EventArgs e ) {}private void Form1_FormClosing( object sender, FormClosingEventArgs e ) {if (MessageBox.Show("Are you sure to exit?","Information",MessageBoxButtons.YesNo,MessageBoxIcon.Question)==DialogResult.Yes){TCP_Core1.IsConnected = false;TCP_Core1.TCP_Close(TCP_Core1.Socket);AppIsRun = false;e.Cancel = false;}else{e.Cancel = true;}}}
}

这里有几点重要的要说明:
(1)我们定义了一个一直循环接受的方法:
public void TaskReadLoop( ) { while (AppIsRun) { TCP_Core1.TCP_Read(TCP_Core1.Socket, null, TCP_Core.EndChar.ODOA, Intervaltime, out dataREC); } }
AppIsRun是存储软件知否在运行的字段;
(2)如果我们把上述TaskReadLoop( )直接在界面线程中运行的话,那么UI就会卡死;
所以我们得单独开辟个线程来运行:
`
private void button1_Click( object sender, EventArgs e ) {
if (TCP_Core1.TCP_Open(textBox1.Text) == 0)
{
listBox1.Items.Add($"Connect [{textBox1.Text}] Successfully.");
btn_send.Enabled = true;
btn_close.Enabled = true;
this.toolStripStatusLabel0.Text = "Ready";

            //Task task = new Task(TaskReadLoop);//task.Start( );Thread thread1 = new Thread(TaskReadLoop);//独立线程运行TCP接受函数,此函数内部有 执行委托TCP_Core1.SetLibxBoxDelegate 动作thread1.Start( );

`

(3)委托 TCP_Core1.SetLibxBoxDelegate+= RefreshLisBox的挂接的方法,RefreshLisBox这里要使用匿名委托,否则会报错:不可以跨线程访问Listbox控件;
`
public void RefreshLisBox(String str ) {//【03】委托函数(匿名委托),否则独立线程中试图刷新界面,会报错
Action action = ( ) =>
{
listBox1.Items.Add(str);
ScrollListBox(listBox1);

            toolStripStatusLabelSendcount.Text = TCP_Core1.SendCount.ToString( );toolStripStatusLabelReceive.Text = TCP_Core1.RecieveCount.ToString( );//更新数据到Form2的dataGridView控件上if (form2!=null){form2.newString = str;form2.SetNewString( );}};Invoke(action);}

`

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/787614.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Why Transformers Need Adam: A Hessian Perspective

目录概符号说明所有参数的 Hessian 矩阵Block-wise Hessian代码Zhang Y., Chen C., Ding T., Li Z., Sun R. and Luo Z. Why transformers need adam: a hessian perspective. arXiv preprint, 2024.概 本文从 Hessian 矩阵的角度回答为什么 Adam 相较于其它方法, 比如 SGD 在 …

VL24 边沿检测

这个就是需要对a 进行打一拍last_a<=a; 需要理解的点是打一拍的last_a是落后a一个时钟周期的,也就是对当前时刻使用a时候,此时的last_a是a的上一时刻的值。`timescale 1ns/1ns module edge_detect(input clk,input rst_n,input a,output reg rise,output reg down ); reg …

RE入门第三天---TEA算法

OK,老规矩,先复习一下昨天的内容 ..... 几分钟就复习了,直接开干今天的内容 先找大佬的wp 来源: TEA系列加密解密 | Gruges Blog (g2uge.github.io) 逆向算法之TEA算法 - Sk2rw - 博客园 (cnblogs.com) 一.TEA加密解密简介 在密码学中,微型加密算法(Tiny Encryption Algo…

vue3 控制el-dialog 双向绑定显示隐藏

父组件<Contact v-model:isView="isView" /> 子组件<template><div><el-dialogwidth="400"title="微信二维码":model-value="props.isView"@closed="handleClose"><div class="dialog-div…

Typora使用PicGo自动上传图片

Gitee配置PicGo图床 简介 由于我们使用Markdown写博客时需要上传一些图片,以便于理解。但是md文件不像Word文件一样能承载图片传输,所以我们使用md文件进行多设备协作,或者传输发给其他人的时候,图片的传输成了很大的问题。一般情况下我们可以搭建一个文件服务器,但是这样…

【网络安全C10-2024.8.24】-docker、数据库、Web应用程序安全

1、在docker中分别以后台方式和交互方式启动centos,对比启动后的容器状态,实现退出容器也能保持其运行状态。docker run -d --name centos7-001 centos docker run -it --name centos7-002 centos /bin/bash docker run -d -t --name centos7-003 centos2、在docker并部署DVW…

网络安全C10-2024.8.24-docker、数据库、Web应用程序安全

docker run -d --name centos7-001 centos docker run -it --name centos7-002 centos /bin/bash docker run -d -t --name centos7-003 centos docker pull sagikazarmark/dvwa docker run -d -p 8082:80 -p 33060:3306 --name dvwa sagikazarmark/dvwa

CodeForces VP Record

CodeForces Round 767 (contest 1628) A Meximum Array 考虑二分。二分的时候计算区间 $ \text{mex} $,参考 P4137 Rmq Problem / mex,主席树即可。时间复杂度 $ \Theta(n \log^2 n) $,无需卡常。 B Peculiar Movie Preferences 首先,对于一个合法的回文串,容易证明首尾两…

数据库监控运维方案,保障高性能及高可用

通过构建对关键指标的监控,实现对数据库性能和资源的实时追踪,识别并解决影响的数据库问题,保障数据库的高性能及高可用性,更全面地支持业务及应用的稳定、持续运行。 随着企业对数据高可用的需求日益增长,对于数据库的实时监控和故障自动恢复方案愈发重要。作为关…

VL22 根据状态转移图实现时序电路

和上一题的第一段完全相同,第二段只是根据状态转移有部分改变,本体使用三段式状态机来写,第三段写法和上一题不一样。`timescale 1ns/1nsmodule seq_circuit(input C ,input clk ,input rst_n,output wire Y );…