c#验证udp协议通信及实现端口扫描器


一、控制台实现udp通信

本次采用c/s模式创建应用实现通信。
1)创建项目
在VS2019中选择创建新项目,选择.net framework控制台应用,设置项目名并选择项目存储位置,然后点击创建,即可建立一个基本的控制台应用。
2)编写服务端
获取udp连接代码如下

            UdpClient client = new UdpClient();
            //设置目标ip地址,127.0.0.1为本地回环,即自己发给自己
            IPAddress remoteIP = IPAddress.Parse("127.0.0.1");
            //设置端口号
            int remotePort = 11000;  
            IPEndPoint remotePoint = new IPEndPoint(remoteIP, remotePort);

发送数据使用client.Send(sendData, sendData.Length, remotePoint);,在发送之前需要使用Encoding.Default.GetBytes把将发送的数据转为16进制编码格式。
完整main函数代码如下:

            //提示信息
            Console.WriteLine("按下任意按键开始发送...");
            Console.ReadKey();

            int m;

            //做好链接准备
            UdpClient client = new UdpClient();  //实例一个端口
            IPAddress remoteIP = IPAddress.Parse("127.0.0.1");  //假设发送给这个IP
            int remotePort = 11000;  //设置端口号
            IPEndPoint remotePoint = new IPEndPoint(remoteIP, remotePort);  //实例化一个远程端点 

            for (int i = 0; i < 50; i++)
            {
                //要发送的数据:第n行:hello cqjtu!重交物联2019级
                string sendString = null;
                sendString += "第";
                m = i + 1;
                sendString += m.ToString();
                sendString += "行:hello cqjtu!重交物联2019级";

                //定义发送的字节数组
                //将字符串转化为字节并存储到字节数组中
                byte[] sendData = null;
                sendData = Encoding.Default.GetBytes(sendString);

                client.Send(sendData, sendData.Length, remotePoint);//将数据发送到远程端点 
            }
            client.Close();//关闭连接

            //提示信息
            Console.WriteLine("");
            Console.WriteLine("数据发送成功,按任意键退出...");
            System.Console.ReadKey();

3)编写客户端
同样创建一个新项目,main函数内代码如下

            int result;
            string str = "第50行:hello cqjtu!重交物联2019级";
            UdpClient client = new UdpClient(11000);
            string receiveString = null;
            byte[] receiveData = null;
            //实例化一个远程端点,IP和端口可以随意指定,等调用client.Receive(ref remotePoint)时会将该端点改成真正发送端端点 
            IPEndPoint remotePoint = new IPEndPoint(IPAddress.Any, 0);
            Console.WriteLine("正在准备接收数据...");
            while (true)
            {
                receiveData = client.Receive(ref remotePoint);//接收数据 
                receiveString = Encoding.UTF8.GetString(receiveData);
                Console.WriteLine(receiveString);
                result = String.Compare(receiveString, str);
                if (result == 0)
                {
                    break;
                }
            }
            client.Close();//关闭连接
            Console.WriteLine("");
            Console.WriteLine("数据接收完毕,按任意键退出...");
            System.Console.ReadKey();

4)测试
同时运行这两个应用,进行测试,测试结果如下:
请添加图片描述

二、图像界面实现发送信息

1).创建项目
选择下图所示项目模板,创建项目。打开后即进入界面设计。
在这里插入图片描述
在其中从工具栏中加入一个按钮,一个文本框和一个富文本框,按自己想法放置。
2)双击添加进的按钮。进入代码编辑界面。按钮点击代码如下

        private void button1_Click(object sender, EventArgs e)
        {
            UdpClient client = new UdpClient();
            IPAddress remoteIP = IPAddress.Parse("127.0.0.1");
            int remotePort = 11000;  //设置端口号
            IPEndPoint remotePoint = new IPEndPoint(remoteIP, remotePort);

            string text = textBox1.Text;
            byte[] sendData = null;
            sendData = Encoding.Default.GetBytes(text);

            client.Send(sendData, sendData.Length, remotePoint);//将数据发送到远程端点 
            client.Close();//关闭连接

            //提示信息
            
            richTextBox1.Text+="数据已发送\n";
        }

3)测试
测试结果如下:
请添加图片描述

3.端口扫描器实现

1)创建项目,设计界面
按前面所说创建桌面应用项目,界面设计如下:
在这里插入图片描述

2)输入端口信息获取及进度条相关配置
在代码中创建一个新函数。将端口相对应文本输入框的textchanged事件绑定为该函数。在class中创建两个私有成员变量,保存相关信息。代码如下

        private void TextBox3_TextChanged(object sender, EventArgs e)
        {
            try {
                progressBar1.Value = start; 
            }
            catch
            {
                progressBar1.Minimum = 0;
                progressBar1.Maximum = 65535;
                progressBar1.Value = 0;
            }

            string text= "-1" ;
            TextBox temp= (TextBox)sender;
            if(temp.Text.Length !=0)
                text = temp.Text;
            if (temp == textBox3 && !text.Equals("-1"))
            {
                label4.Text = text;
                start = Int32.Parse(text);
            }
            else if (temp == textBox2 && !text.Equals("-1"))
            { 
                label5.Text = text;
                end = Int32.Parse(text);
                progressBar1.Minimum = start;
                progressBar1.Maximum = end;
                if(end < start || end >65536 || start < 0 || start > 65536)
                {
                    richTextBox1.Text += "\n输入有误,请重新输入!\n";
                    textBox3.Clear();
                    textBox2.Clear();
                    label4.Text = "";
                    label5.Text = "";
                    start = 0;
                    end = 0;
                }
            }
        }

