C#使用TCP/UDP协议通信

C#使用TCP/UDP协议通信

    • 1.控制台程序使用 UDP 通信
      • 创建项目
      • 单输出代码
      • 使用 UDP 通信
        • 发送端
        • 接收端
        • 结果
    • Form窗口程序使用 TCP 通信
        • 创建客户端项目
        • 客户端设计界面
          • 设置输入框属性:
          • 设置消息显示界面属性:
          • 设置发送消息按钮属性:
          • 设置窗体属性:
        • 客户端代码实现
        • 服务器端代码
        • 运行
    • wireshark抓包
        • 控制台程序使用 UDP 通信
        • Form窗口程序使用 TCP 通信
        • 总结
        • 参考

1.控制台程序使用 UDP 通信

实验内容:用C#、Java或python编写一个命令行/控制台的简单hello world程序,实现如下功能:

  • 在屏幕上连续输出50行“hello cqjtu!重交物联2019级”
  • 同时打开一个网络UDP 套接字,向另一台室友电脑发送这50行消息

创建项目

  • 打开 VS2019 ,点击 “ 创建新项目 ”
    C#使用TCP/UDP协议通信_第1张图片
  • 进行条件筛选,选择 “ 控制台应用(.NET Framework) ” ,然后点击 “ 下一步 ”
    C#使用TCP/UDP协议通信_第2张图片
  • 创建
    C#使用TCP/UDP协议通信_第3张图片
    C#使用TCP/UDP协议通信_第4张图片

单输出代码

for (int i = 0; i < 50; i++)
            {
                Console.WriteLine("hello cqjtu!重交物联2019级");
            }
            System.Console.ReadKey();

C#使用TCP/UDP协议通信_第5张图片
运行结果:
C#使用TCP/UDP协议通信_第6张图片

使用 UDP 通信

目前最普遍的服务模式是 C/S 模式,所以需要编写一个客户端 client 和一个服务端 Server ,来实现通信。

我在我的电脑上运行一个客户端代码,在我室友的电脑上运行一个服务端的代码,就可以实现通信功能。

发送端

代码流程:

  • 首先显示提示信息,等待使用人员操作;
  • 做好连接准备,如:设置IP、端口号等;
  • for 循环发送数据;
  • 关闭端口;
  • 显示提示信息,等待用户确认退出。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net;
using System.Net.Sockets; 
//注意头文件!!!使用网络协议需要引入头文件 .Net 和 .Net.Sockets)

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

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

            for (int i = 0; i < 50; i++)
            {
                //要发送的数据:第n行:hello cqjtu!重交物联2018级
                string sendString = null;
                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();
        }
    }
}


接收端

代码流程:

  • 做好连接准备,并设置结束标志;
  • 循环接收数据;
  • 关闭连接;
  • 显示提示信息,等待用户确定退出。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net;
using System.Net.Sockets;

namespace ConsoleApp2
{
    class Program
    {
        static void Main(string[] args)
        {
            int result = 1;
            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.Default.GetString(receiveData);
                Console.WriteLine(receiveString);
                if (result == 50)
                {
                    break;
                }

                result++;
            }
            client.Close();//关闭连接
            Console.WriteLine("");
            Console.WriteLine("数据接收完毕,按任意键退出...");
            System.Console.ReadKey();
        }
    }
}

结果

发送:
C#使用TCP/UDP协议通信_第7张图片
接收:
C#使用TCP/UDP协议通信_第8张图片

Form窗口程序使用 TCP 通信

用VS2017/2019 的C#编写一个简单的Form窗口程序,有一个文本textEdit和一个发送按钮button,运行程序后,可以在文本框里输入文字,如“hello cqjtu!重交物联2019级”,点击button,将这些文字发送给室友电脑,采用UDP套接字;

从客户端发送多条数据,服务器端接收多条数据,服务器端反馈发送信息给客户端,客户端收到并显示出来。

接下来,我们创建一个新的 C# Form 窗口程序。

创建客户端项目

C#使用TCP/UDP协议通信_第9张图片
C#使用TCP/UDP协议通信_第10张图片

C#使用TCP/UDP协议通信_第11张图片

客户端设计界面

从工具箱内拖 2 个 TextBox 和 1 个 Button 控件。
C#使用TCP/UDP协议通信_第12张图片

设置输入框属性:
  1. 选中对应的 TextBox ,并在右下角的属性中找到 Font 属性,并点击 “ … ”
    C#使用TCP/UDP协议通信_第13张图片
    里面可以设置自己喜欢的字体
    C#使用TCP/UDP协议通信_第14张图片
  2. 设计属性中的(Name)这里默认的 textBox1 ,也可以更改,但不能重复,唯一标识,这是控件的编号,用于代码编写的时候识别,就像是身份证号一样,但是不能出现中文。
    C#使用TCP/UDP协议通信_第15张图片
  3. 在布局这里,Location 是指控件左上角顶点基于窗口所在的位置,Size 是指控件的长和宽,可以自行设置。
    C#使用TCP/UDP协议通信_第16张图片
