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

一、安装Wireshark 抓包软件

Wireshark官网下载地址链接

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

目标: 实现如下功能:

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

1. 简单输出

(1)创建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)编译运行
在这里插入图片描述

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)客户端发送结果显示:
在这里插入图片描述
(4)服务端接收结果显示:
在这里插入图片描述

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

目标:

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

1. 创建一个Windows窗体应用

在这里插入图片描述
在这里插入图片描述

2. 编辑窗体

(1)拖取一个Button控件和两个TextBox控件
在这里插入图片描述
(2)设置消息显示控件属性
添加垂直滚动条:在这里插入图片描述
设置边界样式:在这里插入图片描述
设置消息显示界面的 TextBox 为不可编辑:
在这里插入图片描述
(3)设置Button控件属性
选中Button控件后:
在这里插入图片描述
(4)设置窗体属性
选中窗体后:

在这里插入图片描述

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

运行结果:
在这里插入图片描述

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

在这里插入图片描述
源端口:用来传输数据包的端口
目标端口:数据包将要被传输到的端口
数据报长度:数据报的字节长度
校验和:用来确保UDP首部和数据到达时的完整性
数据:被UDP封装进去的数据,包含应用层协议头部和用户发出的数据

分析:
(1)在这里插入图片描述
该内容表示这是第157帧数据报的详细信息,其中包的大小为352个字节。

(2)
在这里插入图片描述
该内容表示以太网(WIFI)帧头部信息。其中源MAC地址为 98:22:ef:d1:be:23,目标MAC地址为94:b8:6d:e3:ae:95

(3)
在这里插入图片描述
该内容表示本机的IP与目标终端的IP

(4)
在这里插入图片描述
该内容表示传输层的数据报首部信息,此处是UDP协议
Source Port: 50886 表示源端口为50886
Destination Port: 8080 表示目标端口为8080
Length: 10 表示数据报长度为10
Checksum: 0x565e 表示校验和

(5)
在这里插入图片描述
该内容表示 UDP 封装进去的数据,大小为 2 byte

©️2020 CSDN 皮肤主题: 数字20 设计师:CSDN官方博客 返回首页