TCP-端口扫描与网游客户端
文章目录
前言
一、单线程端口
1.项目创建
打开vs,选择创建新项目;
选择窗体应用;
创建项目,自定义项目名称与路径;
2.控件设置
控件数量及名称设置;
table × 4个; textbox × 4;个 progressBar × 1 个; button × 1个
界面如下:
点击一下 textbox4 控件,将 ReadOnly 属性设置为 True ,用于显示结果;
其它属性可自定义设置
3.端口扫描
代码编写:
在窗口设计界面内,双击 button 按钮,可以转到代码编辑区;
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();
}
//主机地址
private string hostAddress;
//起始端口
private int start;
//终止端口
private int end;
//端口号
private int port;
//定义线程对象
private Thread scanThread;
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 = i;
}
textBox4.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);
//扫描到则显示到显示框
textBox4.AppendText("端口 " + port + " 开放!" + Environment.NewLine);
}
catch
{
//未扫描到,则会抛出错误
}
}
}
}
执行结果:
注意127.0.0.1
为电脑个人用户的代ip地址;
二、多线程端口
单线程端口与多线程端口扫描前期准备工作相同,这里我们就直接开始多线称端口。
代码编写:
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
{
//未扫描到,则会抛出错误
}
}
}
}
执行结果:
至此,端口扫描就完成了;
三、网游端口
1.前期准备
新建项目,创建一个窗体应用;
添加 WindowsMediaPlayer 控件
首先需要添加 Windows Media Player 控件,后续播放背景音乐需要使用到。
右击 “ 工具箱 ” 内的 “ 常规 ” ,点击 “ 选择项 ” ;
选择 “ COM 组件 ” ,勾选上 “ Windows Media Player ” ,再点击 “ 确定 ” ;
2.界面设计
textbox —— 2个(输入框、显示框)
button —— 3个(发送、进入游戏、退出游戏)
picturebox —— 1个(图片显示)
trackbar —— 1个(音量调节)
label —— 1个(音量显示)
groupbox —— 2个(控件容器)
WindowsMediaPlayer —— 1个(媒体播放器)
设置控件属性:
右击控件,点击属性,即可进入到属性设置界面;
textBox2 属性设置:需要将 Multiline 属性设为 True ,表示为多行文本框;ScrollBars 属性设为 Vertical ,表示垂直滚动条;
trackBar1 属性设置:设置最大值为100,最小值为0,最小改变量为1,用于音量调节;
其它控件属性,按需求进行设置;
界面显示:
3.代码与数据
代码:
双击 “ 连接游戏 ” 按钮,转到代码编辑区。
在 button2_Click 函数体内,编写连接的代码,在函数体外定义两个全局变量,这里我简单写了个去除终端转义字符的函数 strDelete
//分别创建 TcpClient 和 NetworkStream 的对象
TcpClient tcpClient;
NetworkStream stream;
/*****************
* 进入游戏
*****************/
private void button2_Click(object sender, EventArgs e)
{
/*
* 连接服务器
*/
try
{
//实例化
tcpClient = new TcpClient();
//向指定的IP地址的服务器发出连接请求
tcpClient.Connect("10.160.52.106", 3900);
//获取网络传输流
stream = tcpClient.GetStream();
//接受数据并转化为字符串
byte[] data = new byte[1024];
int receive = stream.Read(data, 0, 1024);
string msg = Encoding.Default.GetString(data, 0, receive);
//去除字符串中的终端转义字符
msg = strDelete(msg);
//显示出来
textBox2.AppendText(msg);
}
catch
{
textBox2.AppendText("服务器未启动" + Environment.NewLine);
}
}
/*****************
* 去除终端转移字符
*****************/
private string strDelete(string str)
{
int flag = -1, de = 0;
for (int i = 0; i < str.Length; i++)
{
if (str[i] == '')
{
flag = i;
}
if (flag != -1)
{
de++;
}
if (str[i] == 'm' && flag != -1)
{
str = str.Remove(flag, de);
i = flag - 1;
flag = -1;
de = 0;
}
}
return str;
}
记得添加头文件。
using System.Net.Sockets
运行结果:
数据传输:
在界面设计文件中,双击 “ 发送 ” 按钮,转到编辑代码的文件中,在 button1_Click 函数中编写以下的代码;
private void button1_Click(object sender, EventArgs e)
{
//获取textBox1内的文本内容
string msg = textBox1.Text + "\n";
//将文本内容转化成比特流并发送给服务器
byte[] data = new byte[1024];
data = Encoding.Default.GetBytes(msg);
stream.Write(data, 0, data.Length);
//接收服务器端传来的数据流并转化为字符串
byte[] data1 = new byte[1024];
int receive = stream.Read(data1, 0, 1024);
msg = Encoding.Default.GetString(data1, 0, receive);
//去除字符串中的终端转义字符
msg = strDelete(msg);
//清除显示框之前的内容
textBox2.Clear();
//显示数据
textBox2.AppendText(msg);
//刷新输入框
textBox1.Clear();
//将光标集中到输入框中
textBox1.Focus();
}
运行结果:
4.背景音乐
在构造函数中添加以下的代码,在程序运行之后,设置音量调节器的初始值(50),并将 WindownsMediaPlayer 控件隐藏起来;
public Form1()
{
InitializeComponent();
//设置音量调节器的初始位置
trackBar1.Value = 50;
label1.Text = "50";
axWindowsMediaPlayer1.Hide();
}
在 button1_Click 函数内添加后半部分的代码;
private void button2_Click(object sender, EventArgs e)
{
/*
* 连接服务器
*/
try
{
//实例化
tcpClient = new TcpClient();
//向指定的IP地址的服务器发出连接请求
tcpClient.Connect("10.160.52.106", 3900);
//获取网络传输流
stream = tcpClient.GetStream();
//接受数据并转化为字符串
byte[] data = new byte[1024];
int receive = stream.Read(data, 0, 1024);
string msg = Encoding.Default.GetString(data, 0, receive);
//去除字符串中的终端转义字符
msg = strDelete(msg);
//显示出来
textBox2.AppendText(msg);
}
catch
{
textBox2.AppendText("服务器未启动" + Environment.NewLine);
}
/******************
* 播放背景音乐
******************/
//设置音量键值
trackBar1.Value = 50;
label1.Text = "50";
//字符串存储音乐路径
string s = @"C:\Users\ASUS\Music\damian.mp3";
//设置为循环播放
axWindowsMediaPlayer1.settings.setMode("loop", true);
//设置初始音乐的音量大小(范围:0——100)
axWindowsMediaPlayer1.settings.volume = 50;
//设置播放歌曲的路径
axWindowsMediaPlayer1.URL = s;
}
双击 trackBar1 控件,转到代码编辑区,编写如下的代码;
/*****************
* 音量调节
*****************/
private void trackBar1_Scroll(object sender, EventArgs e)
{
//控制音量大小
axWindowsMediaPlayer1.settings.volume = trackBar1.Value;
//控制音量显示
label1.Text = trackBar1.Value.ToString();
}
运行结果:
5.背景图片
加入一个 timer 控件。
要拖动到窗体上,而不是控件上,使其父类为Forms;
设置 Enabled 为 True ②设置 Interval 为 3000 ,意为 3000 ms = 3 s;
双击 timer1 控件,转到代码编辑区。
在 timer1_Tick 函数内添加如下代码
//定义flag变量
private int flag = 0;
/*****************
* 自动换图
*****************/
private void timer1_Tick(object sender, EventArgs e)
{
flag++;
string picturePath = @"C:\Users\ASUS\Pictures\" + flag + ".jpg";
//设置图片填充
pictureBox1.SizeMode = PictureBoxSizeMode.Zoom;
pictureBox1.Image = Image.FromFile(picturePath);
if (flag == 5)
{
flag = 0;
}
}
运行结果:
下面为总代码:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace GameClient
{
public partial class Form1 : Form
{
private int flag = 0;
TcpClient tcpClient;
NetworkStream stream;
public Form1()
{
InitializeComponent();
//设置音量调节器的初始位置
trackBar1.Value = 0;
label1.Text = "0";
axWindowsMediaPlayer1.Hide();
}
/*****************
* 进入游戏
*****************/
private void button2_Click(object sender, EventArgs e)
{
/*
* 连接服务器
*/
try
{
//实例化
tcpClient = new TcpClient();
//向指定的IP地址的服务器发出连接请求
tcpClient.Connect("10.160.52.106", 3900);
//获取网络传输流
stream = tcpClient.GetStream();
//接受数据并转化为字符串
byte[] data = new byte[1024];
int receive = stream.Read(data, 0, 1024);
string msg = Encoding.Default.GetString(data, 0, receive);
//去除字符串中的终端转义字符
msg = strDelete(msg);
//显示出来
textBox2.AppendText(msg);
}
catch
{
textBox2.AppendText("服务器未启动" + Environment.NewLine);
}
/******************
* 播放背景音乐
******************/
//设置音量键值
trackBar1.Value = 50;
label1.Text = "50";
//字符串存储音乐路径
string s = @"C:\Users\ASUS\Music\damian.mp3";
//设置为循环播放
axWindowsMediaPlayer1.settings.setMode("loop", true);
//设置初始音乐的音量大小(范围:0——100)
axWindowsMediaPlayer1.settings.volume = 50;
//设置播放歌曲的路径
axWindowsMediaPlayer1.URL = s;
}
/*****************
* 去除终端转移字符
*****************/
private string strDelete(string str)
{
int flag = -1, de = 0;
for (int i = 0; i < str.Length; i++)
{
if (str[i] == '')
{
flag = i;
}
if (flag != -1)
{
de++;
}
if (str[i] == 'm' && flag != -1)
{
str = str.Remove(flag, de);
i = flag - 1;
flag = -1;
de = 0;
}
}
return str;
}
/*****************
* 发送数据
*****************/
private void button1_Click(object sender, EventArgs e)
{
//获取textBox1内的文本内容
string msg = textBox1.Text + "\n";
//将文本内容转化成比特流并发送给服务器
byte[] data = new byte[1024];
data = Encoding.Default.GetBytes(msg);
stream.Write(data, 0, data.Length);
//接收服务器端传来的数据流并转化为字符串
byte[] data1 = new byte[1024];
int receive = stream.Read(data1, 0, 1024);
msg = Encoding.Default.GetString(data1, 0, receive);
//去除字符串中的终端转义字符
msg = strDelete(msg);
//清除显示框之前的内容
textBox2.Clear();
//显示数据
textBox2.AppendText(msg);
//刷新输入框
textBox1.Clear();
textBox1.Focus();
}
/*****************
* 自动换图
*****************/
private void timer1_Tick(object sender, EventArgs e)
{
flag++;
string picturePath = @"C:\Users\ASUS\Pictures\" + flag + ".jpg";
//设置图片填充
pictureBox1.SizeMode = PictureBoxSizeMode.Zoom;
pictureBox1.Image = Image.FromFile(picturePath);
if (flag == 5)
{
flag = 0;
}
}
/*****************
* 音量调节
*****************/
private void trackBar1_Scroll(object sender, EventArgs e)
{
//控制音量大小
axWindowsMediaPlayer1.settings.volume = trackBar1.Value;
//控制音量显示
label1.Text = trackBar1.Value.ToString();
}
/*****************
* 退出游戏
*****************/
private void button3_Click(object sender, EventArgs e)
{
if(stream != null)
{
stream.Close();
tcpClient.Close();
}
textBox2.Clear();
//停止播放背景音乐
axWindowsMediaPlayer1.Ctlcontrols.stop();
}
}
}
总结与参考资料
1.总结
单线程与多线程的区别在于单线程是单一的,而多线程就是多个单一线程,在效率方面比单线更高;对于网游端口控件代码就参考资料来的,不会的就百度或者找的同学解决。
2.参考资料
1: 创建控件的线程访问.
2: AxWindowsMediaPlayer控件的属性.
3: C#winform怎样设计定时更换图片.
4: visual studio2010中C#怎么播放MP3背景音乐.