目录
一、UDP介绍
这部分总结来源于:HarrietLH C#利用套接字实现数据发送
1.Socket
套接字是支持TCP/IP协议的网络通信的基本操作单元。可以将套接字看作不同主机间的进程进行双向通信的端点,它构成了单个主机内及整个网络间的编程界面。
套接字的工作原理:
通过互联网进行通信,至少需要一对套接字,其中一个运行于客户机端,称之为ClientSocket,另一个运行于服务器端,称之为ServerSocket。
套接字之间的连接过程可以分为三个步骤:服务器监听,客户端请求,连接确认。
2.TCP
TCP协议提供的是端到端服务。TCP协议所提供的端到端的服务是保证信息一定能够到达目的地址。它是一种面向连接的协议。
TCP编程的服务器端一般步骤
①创建一个socket,用函数socket()
②绑定IP地址、端口等信息到socket上,用函数bind()
③开启监听,用函数listen()
④接收客户端上来的连接,用函数accept()
⑤收发数据,用函数send()和recv(),或者read()和write()
⑥关闭网络连接;
⑦关闭监听;
TCP编程的客户端一般步骤
①创建一个socket,用函数socket()
②设置要连接的对方的IP地址和端口等属性
③连接服务器,用函数connect()
④收发数据,用函数send()和recv(),或者read()和write()
⑤关闭网络连接
3.UDP
UDP协议提供了一种不同于TCP协议的端到端服务。UDP协议所提供的端到端传输服务是尽力而为(best-effort)的,即UDP套接字将尽可能地传送信息,但并不保证信息一定能成功到达目的地址,而且信息到达的顺序与其发送顺序不一定一致。
UDP编程的服务器端一般步骤
①创建一个socket,用函数socket()
②绑定IP地址、端口等信息到socket上,用函数bind()
③循环接收数据,用函数recvfrom()
④关闭网络连接
UDP编程的客户端一般步骤
①创建一个socket,用函数socket()
②设置对方的IP地址和端口等属性
③发送数据,用函数sendto()
④关闭网络连接
通过两种协议的介绍,可以看出对于UDP协议要比TCP简单一些。但是,UDP不能够保证数据传输一定到达目的地址。
二、控制台程序使用 UDP 通信
任务:用C#、Java或python编写一个命令行/控制台的简单hello world程序,实现如下功能:在屏幕上连续输出50行“hello
cqjtu!重交物联2019级”;同时打开一个网络UDP 套接字,向另一台室友电脑发送这50行消息。
1.控制台输出hello world
①创建新项目
选择控制台应用(.NET Framework),然后下一步
②添加代码
创建好项目,添加如下代码
for (int i = 0; i < 50; i++)
{
Console.WriteLine("第{0}行:hello cqjtu!重交物联2019级", (i + 1));
}
System.Console.ReadKey();
③运行编译
2.使用UDP在室友电脑输出hello world
我们准备在自己电脑上编写客户端代码,在室友的电脑上编写服务端代码,以此来实现两台电脑通信
①客户端
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("10.160.184.45"); //假设发送给这个IP
int remotePort = 1000; //设置端口号
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();
}
}
}
代码流程:
- ①首先显示提示信息,等待使用人员操作;
- ②做好连接准备,如:设置IP、端口号等;
- ③ for 循环发送数据;
- ④关闭端口;
- ⑤显示提示信息,等待用户确认退出。
其中这里的IP是我室友的IP地址,因为要将室友的电脑作为我的服务器
IPAddress remoteIP = IPAddress.Parse("10.160.184.45"); //假设发送给这个IP
②服务端
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(1000);
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();
}
}
}
代码流程:
- ①做好连接准备,并设置结束标志;
- ②循环接收数据;
- ③关闭连接;
- ④显示提示信息,等待用户确定退出。
③编译结果
客户端:
服务端:
3.利用Wireshark抓包分析
打开Wireshark之后在这里输入过滤条件
ip.dst==10.160.184.45
这里的过滤条件是显示目标地址为10.160.184.45的数据包列表,也就是我室友的IP
可以从上图看出来已经抓到了我向目标IP发送的包,选择其中一个包
可以看到我发送的内容
三、Form窗口程序使用 TCP 通信
任务:用VS2017/2019 的C#编写一个简单的Form窗口程序,有一个文本框
textEdit和一个发送按钮button,运行程序后,可以在文本框里输入文字,如“hello
cqjtu!重交物联2019级”,点击button,将这些文字发送给室友电脑,采用UDP套接字;
1.创建项目
新建项目选择Windows 窗体应用
选择好项目文件路径,然后创建项目
2.设计图形界面
借助工具箱完成各个控件的设置(我们这里简单设置了两个Texbox和一个Button)
3.代码编写
双击发送按钮跳转到对应的代码
在 button1_Click
函数内复制粘贴如下代码
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 WindowsFormsApp3
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
try
{
/*
* 显示当前时间
*/
string str = "The current time: ";
str += DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
textBox2.AppendText(str + Environment.NewLine);
/*
* 做好连接准备
*/
int port = 2000;
string host = "10.61.54.150";//我室友的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...";
textBox2.AppendText(str + Environment.NewLine);
c.Connect(ipe);//连接到服务器
/*
*发送消息
*/
string sendStr = textBox1.Text;
str = "The message content: " + sendStr;
textBox2.AppendText(str + Environment.NewLine);
byte[] bs = Encoding.UTF8.GetBytes(sendStr);
str = "Send the message to the server...";
textBox2.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;//显示服务器返回信息
textBox2.AppendText(str + Environment.NewLine);
/*
* 关闭socket
*/
c.Close();
}
catch (ArgumentNullException f)
{
string str = "ArgumentNullException: " + f.ToString();
textBox2.AppendText(str + Environment.NewLine);
}
catch (SocketException f)
{
string str = "ArgumentNullException: " + f.ToString();
textBox2.AppendText(str + Environment.NewLine);
}
textBox2.AppendText("" + Environment.NewLine);
textBox1.Text = "";
}
}
}
然后在我室友的电脑上创建一个控制台程序
代码如下
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApp2
{
class Program
{
static void Main(string[] args)
{
/*
* 做好连接准备
*/
int i = 0;
int port = 2000;
string host = "10.61.54.150";
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.Write("Perform operations {0} :",i);
Console.WriteLine("\t-----------------------------------------------");
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);
}
}
}
}
}
4.程序运行
客户端:
服务端:
5.利用Wireshark抓包分析
打开Wireshark之后在这里输入过滤条件ip.dst==10.61.54.150
这里的过滤条件是显示目标地址为10.160.184.45的数据包列表,也就是我室友的IP
抓到TCP的包,打开查看发送的内容
四、参考文献
1.HarrietLH C#利用套接字实现数据发送
2.可乐有点好喝 C#使用TCP/UDP协议通信并用Wireshark抓包分析数据