TCP编程端口扫描器与网游客户端
本次实验,博主将使用TCP来编写一个端口扫描器以及制作一个网游的客户端
1. 编写端口扫描器程序
1.1编程一个单线程端口扫描器
首先,打开VS2017,点击文件–>新建–>项目,选择Windows窗口应用,创建一个带界面的应用程序。
其次,进入窗口设计页面,现在的窗口应该是空白的一片,从工具栏中选择Label,TextBox,ProgressBar这三个类型的工具若干(如果没有工具箱,可以从视图-- >工具箱召唤出工具栏),在此介绍一下所用各工具的用处。
Label:为控件提供运行时的信息或者信息说明
TextBox:允许用户输入文本,或者输出文本(用作输入密码时可用字符掩码功能)
ProgressBar:显示一个向用户显示操作进程的填充条,俗称进度条。
按照以前所用的应用的大致界面,歪歪扭扭拼凑了一个简易的端口扫描器界面出来。
拼凑好后,将老师所给的代码经过修饰后加入进程序中(可双击控件召唤出编程界面)
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net.Sockets;
using System.Threading;
namespace Port_Scanning
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
//不进行跨线程检查
CheckForIllegalCrossThreadCalls = false;
}
//主机地址
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;
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 = 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
{
//未扫描到,则会抛出错误
}
}
}
}
如果直接使用代码的话,Program.cs中该行可能会报错
原因是因为它找不到Form1程序
可在前面加上命名空间名(我的是Port_Scanning),此程序就不会报错了
填充好代码后,点击启动,让其运行。
可以看到单线程下程序扫描20个端口,缓慢的完成了扫描任务
1.2编译完成一个多线程端口扫描器
由于单线程端口扫描器有点慢,所以接下来编程一个多线程的端口扫描器。
由于外壳不变,只需要改变其内核,所以还是可以使用上面所拼凑的窗口,在窗口函数中做一点小小的修改。修改完毕后,点击运行。
可以看到,使用多线程的端口扫描器明显快于单线程端口扫描器.
2.编写网游客户端
2.1考古20年前的游戏
要求:游戏服务器的校园内网IP地址为 10.160.52.106,端口为3900,采用TCP连接。
首先,为了保证能够连接到这个游戏,先尝试ping通此IP
可以看到,能够ping通该IP,则进入下一步,输入telnet,输入以下代码
open 10.160.52.106 3900
成功进入金庸梦这款游戏(后悔知道的有点晚)
2.2使用VS2017实现网游客户端
接下来将要在VS2017中编程,将模板函数略微修改一下
由于是空头函数,于是点进去看了看效果
接下来,我们镶嵌一点函数进去
首先,需要建立TCP连接,使用如下函数(如有不懂可以查看以下博客)
C# tcpClient发送和接收
private void button10_Click(object sender, EventArgs e)
{
Socket tcpClient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPAddress ipaddress = IPAddress.Parse("10.1.230.41");
EndPoint point = new IPEndPoint(ipaddress, 3900);
tcpClient.Connect(point);
}
总的来说就是:新建一个socket对象–>设定目标的IP–>设定目标的端口–>调用connect函数.
连接成功后,理所应当的可以进行收发消息了,其中,接受消息的函数如下
byte[] data = new byte[1024];
//传递一个byte数组,用于接收数据。length表示接收了多少字节的数据
int length = tcpClient.Receive(data);
string message = Encoding.Default.GetString(data, 0, length);//只将接收到的数据进行转化
textBox2.Text += message;//textBox2是我接收消息的文本框
发消息选择使用另一个文本框textBox1,再配上发送按钮button12.
private void button12_Click(object sender, EventArgs e)
{
Socket tcpClient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPAddress ipaddress = IPAddress.Parse("10.1.230.41");
EndPoint point = new IPEndPoint(ipaddress, 3900);
tcpClient.Connect(point);
string message2 = textBox1.Text;//读取用户的输入
//将字符串转化为字节数组,然后发送到服务器端
byte[] data = new byte[1024];
//传递一个byte数组,用于接收数据。length表示接收了多少字节的数据
}
就能够简易的完成简单的端口消息收发了。
2.3来点音乐!
做完它的消息收发后,总感觉跟平时的网游不太一样,想了半天才想起来,别人的登录界面还有音乐可以听,于是准备播放一下背景音乐。
首先,去某网站找了首黑凤梨,下载到了F盘里,记住它的地址(博主下载的是wav格式的音乐)
然后,在代码中插入播放wav后缀音乐的函数
System.Media.SoundPlayer sp = new SoundPlayer();
sp.SoundLocation = @"F:\我的学习\2020-2021\邓紫棋 - 喜欢你.wav";
sp.PlayLooping();
再次点开客户端,悦儿的歌声就有了(不知道该怎么给大家听,反正懂的都懂)
2.4变换背景图片
假如真的是个网游客户端,那么他的宣传画就应该不断变化,点进去就是各种各样的活动了,那么怎么设置图片的变换呢,在这里慢慢摸索.
首先运用到的就是刚刚在用的picturebox,将其SizeMode调整为StretchImage
接下来拖出一个新工具timer,将timer的Enabled改为true,Interval改为3000(意为3000ms、即3S触发一次)
以下为picturebox中的函数
private void pictureBox1_Click(object sender, EventArgs e)
{
System.Windows.Forms.Timer mytimer = new System.Windows.Forms.Timer();
mytimer.Tick += new EventHandler(change);
mytimer.Enabled = true;
mytimer.Interval = 3000;
}
其中,change为博主自己所写的函数,核心内容为(我的四张图片取名很简单)
private void change(object sender, EventArgs e)
{
//i++,实现第i张;
int i = 0;
i++;
string filePath = Application.StartupPath + "\\hello" + i.ToString() + ".jpg";
this.pictureBox1.Image = Image.FromFile(filePath);
//当i=4时,i变为0,然后重新开始;
if (i == 4)
{
i = 0;
}
}
我将需要轮换的图片与启动器放在了一起.
最终再点进去一次
过了3秒
此次作业大功告成!