欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

XX的学习日记(网络通信编程)三——C#编程和网络编程入门

程序员文章站 2022-06-29 21:52:47
...

一、安装Wireshark 抓包软件

Wireshark官网下载地址链接

二、用C#编写一个命令行/控制台hello world程序

目标: 实现如下功能:

  1. 在屏幕上连续输出50行“hello cqjtu!重交物联2018级”;
  2. 打开一个网络UDP 套接字,向室友电脑发送这50行消息;
  3. 抓取上述程序发送的网络包,对数据帧结构进行分析。

1. 简单输出

(1)创建C#控制台程序
XX的学习日记(网络通信编程)三——C#编程和网络编程入门
XX的学习日记(网络通信编程)三——C#编程和网络编程入门
(2) 编写代码

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            for (int i = 0; i < 50; i++)
                Console.WriteLine("{0}:hello cqjtu!重交物联2018级",(i+1));
                Console.ReadLine();
        }
    }
}

(3)编译运行
XX的学习日记(网络通信编程)三——C#编程和网络编程入门

2. 使用网络UDP输出

使用C/S服务模式,所以需要一个客户端Client和一个服务端Server
(1)客户端程序:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;

namespace Client
{
    class Program
    {
        static void Main(string[] args)
        {
            //提示信息
            Console.WriteLine("按任意键发送");
            Console.ReadKey();
            
            int m;

            //做好链接准备
            UdpClient client = new UdpClient();  //实例一个端口
            IPAddress remoteIP = IPAddress.Parse("192.168.8.101");  //假设发送给这个IP
            int remotePort = 11000;  //设置端口号
            IPEndPoint remotePoint = new IPEndPoint(remoteIP, remotePort);  //实例化一个远程端点 
			Console.WriteLine("from XX");
            for(int i = 0; i < 50; i++)
            {
                //要发送的数据:第n行:hello cqjtu!重交物联2018级
                string sendString = null;
                sendString += "第";
                m = i+1;
                sendString += m.ToString();
                sendString += "行:hello cqjtu!重交物联2018级";

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

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

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

(2)服务端程序

using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Net.Sockets;

namespace UDP
{
    class Program
    {
        static void Main(string[] args)
        {
            int recv;
            byte[] data = new byte[1024];

            //得到本机IP,设置TCP端口号         
            IPEndPoint ip = new IPEndPoint(IPAddress.Any, 8001);
            Socket server = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);

            //绑定网络地址
            server.Bind(ip);

            Console.WriteLine("这是服务端, 主机名为: {0}", Dns.GetHostName());

            //等待客户机连接
            Console.WriteLine("等待客户端发送数据...");

            //得到客户机IP
            IPEndPoint sender = new IPEndPoint(IPAddress.Any, 0);
            EndPoint Remote = (EndPoint)(sender);
            recv = server.ReceiveFrom(data, ref Remote);
            Console.WriteLine("消息来自于: {0}: ", Remote.ToString());
            Console.WriteLine(Encoding.Default.GetString(data, 0, recv));

            //客户机连接成功后,发送信息
            string welcome = "连接成功 ";

            //字符串与字节数组相互转换
            data = Encoding.Default.GetBytes(welcome);

            //发送信息 
            server.SendTo(data, Remote);
            
            while (true)
            {
                data = new byte[1024];
                //发送接收信息
                //从客户机接受消息
                recv = server.ReceiveFrom(data, ref Remote);
                //将字节流信息转换为字符串
                string Data = Encoding.Default.GetString(data, 0, recv);
                //将字符串输出到屏幕上
                Console.WriteLine(Data);
                // Console.WriteLine(Encoding.Default.GetString(data, 0, recv));
                /*
                //定义字符串input
                string input;
                //读取屏幕上的字符串
                input = Console.ReadLine();
                if (input == "exit")
                    break;
                //将input发送至客户机
                server.SendTo(Encoding.Default.GetBytes(input),Remote);*/
            }
            server.Close();
        }
    }
}

(3)客户端发送结果显示:
XX的学习日记(网络通信编程)三——C#编程和网络编程入门
(4)服务端接收结果显示:
XX的学习日记(网络通信编程)三——C#编程和网络编程入门

三、用VS2019的C#编写一个简单的Form窗口程序

目标:

  1. 编辑包含一个文本框 textEdit和一个发送按钮button,运行程序后,可以在文本框里输入文字,如“hello cqjtu!重交物联2018级”,点击button,将这些文字发送给室友电脑,采用UDP套接字;
  2. 抓取上述程序发送的网络包,对数据帧结构进行分析。

1. 创建一个Windows窗体应用

XX的学习日记(网络通信编程)三——C#编程和网络编程入门
XX的学习日记(网络通信编程)三——C#编程和网络编程入门

2. 编辑窗体

(1)拖取一个Button控件和两个TextBox控件
XX的学习日记(网络通信编程)三——C#编程和网络编程入门
(2)设置消息显示控件属性
添加垂直滚动条:XX的学习日记(网络通信编程)三——C#编程和网络编程入门
设置边界样式:XX的学习日记(网络通信编程)三——C#编程和网络编程入门
设置消息显示界面的 TextBox 为不可编辑:
XX的学习日记(网络通信编程)三——C#编程和网络编程入门
(3)设置Button控件属性
选中Button控件后:
XX的学习日记(网络通信编程)三——C#编程和网络编程入门
(4)设置窗体属性
选中窗体后:

XX的学习日记(网络通信编程)三——C#编程和网络编程入门

3. 编辑代码

双击窗体转到代码
复制下列代码,覆盖原有的所有代码:

using System;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
using System.Threading;


namespace frame_udp_server
{
    public partial class Form1 : Form
    {
        private UdpClient receiveUdpClient;//接收用
        private UdpClient sendUdpClient;//发送用
        private const int port = 8080;//和本机绑定的端口号
        IPAddress ip = IPAddress.Parse("192.168.8.102");//客户端ip
        IPAddress remoteip = IPAddress.Parse("192.168.8.101");//服务端ip
        public Form1()
        {
            InitializeComponent();
            CheckForIllegalCrossThreadCalls = false;
            //获取本机可用IP地址
            /*IPAddress[] ips = Dns.GetHostAddresses(Dns.GetHostName());
            foreach (IPAddress ipa in ips)
            {
                if (ipa.AddressFamily == AddressFamily.InterNetwork)
                {
                    ip = ipa;
                    break;
                }
            }

            //为了在同一台机器调试,此IP也作为默认远程IP
            remoteip = ip;*/
            //IPAddress remoteip = IPAddress.Parse("192.168.43.208");

        }

        private void Form1_Load(object sender, EventArgs e)
        {
            //创建一个线程接收远程主机发来的信息
            Thread myThread = new Thread(ReceiveData);
            myThread.IsBackground = true;
            myThread.Start();
        }

        //接收数据
        private void ReceiveData()
        {
            IPEndPoint local = new IPEndPoint(ip, port);
            receiveUdpClient = new UdpClient(local);
            IPEndPoint remote = new IPEndPoint(IPAddress.Any, 0);
            while (true)
            {
                try
                {
                    //关闭udpClient 时此句会产生异常
                    byte[] receiveBytes = receiveUdpClient.Receive(ref remote);
                    string receiveMessage = Encoding.Unicode.GetString(
                        receiveBytes, 0, receiveBytes.Length);
                    listBox1.Items.Add("收到的消息:" + receiveMessage);
                }
                catch
                {
                    break;
                }
            }
        }
        //点击发送按钮发送数据

        private void button1_Click_1(object sender, EventArgs e)
        {
            //remoteip = IPAddress.Parse(txt_IPAddress.Text);
            Thread myThread = new Thread(SendMessage);
            myThread.IsBackground = true;
            myThread.Start(textBox1.Text);
        }
        //发送消息
        private void SendMessage(object obj)
        {
            string message = (string)obj;
            sendUdpClient = new UdpClient(0);
            byte[] bytes = Encoding.Unicode.GetBytes(message);
            IPEndPoint iep = new IPEndPoint(remoteip, port);
            try
            {
                sendUdpClient.Send(bytes, bytes.Length, iep);
                listBox1.Items.Add("发送的消息:" + message);
                textBox1.Clear();
            }
            catch (Exception ex)
            {
                listBox1.Items.Add("发送出错:" + ex.Message);
            }
        }
        delegate void AddItemDelegate(ListBox listbox, string text);
        private void AddItem(ListBox listbox, string text)
        {
            if (listbox.InvokeRequired)
            {
                AddItemDelegate d = AddItem;
                //Control.Invoke 方法 (Delegate, Object[]):
                //在拥有控件的基础窗口句柄的线程上,用指定的参数列表执行指定委托。
                listbox.Invoke(d, new object[] { listbox, text });
            }
            else
            {
                //Add:动态的添加列表框中的项
                listbox.Items.Add(text);

                //SelectedIndex属性获取单项选择ListBox中当前选定项的位置
                //Count:列表框中条目的总数
                listbox.SelectedIndex = listbox.Items.Count - 1;

                //调用此方法等效于将 SelectedIndex 属性设置为-1。 
                //可以使用此方法快速取消选择列表中的所有项。
                listbox.ClearSelected();
            }
        }
        delegate void ClearTextBoxDelegate();
        private void ClearTextBox()
        {
            if (textBox1.InvokeRequired)
            {
                ClearTextBoxDelegate d = ClearTextBox;
                textBox1.Invoke(d);
            }
            else
            {
                textBox1.Clear();
                textBox1.Focus();
            }
        }

        private void Button2_Click(object sender, EventArgs e)
        {
            this.Close();
        } 
    }
}

运行结果:
XX的学习日记(网络通信编程)三——C#编程和网络编程入门

4. 使用Wireshark抓取上述程序发送的网络包,并对数据帧结构进行分析

XX的学习日记(网络通信编程)三——C#编程和网络编程入门
源端口:用来传输数据包的端口
目标端口:数据包将要被传输到的端口
数据报长度:数据报的字节长度
校验和:用来确保UDP首部和数据到达时的完整性
数据:被UDP封装进去的数据,包含应用层协议头部和用户发出的数据

分析:
(1)XX的学习日记(网络通信编程)三——C#编程和网络编程入门
该内容表示这是第157帧数据报的详细信息,其中包的大小为352个字节。

(2)
XX的学习日记(网络通信编程)三——C#编程和网络编程入门
该内容表示以太网(WIFI)帧头部信息。其中源MAC地址为 98:22:ef:d1:be:23,目标MAC地址为94:b8:6d:e3:ae:95

(3)
XX的学习日记(网络通信编程)三——C#编程和网络编程入门
该内容表示本机的IP与目标终端的IP

(4)
XX的学习日记(网络通信编程)三——C#编程和网络编程入门
该内容表示传输层的数据报首部信息,此处是UDP协议
Source Port: 50886 表示源端口为50886
Destination Port: 8080 表示目标端口为8080
Length: 10 表示数据报长度为10
Checksum: 0x565e 表示校验和

(5)
XX的学习日记(网络通信编程)三——C#编程和网络编程入门
该内容表示 UDP 封装进去的数据,大小为 2 byte

相关标签: c#