2.单线程扫描实现

双击单线程对应按钮,进入代码编辑界面。相关代码如下:

        private void Clicked(object sender, MouseEventArgs e)
        {
            progressBar1.Value = start;
            if (textBox1.Text == null)
            {
                richTextBox1.Text += "\n请输入ip地址\n";
                return;
            }
            else
                addr = textBox1.Text;
            TcpClient obj = null;
            richTextBox1.Text += "\n开始扫描!\n";
            while (progressBar1.Value != progressBar1.Maximum) {
                try {
                    obj = new TcpClient(addr, progressBar1.Value);
                } catch
                {

                }
                finally
                {
                    progressBar1.Value += 1;
                }
                richTextBox1.Text += "\n扫描结束\n";
            }
        }

在实际使用时,如果使用单线程,等待时间将会较长,同时,扫描时也不能对该窗口进行任何操作,否则将会卡死,使用体验较差。

多线程扫描实现

先在class中定义两个私有线程变量。然后双击多线程对应按钮,进入代码编辑界面。
相关代码如下

        private void button2_Click(object sender, EventArgs e)
        {
            progressBar1.Value = start;
            if (textBox1.Text == null)
            {
                richTextBox1.Text += "\n请输入ip地址\n";
                return;
            }
            else
                addr = textBox1.Text;
            richTextBox1.Text = "端口扫描器\n";
            richTextBox1.Text += "\n开始扫描!\n";
            Thread startscan = new Thread(new ThreadStart(scan));
            startscan.Start();
        }

scan:

        public void scan()
        {
            bool flag = false;
            for(int i = start; i <= end; i++)
            {
                port = i;
                scans = new Thread(new ThreadStart(truescan));
                scans.Start();
                System.Threading.Thread.Sleep(100);
            }
            while(!flag){
                for(int i = start; i <= end; i++)
                {
                    if (!ischecked[i])
                    {
                        flag = false;
                        System.Threading.Thread.Sleep(100);
                        break;
                    }
                    flag = true;
                }
            }
            End temp = new End(scanEnd);
            this.Invoke(temp);
        }

truescan:

        public void truescan()
        {
            int temp = port;
            Thread now = scans;
            TcpClient obj = null;
            try
            {
                obj = new TcpClient(addr, temp);

                setText temp1 = new setText(portOpen);
                this.Invoke(temp1,temp);
            }
            catch
            {
                setText temp1 = new setText(portNotOpen);
                this.Invoke(temp1,temp);
            }
            finally
            {
                ischecked[temp] = true;
                End temp1 = new End(gogo);
                if(temp!=start)
                    this.Invoke(temp1);
            }
        }

在c#中,如果需要在某一线程中操作非本线程创建的控件时,需要使用委托来实现相关操作。本次定义使用的相关定义代码如下

        public delegate void setText(int t);
        public delegate void End();

在使用前,将这些通过new 与相关处理函数绑定,再在子线程中通过invoke调用,传递参数。本次定义的处理函数如下:

       public void portOpen(int temp)
        {
            richTextBox1.Text += "\n端口" + temp + "开放\n";
        }
        public void portNotOpen(int temp)
        {
            richTextBox1.Text += "\n端口" + temp + "未开放\n";
        }
        public void scanEnd()
        {
            richTextBox1.Text += "扫描结束";
        }
        public void gogo()
        {
            progressBar1.Value++;
        }

3)测试
测试结果如下
请添加图片描述

4.udp数据帧分析

使用前面的发送软件发送信息,通过抓包软件得到数据包如下
在这里插入图片描述
如果发送到其他电脑,第二行应与以下图片相似。
在这里插入图片描述
第一行为目标地址,第二行为源地址,第三行为类型,即采用的协议,第四行为校验码。
第三行为ip包。如下所示
在这里插入图片描述
包含以下内容

  1. Version(版本号):分为 IPv4 和 IPv6 这里用的 IPv4 ,所以值为 4 ,1 个字节
  2. Header length(ip报头长度):32位字的报头长度
  3. TOS(级别):服务类型描述数据报将如何被处理,比如优先发送等,大多数都是默认为 0
  4. Total Length(总长度):包括报头和数据的数据包长度
  5. identifier(标识):唯一的 IP 数据包值
  6. Flags(标志):说明是否有数据被分段,由于本次每个包的数据很小,没有被分段,所以这里数值为 0 。
  7. Fragmentation Offset(分段偏移):如果数据包在装人帧时太大,则需要进行分段和重组,这里没有分段,所以偏移量为 0
  8. TTL(存活期):存活期是在数据包产生时建立在其内部的一个设置,如果这个数据包在这个TTL到期时仍没有到达它要去的目的地,那么它将被丢弃,这个设置将防止IP包在寻找目的地的时候在网络中不断循环,每经过一个路由器,它的值就减一,这里它的值为 64 ,也就是 64 个生存期
  9. Protocol(协议):上层协议的端口( TCP 是端口 6;UDP 是端口 17) ,同样也支持网络层协议,如ARP和ICMP,这里值为 17 ,也就是 UDP 协议
  10. Header Checksum(校验码):只针对报头的循环冗余校验(CRC)
  11. 目的地址及源地址
    最后一行为数据,里面是发送的数据字节,如果发送的数据含有中文,通过utf-8编码格式解码后即可看到完整数据。

参与评论 您还未登录,请先 登录 后发表或查看评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:1024 设计师:我叫白小胖 返回首页

打赏作者

weixin_45747542

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值