设置消息显示界面属性:
  1. 点击黑色的小三角按钮,可以将单行文本框设置为多行文本框。
    C#使用TCP/UDP协议通信_第17张图片
  2. 添加垂直滚动条:找到 ScrollBars 属性,设置参数为 Vertical 。
    C#使用TCP/UDP协议通信_第18张图片
  3. 设置边界样式:找到 BorderStyle ,参数设置为 FixedSingle 。
    C#使用TCP/UDP协议通信_第19张图片
  4. 设置消息显示界面的 TextBox 不可编辑:找到 Enabled 属性,参数设为 False 。
    C#使用TCP/UDP协议通信_第20张图片

还可以根据设置消息输入框的文本样式来设置消息显示界面内的文本样式。

设置发送消息按钮属性:
  1. 找到 Text 属性,参数输入为 “ 发送 ” ,则控件上就会显示输入的字样。
    C#使用TCP/UDP协议通信_第21张图片
设置窗体属性:
  1. 左击窗体选中它,在右下角的属性中找到 Text 属性,编辑为 “ 客户端 ” ,然后窗体的左上角,就显示为 “ 客户端 ”。
  2. 紧接着,有个 AcceptButton 属性,下拉框选中这个 button1 按钮,设置完这个属性后,当我们最后执行这个程序后,按下回车键 = 点击这个按钮。
    C#使用TCP/UDP协议通信_第22张图片
客户端代码实现

双击图形界面的按钮后,VS2019 会自动的转到代码编辑区域。

C#使用TCP/UDP协议通信_第23张图片
代码流程:
当点击按钮后,button1_Click 函数开始执行。

  • 获取当前时间,并打印到消息显示界面内;
  • 做连接服务器端的准备,如:设置IP、设置端口号、实例socket端口;
  • 打印连接信息,并连接服务器;
  • 从消息输入框获取字符串并按照UTF8编码到字节数组存储,然后发送出去。
  • 将从服务器端接收到的字节流按照UTF8解码为字符串并存储打印出来。
  • 关闭socket端口变量。

两个 catch 是做异常情况处理,并打印到消息显示界面内。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace WindowsFormsApp1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            
        }

        private void button1_Click(object sender, EventArgs e)
        {
            try
            {
                /*
                 * 显示当前时间
                 */
                string str = "The current time: ";
                str += DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
                textBox1.AppendText(str + Environment.NewLine);
                /*
                 * 做好连接准备
                 */
                int port = 2000;
                string host = "10.61.170.2";//我室友的IP地址
                IPAddress ip = IPAddress.Parse(host);
                IPEndPoint ipe = new IPEndPoint(ip, port);//把ip和端口转化为IPEndPoint实例
                Socket c = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);//创建一个Socket
                /*
                 * 开始连接
                 */
                str = "Connect to server...";
                textBox1.AppendText(str + Environment.NewLine);
                c.Connect(ipe);//连接到服务器
                /*
                 *发送消息 
                 */
                string sendStr = textBox2.Text;
                str = "The message content: " + sendStr;
                textBox1.AppendText(str + Environment.NewLine);
                byte[] bs = Encoding.UTF8.GetBytes(sendStr);
                str = "Send the message to the server...";
                textBox1.AppendText(str + Environment.NewLine);
                c.Send(bs, bs.Length, 0);//发送信息
                /*
                 * 接收服务器端的反馈信息
                 */
                string recvStr = "";
                byte[] recvBytes = new byte[1024];
                int bytes;
                bytes = c.Receive(recvBytes, recvBytes.Length, 0);//从服务器端接受返回信息
                recvStr += Encoding.UTF8.GetString(recvBytes, 0, bytes);
                str = "The server feedback: " + recvStr;//显示服务器返回信息
                textBox1.AppendText(str + Environment.NewLine);
                /*
                 * 关闭socket
                 */
                c.Close();
            }
            catch (ArgumentNullException f)
            {
                string str = "ArgumentNullException: " + f.ToString();
                textBox1.AppendText(str + Environment.NewLine);
            }
            catch (SocketException f)
            {
                string str = "ArgumentNullException: " + f.ToString();
                textBox1.AppendText(str + Environment.NewLine);
            }
            textBox1.AppendText("" + Environment.NewLine);
            textBox2.Text = "";
        }
    }
}

服务器端代码

根据前面 “ 控制台程序使用 UDP 通信 ” 创建一个新的控制台程序

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

