TCP编程与网游客户端
实验环境:Visual Studio 2017 社区版
一.编写端口扫描器程序
单线程
1.新建项目
文件–>新项目–C#窗口应用。
2.设计界面
3.主要代码
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace PortScanner2
{
public partial class Form1 : Form
{
//自定义变量
private int port;
private string Addr;
private bool[] done = new bool[65536];
private int start;
private int end;
//private Thread scanThread;
private bool OK;
public Form1()
{
InitializeComponent();
}
private void textBox2_TextChanged(object sender, EventArgs e)
{
label4.Text = textBox2.Text;
}
private void textBox3_TextChanged(object sender, EventArgs e)
{
label6.Text = textBox3.Text;
}
private void button1_Click(object sender, EventArgs e)
{
//显示端口扫描的范围
progressBar1.Minimum = Int32.Parse(textBox2.Text);
progressBar1.Maximum = Int32.Parse(textBox3.Text);
//显示框初始化
listBox1.Items.Clear();
listBox1.Items.Add("端口扫描器 v1.0.");
listBox1.Items.Add("");
//调用函数PortScan
PortScan();
}
private void PortScan()
{
start = Int32.Parse(textBox2.Text);
end = Int32.Parse(textBox3.Text);
//检查输入范围合法性
if ((start >= 0 && start <= 65536) && (end >= 0 && end <= 65536) && (start <= end))
{
listBox1.Items.Add("开始扫描... (可能需要请您等待几分钟)");
Addr = textBox1.Text;
for (int i = start; i <= end; i++)
{
port = i;
//使用该端口的扫描线程
//scanThread = new Thread(new ThreadStart(Scan));
// scanThread.Start();
//使线程睡眠
// System.Threading.Thread.Sleep(100);
Scan();
progressBar1.Value = i;
label5.Text = i.ToString();
}
//未完成时情况
while (!OK)
{
OK = true;
for (int i = start; i <= end; i++)
{
if (!done[i])
{
OK = false;
break;
}
}
System.Threading.Thread.Sleep(1000);
}
listBox1.Items.Add("扫描结束!");
}
else
{
MessageBox.Show("输入错误,端口范围为[0-65536]");
}
}
private void Scan()
{
int portnow = port;
//创建线程变量
//Thread Threadnow = scanThread;
done[portnow] = true;
//创建TcpClient对象,TcpClient用于为TCP网络服务提供客户端连接
TcpClient objTCP = null;
//扫描端口,成功则写入信息
try
{
//用TcpClient对象扫描端口
objTCP = new TcpClient(Addr, portnow);
listBox1.Items.Add("端口 " + portnow.ToString() + " 开放!");
}
catch
{
}
}
}
}
4.执行结果
多线程
1.在这个解决方案下新建一个项目。
2.设计界面,与单线程类似
3.主要代码
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;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace PortScanner1
{
public partial class Form1 : Form
{
//自定义变量
private int port;
private string Addr;
private bool[] done = new bool[65536];
private int start;
private int end;
private Thread scanThread;
private bool OK;
public Form1()
{
InitializeComponent();
CheckForIllegalCrossThreadCalls = false;//这行代码若不加,执行的时候会报错
}
private void button1_Click(object sender, EventArgs e)
{
//创建线程,并创建ThreadStart委托对象
Thread process = new Thread(new ThreadStart(PortScan));
process.Start();
//显示端口扫描的范围
progressBar1.Minimum = Int32.Parse(textBox2.Text);
progressBar1.Maximum = Int32.Parse(textBox3.Text);
//显示框初始化
listBox1.Items.Clear();
listBox1.Items.Add("端口扫描器 v1.0.");
listBox1.Items.Add("");
}
private void PortScan()
{
start = Int32.Parse(textBox2.Text);
end = Int32.Parse(textBox3.Text);
//检查输入范围合法性
if ((start >= 0 && start <= 65536) && (end >= 0 && end <= 65536) && (start <= end))
{
listBox1.Items.Add("开始扫描... (可能需要请您等待几分钟)");
Addr = textBox1.Text;
for (int i = start; i <= end; i++)
{
port = i;
//使用该端口的扫描线程
scanThread = new Thread(new ThreadStart(Scan));
scanThread.Start();
//使线程睡眠
System.Threading.Thread.Sleep(100);
progressBar1.Value = i;
label6.Text = i.ToString();
}
//未完成时情况
while (!OK)
{
OK = true;
for (int i = start; i <= end; i++)
{
if (!done[i])
{
OK = false;
break;
}
}
System.Threading.Thread.Sleep(1000);
}
listBox1.Items.Add("扫描结束!");
}
else
{
MessageBox.Show("输入错误,端口范围为[0-65536]");
}
}
private void Scan()
{
int portnow = port;
//创建线程变量
Thread Threadnow = scanThread;
done[portnow] = true;
//创建TcpClient对象,TcpClient用于为TCP网络服务提供客户端连接
TcpClient objTCP = null;
//扫描端口,成功则写入信息
try
{
//用TcpClient对象扫描端口
objTCP = new TcpClient(Addr, portnow);
listBox1.Items.Add("端口 " + portnow.ToString() + " 开放!");
}
catch
{
}
}
private void textBox3_TextChanged(object sender, EventArgs e)
{
label5.Text = textBox3.Text;
}
private void textBox2_TextChanged(object sender, EventArgs e)
{
label4.Text = textBox2.Text;
}
}
}
4.执行结果
从二者执行的结果可以看出,使用多线程执行要比单线程执行快的多。
二.编写一个网游客户端,游戏服务器的校园内网IP地址为 10.160.52.106,端口为3900,采用TCP连接
1.新建一个C#窗口项目命名为gametest,步骤与前面一样,这里就不再上图了
2设计游戏客户端界面
(1)添加播放音乐的组件:工具–>选择工具箱–>COM组件
(2)添加窗口控件,鼠标左键点中拖动即可,如果找不到控件在哪里,也可以搜索
(3)将label,button,TextBox,ListBox,label,windowsmediaplayer,pictureBox等控件拖入图形设计界面,其效果如下
(4)改变控件的属性,比如label,button的Text,font等属性
(5)添加图片到imagelist里面:右键imagelist–>选择图像–>如下窗口–>添加–>选择图片即可(图片的size最好一样)
(6)设置pictureBox的属性,这里关系到背景图片切换时的清晰度,ImageSize应与imagelist的第一张相同,colorDepth选择最大值。
(7)另外,可以更改axWindowsMediaPlayer的属性,使之执行时不可见,将Visable的值由原来的true改为false。
(8)更改定时器Timer的属性,使背景图片(picturebox)每30秒切换一次。
3相关代码
(1)连接服务器代码
private NetworkStream stream;
private TcpClient tcpClient = new TcpClient();//创建一个TCP的客户端
public Form1()
{
InitializeComponent();
try
{
tcpClient.Connect("10.160.52.106", 3900);
listBox1.Items.Add("连接成功!");
stream = tcpClient.GetStream();
byte[] data = new byte[1024];
//判断网络流是否可读
if (stream.CanRead)
{
int len = stream.Read(data, 0, data.Length);
//Encoding ToEncoding = Encoding.GetEncoding("UTF-8");
//Encoding FromEncoding = Encoding.GetEncoding("GB2312");
//data=Encoding.Convert(FromEncoding, ToEncoding, data);
//string msg = Encoding.UTF8.GetString(data, 0, data.Length);
string msg = Encoding.Default.GetString(data, 0, data.Length);
string str = "\r\n";
char[] str1 = str.ToCharArray();
string[] msg1 = msg.Split(str1);
for (int j = 0; j < msg1.Length; j++)
{
listBox1.Items.Add(msg1[j]);
}
}
}
catch
{
listBox1.Items.Add("服务器未启动!");
}
}
(2)发送消息的代码
private void button1_Click(object sender, EventArgs e)
{
if (tcpClient.Connected)
{
//向服务器发送数据
string msg = textBox1.Text;
Byte[] outbytes = System.Text.Encoding.Default.GetBytes(msg + "\n");
stream.Write(outbytes, 0, outbytes.Length);
byte[] data = new byte[1024];
//接收服务器回复数据
if (stream.CanRead)
{
int len = stream.Read(data, 0, data.Length);
string msg1 = Encoding.Default.GetString(data, 0, data.Length);
string str = "\r\n";
char[] str1 = str.ToCharArray();
string[] msg2 = msg1.Split(str1);
for (int j = 0; j < msg2.Length; j++)
{
listBox1.Items.Add(msg2[j]);
}
}
else
{
listBox1.Items.Add("连接已断开");
}
}
}
(4)播放背景音乐的代码
//背景音乐的播放
private void button12_Click(object sender, EventArgs e)
{
try
{
// String m = @"baizhanchengshi.mp3";
String m=@"E:\MicrosoftVisualStudio\Gametest\Gametest\baizhanchengshi.mp3";
axWindowsMediaPlayer1.URL = m;
}
catch
{
listBox1.Items.Add("背景音乐播放失败");
}
}
private void button13_Click(object sender, EventArgs e)
{
axWindowsMediaPlayer1.Ctlcontrols.pause();
}
(5)背景图片的自动切换
/*
背景图片的自动切换
*/
private int im = 0;
private void timer1_Tick(object sender, EventArgs e)
{
//this.BackgroundImage = imageList1.Images[im++ % 5];
//pictureBox1.SizeMode = PictureBoxSizeMode.Zoom;
pictureBox1.SizeMode = PictureBoxSizeMode.StretchImage;
pictureBox1.Image = imageList1.Images[im++ % 5];
//pictureBox1.SizeMode = PictureBoxSizeMode.StretchImage;
//groupBox1.BackgroundImageLayout = ImageLayout.Stretch;
//this.BackgroundImageLayout = ImageLayout.Zoom;
}
4.form.cs全部代码
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 Gametest
{
public partial class Form1 : Form
{
private NetworkStream stream;
private TcpClient tcpClient = new TcpClient();
public Form1()
{
InitializeComponent();
try
{
tcpClient.Connect("10.160.52.106", 3900);
listBox1.Items.Add("连接成功!");
stream = tcpClient.GetStream();
byte[] data = new byte[1024];
//判断网络流是否可读
if (stream.CanRead)
{
int len = stream.Read(data, 0, data.Length);
//Encoding ToEncoding = Encoding.GetEncoding("UTF-8");
//Encoding FromEncoding = Encoding.GetEncoding("GB2312");
//data=Encoding.Convert(FromEncoding, ToEncoding, data);
//string msg = Encoding.UTF8.GetString(data, 0, data.Length);
string msg = Encoding.Default.GetString(data, 0, data.Length);
string str = "\r\n";
char[] str1 = str.ToCharArray();
string[] msg1 = msg.Split(str1);
for (int j = 0; j < msg1.Length; j++)
{
listBox1.Items.Add(msg1[j]);
}
}
}
catch
{
listBox1.Items.Add("服务器未启动!");
}
}
private void button1_Click(object sender, EventArgs e)
{
if (tcpClient.Connected)
{
//向服务器发送数据
string msg = textBox1.Text;
Byte[] outbytes = System.Text.Encoding.Default.GetBytes(msg + "\n");
stream.Write(outbytes, 0, outbytes.Length);
byte[] data = new byte[1024];
//接收服务器回复数据
if (stream.CanRead)
{
int len = stream.Read(data, 0, data.Length);
string msg1 = Encoding.Default.GetString(data, 0, data.Length);
string str = "\r\n";
char[] str1 = str.ToCharArray();
string[] msg2 = msg1.Split(str1);
for (int j = 0; j < msg2.Length; j++)
{
listBox1.Items.Add(msg2[j]);
}
}
else
{
listBox1.Items.Add("连接已断开");
}
}
}
//背景音乐的播放
private void button12_Click(object sender, EventArgs e)
{
try
{
// String m = @"baizhanchengshi.mp3";
String m=@"E:\MicrosoftVisualStudio\Gametest\Gametest\baizhanchengshi.mp3";
axWindowsMediaPlayer1.URL = m;
}
catch
{
listBox1.Items.Add("背景音乐播放失败");
}
}
private void button13_Click(object sender, EventArgs e)
{
axWindowsMediaPlayer1.Ctlcontrols.pause();
}
/*
背景图片的自动切换
*/
private int im = 0;
private void timer1_Tick(object sender, EventArgs e)
{
//this.BackgroundImage = imageList1.Images[im++ % 5];
//pictureBox1.SizeMode = PictureBoxSizeMode.Zoom;
pictureBox1.SizeMode = PictureBoxSizeMode.StretchImage;
pictureBox1.Image = imageList1.Images[im++ % 5];
//pictureBox1.SizeMode = PictureBoxSizeMode.StretchImage;
//groupBox1.BackgroundImageLayout = ImageLayout.Stretch;
//this.BackgroundImageLayout = ImageLayout.Zoom;
}
//关闭连接
private void button2_Click(object sender, EventArgs e)
{
tcpClient.Close();
listBox1.Items.Add("已断开连接");
}
}
}
5.执行结果
总结
这次练习加深了我对C#From的了解,对各种控件更加的熟悉了,如果有什么不对的地方,望指出,感谢