文章目录
- 一、控制台程序使用UDP通信
-
- 1.创建新项目
- 2.编写代码
- 二、Form窗口程序使用 TCP 通信
-
- 1.创建新项目
- 2.设计图形界面
- 3.编写代码
- 4.编译客户端和服务器端
- 三、TCP编程-端口扫描器
-
- 1.创建新项目
- 2.设置界面
- 3.编写代码
- 四、总结
- 五、参考链接
一、控制台程序使用UDP通信 1.创建新项目 (1)打开visual studio 2019,创建新项目
文章图片
(2)选择控制台应用(.net.Framework)
文章图片
(3)编辑项目名称,选择保存位置。
文章图片
(4)创建好项目如下图所示
文章图片
2.编写代码 在控制台上简单输出:
在 Main 函数内书写如下的代码(功能:连续输出 50 行数据)
for(int i = 0;
i < 50;
i++)
{
Console.WriteLine("第{0}行:hello cqjtu!重交物联2019级", (i + 1));
}
System.Console.ReadKey();
编译运行结果:
使用UDP通信
(1)目前最普遍的服务模式是 C/S 模式,所以需要一个客户端 client 和一个服务端 Server ,来实现通信。
(2)比如我现在在我的电脑上运行一个客户端代码,在我室友的电脑上运行一个服务端的代码,就可以实现通信功能。
(3)在我自己的电脑上使用 VS2019 创建一个新项目 client ,并将下列代码复制粘贴进去。(注意头文件!!!使用网络协议需要引入头文件 .Net 和 .Net.Sockets)
客户端
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
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.15");
//假设发送给这个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 += "第";
m = i + 1;
sendString += m.ToString();
sendString += "行:hello cqjtu!重交物联2019级";
//定义发送的字节数组
//将字符串转化为字节并存储到字节数组中
byte[] sendData = https://www.it610.com/article/null;
sendData = Encoding.Default.GetBytes(sendString);
client.Send(sendData, sendData.Length, remotePoint);
//将数据发送到远程端点
}
client.Close();
//关闭连接//提示信息
Console.WriteLine("");
Console.WriteLine("数据发送成功,按任意键退出...");
System.Console.ReadKey();
}
}
}
流程:
(1)首先显示提示信息,等待使用人员操作
(2)做好连接准备,如:设置IP地址,端口号
(3)for循环发送数据
(4)关闭端口
(5)显示提示信息,等待用户确认退出
在我室友的电脑上使用 VS2019 创建一个新项目 server,并将下列代码复制粘贴进去。
服务器端
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Threading.Tasks;
namespace Server1
{
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 = https://www.it610.com/article/null;
//实例化一个远程端点,IP和端口可以随意指定,等调用client.Receive(ref remotePoint)时会将该端点改成真正发送端端点
IPEndPoint remotePoint = new IPEndPoint(IPAddress.Any, 0);
Console.WriteLine("正在准备接收数据...");
while (true)
{
receiveData = https://www.it610.com/article/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();
}
}
}
代码流程:
①做好连接准备,并设置结束标志;
②循环接收数据;
③关闭连接;
④显示提示信息,等待用户确定退出。
运行结果显示
文章图片
文章图片
(1)打开wirshark,点击捕获—>选项
文章图片
(2)选择WLAN,开始
文章图片
(3)可以看到现在 Wireshark 不断的在抓包,先点击红色的按钮暂停抓包。
文章图片
(4)重新编译客户端和服务器端,先不要按下按键发送数据,先挂着,看下一步。
文章图片
(5)点击鲨鱼鱼鳍的图标,然后点击 “ 继续不保存 ”,不保存之前抓取的包。
文章图片
(6)然后按键盘开始发送数据,发送完后,点击 Wireshark 的红色按钮,停止抓包。
二、Form窗口程序使用 TCP 通信 1.创建新项目 (1)选中 “ Windows 窗体应用 ” ,再点击 “ 下一步 ”。
文章图片
(2)设置项目名称、保存位置,再点击 “ 创建 ” 。
文章图片
(3)创建完毕。
文章图片
2.设计图形界面 【ubuntu|C#使用TCP/UDP协议通信并用Wireshark抓包分析数据】摆放控件:
(1)首先往图形界面内拖动控件并进行摆放,如下图所示。
从工具箱内拖 2 个 TextBox 和 1 个 Button 控件。
文章图片
设置消息输入框属性:
(2)左键选中最下面的 TextBox ,并在右下角的属性中找到 Font 属性,并点击 “ … ”
文章图片
文章图片
(3)然后在设计属性中的(Name)这里默认的 textBox1 ,也可以更改,但不能重复,唯一标识,这是控件的编号,用于代码编写的时候识别,就像是身份证号一样,不能出现中文。
文章图片
(4)在布局这里,Location 是指控件左上角顶点基于窗口所在的位置,Size 是指控件的长和宽,可以自行设置。
也可自行拖动文本框,改变长宽,位置。
文章图片
(5)选中TextBox2
添加垂直滚动条:找到 ScrollBars 属性,设置参数为 Vertical
文章图片
设置边界样式:找到 BorderStyle ,参数设置为 FixedSingle
文章图片
编号为 textBox2 。
文章图片
设置消息显示界面的 TextBox 不可编辑:找到 Enabled 属性,参数设为 False 。
文章图片
设置发送消息按钮属性:
左键点击选中按钮,找到 Text 属性,参数输入为 “ 发送 ” ,则控件上就会显示输入的字样
文章图片
它的唯一标识为:button1
文章图片
设置窗体属性:
(1)左击窗体选中它,在右下角的属性中找到 Text 属性,编辑为 “ 客户端 ” ,然后窗体的左上角,就显示为 “ 客户端 ”。
(2)紧接着,有个 AcceptButton 属性,下拉框选中这个 button1 按钮,设置完这个属性后,当我们最后执行这个程序后,按下回车键 = 点击这个按钮。
文章图片
文章图片
至此,控件的一些简单属性就设置完毕了。
文章图片
3.编写代码
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();
}public 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 = 82569;
string host = "192.168.43.14";
//我室友的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 = "";
}
}
}
**流程:
当点击按钮后,button1_Click 函数开始执行。
①获取当前时间,并打印到消息显示界面内;
②做连接服务器端的准备,如:设置IP、设置端口号、实例socket端口;
③打印连接信息,并连接服务器;
④从消息输入框获取字符串并按照UTF8编码到字节数组存储,然后发送出去。
⑤将从服务器端接收到的字节流按照UTF8解码为字符串并存储打印出来。
⑥关闭socket端口变量。
两个 catch 是做异常情况处理,并打印到消息显示界面内。
接下来开始编写服务器端代码:
注:从第三部分: “ Form窗口程序使用 TCP 通信 ” 开始至此,都是在编写客户端的部分,接下来我们需要编写服务器端的代码了。
根据第二部分: “ 控制台程序使用 UDP 通信 ” 创建一个新的控制台程序,这里就不再演示了。
复制下面 main 函数内的代码,并粘贴进你自己的 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 ConsoleApp2
{
class Program
{
static void Main(string[] args)
{
/*
* 做好连接准备
*/
int i = 0;
int port = 82569;
string host = "192.168.43.14";
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.编译客户端和服务器端 客户端
文章图片
服务器端:
文章图片
现在向服务器发送数据
文章图片
服务器端
文章图片
三、TCP编程-端口扫描器 1.创建新项目
文章图片
2.设置界面 需要1个button,1个Listbox,4个TextBox,5个label控件
文章图片
3.编写代码 单线程
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WindowsFormsApp3
{
public partial class Form1 : Form
{
//主机地址
private string hostAddress;
//起始端口
private int start;
//终止端口
private int end;
//端口号
private int port;
//定义线程对象
//private Thread scanThread;
public Form1()
{
InitializeComponent();
}private void label1_Click(object sender, EventArgs e)
{}private void label3_Click(object sender, EventArgs e)
{
}private void button1_Click(object sender, EventArgs e)
{
try
{//初始化
textBox4.Clear();
label5.Text = "0%";
//获取ip地址和始末端口号
hostAddress = textBox1.Text;
start = Int32.Parse(textBox2.Text);
end = Int32.Parse(textBox3.Text);
if (decideAddress())
{
//让输入的textbox只读,无法改变
textBox1.ReadOnly = true;
textBox2.ReadOnly = true;
textBox3.ReadOnly = true;
//设置进度条的范围
progressBar1.Minimum = start;
progressBar1.Maximum = end;
//显示框显示
textBox4.AppendText("端口扫描器 v1.0.0" + Environment.NewLine + Environment.NewLine);
//调用端口扫描函数
PortScan();
}
else
{
//若端口号不合理,弹窗报错
MessageBox.Show("输入错误,端口范围为[0-65536]!");
}
}
catch
{
//若输入的端口号为非整型,则弹窗报错
MessageBox.Show("输入错误,端口范围为[0-65536]!");
}
}private bool decideAddress()
{
//判断端口号是否合理
if ((start >= 0 && start <= 65536) && (end >= 0 && end <= 65536) && (start <= end))
return true;
else
return false;
}private void PortScan()
{
double x;
string xian;
//显示扫描状态
textBox4.AppendText("开始扫描...(可能需要请您等待几分钟)" + Environment.NewLine + Environment.NewLine);
//循环抛出线程扫描端口
for (int i = start;
i <= end;
i++)
{
x = (double)(i - start + 1) / (end - start + 1);
xian = x.ToString("0%");
port = i;
//调用端口i的扫描操作
Scan();
//进度条值改变
label5.Text = xian;
label5.Refresh();
progressBar1.Value = https://www.it610.com/article/i;
}
textBox1.AppendText(Environment.NewLine +"扫描结束!" + Environment.NewLine);
//输入框textbox只读属性取消
textBox1.ReadOnly = false;
textBox2.ReadOnly = false;
textBox3.ReadOnly = false;
}private void Scan()
{
int portnow = port;
//创建TcpClient对象,TcpClient用于为TCP网络服务提供客户端连接
TcpClient objTCP = null;
try
{
//用于TcpClient对象扫描端口
objTCP = new TcpClient(hostAddress, portnow);
//扫描到则显示到显示框
textBox1.AppendText("端口 " + port + " 开放!" + Environment.NewLine);
}
catch
{
//未扫描到,则会抛出错误
}
}
}
}
文章图片
多线程
代码
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Threading;
namespace WindowsFormsApp4
{
public partial class Form1 : Form
{
//主机地址
private string hostAddress;
//起始端口
private int start;
//终止端口
private int end;
//端口号
private int port;
//定义线程对象
private Thread scanThread;
//定义端口状态数据(开放则为true,否则为false)
private bool[] done = new bool[65526];
private bool OK;
public Form1()
{
InitializeComponent();
//不进行跨线程检查
CheckForIllegalCrossThreadCalls = false;
}private void textBox4_TextChanged(object sender, EventArgs e)
{}private void progressBar1_Click(object sender, EventArgs e)
{}private void button1_Click(object sender, EventArgs e)
{
try
{
//初始化
textBox4.Clear();
label5.Text = "0%";
//获取ip地址和始末端口号
hostAddress = textBox1.Text;
start = Int32.Parse(textBox2.Text);
end = Int32.Parse(textBox3.Text);
if (decideAddress())
{
textBox1.ReadOnly = true;
textBox2.ReadOnly = true;
textBox3.ReadOnly = true;
//创建线程,并创建ThreadStart委托对象
Thread process = new Thread(new ThreadStart(PortScan));
process.Start();
//设置进度条的范围
progressBar1.Minimum = start;
progressBar1.Maximum = end;
//显示框显示
textBox4.AppendText("端口扫描器 v1.0.0" + Environment.NewLine + Environment.NewLine);
}
else
{
//若端口号不合理,弹窗报错
MessageBox.Show("输入错误,端口范围为[0-65536]!");
}
}
catch
{
//若输入的端口号为非整型,则弹窗报错
MessageBox.Show("输入错误,端口范围为[0-65536]!");
}
}private bool decideAddress()
{
//判断端口号是否合理
if ((start >= 0 && start <= 65536) && (end >= 0 && end <= 65536) && (start <= end))
return true;
else
return false;
}private void PortScan()
{
double x;
string xian;
//显示扫描状态
textBox4.AppendText("开始扫描...(可能需要请您等待几分钟)" + Environment.NewLine + Environment.NewLine);
//循环抛出线程扫描端口
for (int i = start;
i <= end;
i++)
{
x = (double)(i - start + 1) / (end - start + 1);
xian = x.ToString("0%");
port = i;
//使用该端口的扫描线程
scanThread = new Thread(new ThreadStart(Scan));
scanThread.Start();
//使线程睡眠
System.Threading.Thread.Sleep(100);
//进度条值改变
label5.Text = xian;
progressBar1.Value = https://www.it610.com/article/i;
}
while (!OK)
{
OK = true;
for (int i = start;
i <= end;
i++)
{
if (!done[i])
{
OK = false;
break;
}
}
System.Threading.Thread.Sleep(1000);
}
textBox4.AppendText(Environment.NewLine +"扫描结束!" + Environment.NewLine);
textBox1.ReadOnly = false;
textBox2.ReadOnly = false;
textBox3.ReadOnly = false;
}private void Scan()
{
int portnow = port;
//创建线程变量
Thread Threadnow = scanThread;
//扫描端口,成功则写入信息
done[portnow] = true;
//创建TcpClient对象,TcpClient用于为TCP网络服务提供客户端连接
TcpClient objTCP = null;
try
{
//用于TcpClient对象扫描端口
objTCP = new TcpClient(hostAddress, portnow);
//扫描到则显示到显示框
textBox4.AppendText("端口 " + port + " 开放!" + Environment.NewLine);
}
catch
{
//未扫描到,则会抛出错误
}
}
}
}
文章图片
相比于单线程,多线程快很多
四、总结 本实验主要是用C#编写一个命令行/控制台的简单hello world程序,实现如下功能:在屏幕上连续输出50行“hello cqjtu!重交物联2019级”;同时打开一个网络UDP 套接字,向另一台室友电脑发送这50行消息。
用VS2019 的C#编写一个简单的Form窗口程序,有一个文本框 textEdit和一个发送按钮button,运行程序后,可以在文本框里输入文字,如“hello cqjtu!重交物联2019级”,点击button,将这些文字发送给室友电脑,采用UDP套接字;
编写端口扫描器程序,分别采用单一进程和多线程方式,对比两者的效果
五、参考链接 https://blog.csdn.net/ssj925319/article/details/109336123
https://blog.csdn.net/tyro_00/article/details/109827571
https://blog.csdn.net/qq_55691662/article/details/121455003?spm=1001.2014.3001.5501
推荐阅读
- Linux777权限是啥
- opencv|opencv之 编译opencv中的GPU库及从Opencv2.4.11到Opencv3.4.1遇到的搞笑问题整理()
- CUDA|Opencv调用GPU模块
- 笔记|Redis-redis概念、配置、Sentinel高可用
- 笔记|mysql(三)路由器读写分离、MHA高可用
- 笔记|mysql(二)优化mysql
- linux|jenkins
- linux|在安装Docker-ce的时候遇到报错
- 笔记|Linux笔记4(软件包管理,Shell编程)