TCP编程-端口扫描器与网游客户端

c#单线程和多线程的应用比较

准备工作

新建工程(环境为visual studio 2019)
选择Windows窗体应用
在这里插入图片描述
之后的界面输入项目的名称,并选择代码的存储路径,完成后点击创建。
在这里插入图片描述
安放控件
需要的控件为:label、textbox、progressBar、button
实际效果为:
在这里插入图片描述
将texbox4的readonly属性修改为true,意思为该文本框只读不改,仅显示结果

单线程

摆放完成之后右键按键,选择查看代码,在代码框内输入

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
            {
                //未扫描到,则会抛出错误
            }
        }
    }
}

执行结果如下:
在这里插入图片描述

多线程

在单线程代码框内将代码替换为如下:

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
            {
                //未扫描到,则会抛出错误
            }
        }
    }
}

显示为:
在这里插入图片描述

由此可见多线程比单线程快很多

c#编写网游客户端连接游戏服务器

准备工作

选择Windows窗体应用

在这里插入图片描述
添加Windowsmediaplayer控件
在这里插入图片描述
选择COM控件,勾选Windows media player,点击确认
在这里插入图片描述
界面设计如下·:
在这里插入图片描述

连接服务器

在代码去中输入:

//分别创建 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;
}

结果为:
在这里插入图片描述

传输数据

在界面设计文件中,双击 “ 发送 ” 按钮,转到编辑代码的文件中,在 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();
}

结果为
在这里插入图片描述

播放背景音乐

在构造函数添加如下代码:

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();
}

结果为:
在这里插入图片描述

变换图片

在 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();
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值