namespace ConsoleApp3
{
    class Program
    {
        static void Main(string[] args)
        {
            /*
             * 做好连接准备
             */
            int i = 0;
            int port = 2000;
            string host = "10.61.170.2";
            IPAddress ip = IPAddress.Parse(host);
            IPEndPoint ipe = new IPEndPoint(ip, port);
            Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);//创建一个Socket类
            s.Bind(ipe);//绑定2000端口
            /*
             * 循环监听并处理消息
             */
            while (true)
            {
                i++;
                try
                {
                    Console.WriteLine("\t-----------------------------------------------");
                    Console.Write("Perform operations {0} :", i);
                    s.Listen(0);//开始监听
                    Console.WriteLine("1. Wait for connect...");
                    /*
                     * 实例一个新的socket端口
                     */
                    Socket temp = s.Accept();//为新建连接创建新的Socket。
                    Console.WriteLine("2. Get a connect");
                    /*
                     * 接收客户端发的消息并做解码处理
                     */
                    string recvStr = "";
                    byte[] recvBytes = new byte[1024];
                    int bytes;
                    bytes = temp.Receive(recvBytes, recvBytes.Length, 0);//从客户端接受信息
                    recvStr += Encoding.UTF8.GetString(recvBytes, 0, bytes);
                    Console.WriteLine("3. Server Get Message:{0}", recvStr);//把客户端传来的信息显示出来
                    /*
                     * 返回给客户端连接成功的消息
                     */
                    string sendStr = "Ok!Client send message sucessful!";
                    byte[] bs = Encoding.UTF8.GetBytes(sendStr);
                    temp.Send(bs, bs.Length, 0);//返回客户端成功信息
                    /*
                     * 关闭端口
                     */
                    temp.Close();
                    Console.WriteLine("4. Completed...");
                    Console.WriteLine("-----------------------------------------------------------------------");
                    Console.WriteLine("");
                    //s.Close();//关闭socket(由于再死循环中,所以不用写,但如果是单个接收,实例socket并完成任务后需关闭)
                }
                catch (ArgumentNullException e)
                {
                    Console.WriteLine("ArgumentNullException: {0}", e);
                }
                catch (SocketException e)
                {
                    Console.WriteLine("SocketException: {0}", e);
                }
            }
        }
    }
}

运行

C#使用TCP/UDP协议通信_第24张图片
C#使用TCP/UDP协议通信_第25张图片

wireshark抓包

控制台程序使用 UDP 通信

输入 “ UDP ” 过滤包,然后就可以看到下面的信息,这些就是我发送给我室友电脑上的 50 条数据
C#使用TCP/UDP协议通信_第26张图片

  1. Version(版本号):分为 IPv4 和 IPv6 现在普遍都用的 IPv4 ,所以值为 4 ,1 个字节;
  2. HLen(ip报头长度):32位字的报头长度(HLEN);
  3. TOS(级别):服务类型描述数据报将如何被处理,比如优先发送等,大多数都是默认为 0 ;
  4. Datagram Total Length(总长度):包括报头和数据的数据包长度
  5. identifier(标识):唯一的 IP 数据包值;
  6. Flags(标志):说明是否有数据被分段,我是一条一条的发送多个数据包,每个包的数据很小,没有被分段,所以这里数值为 0 。
  7. Fragmentation Offset(分段偏移):如果数据包在装人帧时太大,则需要进行分段和重组,这里没有分段,所以偏移量为 0 ;
  8. TTL(存活期):存活期是在数据包产生时建立在其内部的一个设置,如果这个数据包在这个TTL到期时仍没有到达它要去的目的地,那么它将被丢弃,这个设置将防止IP包在寻找目的地的时候在网络中不断循环,每经过一个路由器,它的值就减一,这里它的值为 128 ,也就是 128 个生存期;
  9. Protocol(协议):上层协议的端口( TCP 是端口 6;UDP 是端口 17) ,同样也支持网络层协议,如ARP和ICMP,这里值为 17 ,也就是 UDP 协议;
  10. Header Checksum(校验码):只针对报头的循环冗余校验(CRC);
  11. Source Address(源地址):消息发送者的 ip 地址,这里是10.60.191.19;
  12. Destination Address(目的地址):消息接收者的 ip 地址,这里是10.60.202.32;
  13. ip包头的第六行:用于网络检测、调试、安全以及更多的内容,不过大多数情况都是默认为 0 的;
  14. Data数据包:可以很显然看到,长度为 34 字节,对应的十六进制就是蓝色的区域了,这就是我们要发送的数据:第n行:hello cqjtu!重交物联2019级
    C#使用TCP/UDP协议通信_第27张图片
Form窗口程序使用 TCP 通信

UDP与TCP包的区别
UDP:
在这里插入图片描述
第三行:Internet Protocl Version 4:IPv4协议
第四行:User Datagram Protocol:UDP协议
TCP:
在这里插入图片描述
第三行:Internet Protocl Version 4:IPv4协议
第四行:Transmission Control Protocol:TCP协议

它们的区别也就在于第四行,第三行都是 IPv4 协议。

总结

UDP/TCP 套接字进行网络通信,都是基于 C/S 模式,一个客户端,一个服务器端,在使用套接字的时候,端口号、IP地址是必不可缺的

参考

C#使用TCP/UDP协议通信并用Wireshark抓包分析数据

你可能感兴趣的:(网络通信编程,python,opencv,开发语言)