TCP/UDP编程基础
一、UDP原理
(一)UDP简介
Internet 协议集支持一个无连接的传输协议,该协议称为用户数据包协议(UDP,User Datagram Protocol)。UDP 为应用程序提供了一种无需建立连接就可以发送封装的 IP 数据包的方法。RFC 768 描述了 UDP。
Internet 的传输层有两个主要协议,互为补充。无连接的是 UDP,它除了给应用程序发送数据包功能并允许它们在所需的层次上架构自己的协议之外,几乎没有做什么特别的事情。面向连接的是 TCP,该协议几乎做了所有的事情。
(二)UDP协议
源端口和目的端口,端口号理论上可以有2^16这么多。因为它的长度是16个bit
- Length占用2个字节,标识UDP头的长度,包括首部长度和数据长度。可以有65535字节那么长。但是一般网络-在传送的时候,一次一般传送不了那么长的协议(涉及到MTU的问题),就只好对数据分片。
- Checksum :校验和,包含UDP头和数据部分。这是一个可选的选项,并不是所有的系统都对UDP数据包加以检验和数据(相对TCP协议的必须来说),但是RFC中标准要求,发送端应该计算检验和。
- UDP检验和覆盖UDP协议头和数据,这和IP的检验和是不同的,IP协议的检验和只是覆盖IP数据头,并不覆盖所有的数据。UDP和TCP都包含一个伪首部,这是为了计算检验和而设置的。
伪首部甚至还包含IP地址这样的IP协议里面都有的信息,目的是让UDP两次检查数据是否已经正确到达目的地。如果发送端没有打开检验和选项,而接收端计算检验和有差错,那么UDP数据将会被悄悄的丢掉(不保证送达),而不产生任何差错报文
二、C#实现HelloWorld
(一)C#实现控制台helloworld
1.创建新项目控制台应用(.NET Framework)
->下一步
2.给项目命名选择位置,点击创建
3.测试输出
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace myc
{
internal class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello World!");
}
}
}
4.运行输出
(二)C#窗口输出helloworld
1.项目创建Windows窗体应用(.NET Framework)
->下一步
2.项目配置命名
3.点击工具箱加一个Button和TextBox
5.双击Button1加入代码
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace testWindowsFormsApp
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void button1_Click(object sender, EventArgs e)
{
//通过点击实际完成数据的添加显示
showMsg();
}
void showMsg()
{
//向文本控件中添加HelloWorld
textBox1.AppendText("Hello World!" + "\t\n");
}
}
}
6.运行结果
三、控制台程序使用 UDP 通信
(一)客户端
1.创建新项目控制台应用(.NET Framework)
->下一步
2.给项目命名选择位置,点击创建
2.编写代码
在Main中加入以下代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
namespace Server
{
class Program
{
static void Main(string[] args)
{
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.Default.GetString(receiveData);
Console.WriteLine(receiveString);
result = String.Compare(receiveString, str);
if (result == 0)
{
break;
}
}
client.Close();//关闭连接
Console.WriteLine("");
Console.WriteLine("数据接收完毕,按任意键退出...");
System.Console.ReadKey();
}
}
}
(二)服务器端
创建控制台应用(.NET Framework)
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.43.41"); //假设发送给这个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();
}
}
}
(三)WireShark抓包
1.运行客户端程序
2.另一台电脑充当服务器发送数据
2.接收到数据
3.打开WireShark进行抓包
四、窗口程序使用 UDP 通信
(一)客户端
1.项目创建Windows窗体应用(.NET Framework)
->下一步
2.给项目命名选择存储位置,点击创建
3.设计页面
(1)摆放控件:
- 首先往图形界面内拖动控件并进行摆放,如下图所示。
- 从工具箱内拖 2 个 TextBox 和 1 个 Button 控件。
注:刚拖出来的 TextBox 只能输入一行,只能横着拖,不能竖着拖,不用担心,看看下面的设置属性,就可以设计出如下的界面了
(2)设置消息输入框属性
选中一个 TextBox ,并点击黑色的小三角按钮,可以将单行文本框设置为多行文本框。
添加垂直滚动条:找到 ScrollBars 属性,设置参数为 Vertical 。
设置边界样式:找到 BorderStyle ,参数设置为 FixedSingle 。
编号为 textBox1 。
设置消息显示界面的 TextBox 不可编辑:找到 Enabled 属性,参数设为 False 。
(2)设置Button1设置发送消息按钮属性:
左键点击选中按钮,找到 Text 属性,参数输入为 “ 发送 ” ,则控件上就会显示输入的字样
它的唯一标识为:button1
设置字体样式
(3)设置窗体属性:
左击窗体选中它,在右下角的属性中找到 Text 属性,编辑为 “ 客户端 ” ,然后窗体的左上角,就显示为 “ 客户端 ”。
紧接着,有个 AcceptButton 属性,下拉框选中这个 button1 按钮,设置完这个属性后,当我们最后执行这个程序后,按下回车键 = 点击这个按钮。
至此,控件的一些简单属性就设置完毕了。
5.编写代码,双击Button1,编写代码
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 youWindowsFormsApp
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
string str = "The current time: ";
str += DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
textBox1.AppendText(str + Environment.NewLine);
UdpClient udpSender = new UdpClient(0);
int port = 8000;
string host = "192.168.43.41";//我室友的IP地址
IPAddress ip = IPAddress.Parse(host);
IPEndPoint ipe = new IPEndPoint(ip, port);//把ip和端口转化为IPEndPoint实例
udpSender.Connect(host, port);
string message = textBox2.Text;
byte[] sendBytes = Encoding.UTF8.GetBytes(message);
udpSender.Send(sendBytes, sendBytes.Length);
string sendStr = textBox2.Text;
str = "The message content: " + sendStr;
textBox1.AppendText(str + Environment.NewLine);
str = "Send the message to the server...";
textBox1.AppendText(str + Environment.NewLine);
byte[] recvStr = udpSender.Receive(ref ipe);
string message1 = Encoding.UTF8.GetString(recvStr, 0, recvStr.Length);
str = "The server feedback: " + message1;//显示服务器返回信息
textBox1.AppendText(str + Environment.NewLine);
}
}
}
(二)服务器
1.服务器端编写选择控制台应用
2.编写代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
namespace myConsoleApp
{
internal class Program
{
static void Main(string[] args)
{
int recv;
byte[] data = new byte[1024];
//得到本机IP,设置TCP端口号
IPEndPoint ip = new IPEndPoint(IPAddress.Any, 8000);
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.UTF8.GetString(data, 0, recv));
//客户机连接成功后,发送信息
string welcome = "连接成功 ";
//字符串与字节数组相互转换
data = Encoding.UTF8.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 = "连接成功";
if (input == "exit")
break;
//将input发送至客户机
server.SendTo(Encoding.UTF8.GetBytes(input), Remote);
}
server.Close();
}
}
}
(三)发送数据
1.室友发送给我的电脑的数据
2.我接收到的数据
(四)WireShark抓包
1.中文
2.数字
3.英文
五、总结
本次实验了解了UDP协议的相关内容原理,了解了如何用C#编写基本简单程序的方法,包括控制台程序和窗口程序,学会如何分别用这两种方式实现客户端向服务器端或者服务器端向客户端发送数据的方法。以及其中用到的UDP协议原理。