C#基础学习笔记(十五)

C#基础学习笔记(十五)

1.复习

在这里插入图片描述

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }
    //用来存储音乐文件的全路径
    List<string> listSongs = new List<string>();
    private void button1_Click(object sender, EventArgs e)
    {
        OpenFileDialog openFileDialog = new OpenFileDialog();
        openFileDialog.Title = "请选择音乐文件";
        openFileDialog.InitialDirectory = @"D:\示例图片";
        openFileDialog.Multiselect = true;
        openFileDialog.Filter = "音乐文件|*.wav|所有文件|*.*";
        openFileDialog.ShowDialog();
        //获得选择文件夹中的选择的文件
        string[] path = openFileDialog.FileNames;
        for (int i = 0; i < path.Length; i++)
        {
            listBox1.Items.Add(Path.GetFileName(path[i]));
            listSongs.Add(path[i]);
        }
    }
    SoundPlayer soundPlayer = new SoundPlayer();
    private void listBox1_DoubleClick(object sender, EventArgs e)
    {
        soundPlayer.SoundLocation = listSongs[listBox1.SelectedIndex];
        soundPlayer.Play();
    }

    private void button3_Click(object sender, EventArgs e)
    {
        //获取当前选中歌曲的索引
        int index = listBox1.SelectedIndex;
        index++;
        if (index == listBox1.Items.Count) 
        {
            index = 0;
        }
        //将改变后的索引重新的赋值给当前选中项的索引
        listBox1.SelectedIndex = index;
        soundPlayer.SoundLocation = listSongs[index];
        soundPlayer.Play();
    }

    private void button2_Click(object sender, EventArgs e)
    {
        int index = listBox1.SelectedIndex;
        index--;
        if (index < 0) 
        {
            index = listBox1.Items.Count - 1;
        }
        //将改变后的索引重新的赋值给当前选中项的索引
        listBox1.SelectedIndex = index;
        soundPlayer.SoundLocation = listSongs[index];
        soundPlayer.Play();
    }
}

2.线程和进程的复习

2.1 Thread类

  • Start(); 启动线程
  • Abort(); 终止线程,而且不能再Start

2.2 线程中如何访问控件

//取消跨线程的访问
Control.CheckForIllegalCrossThreadCalls = false;

2.3 执行带参数的方法

如果线程执行的方法需要参数,那么要求这个参数必须是object类型。

3.摇奖机

在这里插入图片描述

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }
    bool b = false;
    private void button1_Click(object sender, EventArgs e)
    {
        //PlayGame();
        if (b == false) 
        {
            b = true;
            button1.Text = "停止";
            Thread th = new Thread(PlayGame);
            th.IsBackground = true;
            th.Start();
        }
        else
        {
            b = false;
            button1.Text = "开始";
        }
    }
    private void PlayGame()
    {
        Random r = new Random();
        while (b)
        {
            label1.Text = r.Next(0, 10).ToString();
            label2.Text = r.Next(0, 10).ToString();
            label3.Text = r.Next(0, 10).ToString();
        }
    }

    private void Form1_Load(object sender, EventArgs e)
    {
        Control.CheckForIllegalCrossThreadCalls = false;
    }
}

4.SOCKET网络编程

4.1 概述

人通过【电话】可以通讯

程序通过【Socket】来通讯

Socket就是程序间的电话机

  • 我和其他人打电话 电话 规定好的语言
  • 电脑和电脑进行联系 协议UDP/TCP

4.2 Socket相关概念

  • socket的英文原义是“孔”或“插座”。作为进程通信机制,取后一种意思。通常也称作“套接字”,用于描述IP地址和端口,是一个通信链的句柄。(其实就是两个程序通信用的。)
  • socket非常类似于电话插座。以一个电话网为例。电话的通话双方相当于相互通信的2个程序,电话号码就是IP地址。任何用户在通话之前,首先要占有一部电话机,相当于申请一个socket;同时要知道对方的号码,相当于对方有一个固定的socket。然后向对方拨号呼叫,相当于发出连接请求。对方假如在场并空闲,拿起电话话筒,双方就可以正式通话,相当于连接成功。双方通话的过程,是一方向电话机发出信号和对方从电话机接收信号的过程,相当于向socket发送数据和从socket接收数据。通话结束后,一方挂起电话机相当于关闭socket,撤消连接。

在这里插入图片描述

可以结合找人的示例,形象的理解,服务器端的门卫(负责监听的Sockt),知道了访问请求就会创建一个负责通讯的Socket

4.3 Socket相关概念[端口]

  • 在Internet上有很多这样的主机,这些主机一般运行了多个服务软件,同时提供几种服务。每种服务都打开一个Socket,并绑定到一个端口上,不同的端口对应于不同的服务(应用程序)。

  • 例如:http 使用80端口 ftp使用21端口 smtp 25端口

  • 有两种类型:50000

    • 流式Socket(STREAM):
      是一种面向连接的Socket,针对于面向连接的TCP服务应用,安全,但是效率低;

    • 数据报式Socket(DATAGRAM):
      是一种无连接的Socket,对应于无连接的UDP服务应用.不安全(丢失,顺序混乱,在接收端要分析重排及要求重发),但效率高.

一般使用的就是TCP,会有3次握手

客户端:你有空吗?

服务端:我有空

客户端:我知道你有空了

安全稳定,但是效率慢

UDP快速,效率高,但是不稳定,容易发生数据丢失

4.4 Socket一般应用模式(服务器端和客户端)

在这里插入图片描述

1.服务端welcoming socket 开始监听端口(负责监听客户端连接信息)

2.客户端client socket连接服务端指定端口(负责接收和发送服务端消息)

3.服务端welcoming socket 监听到客户端连接,创建connection socket。(负责和客户端通信)

在这里插入图片描述

示例:

服务器:

在这里插入图片描述

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }
    /*
            服务端                               客户端 
            |                                   |
        Socket()                                |
            |                                   |
        Bind()绑定监听端口                        |
            |                                   |
        Listen()设置监听队列                      |
            |                                   |
        while{Accept()}循环等待客户端连接<———————>Connect()建立连接
            |                                   |
        Receive()<—————————————————————————————Sned()发送数据         
            |                                   |
        Send()———————————————————————————————>Receive()接收数据
            |                                   |
        捕捉异常<——————————————————————————————Close()发送数据                                
            |
        Close()
    */
    private void btnStart_Click(object sender, EventArgs e)
    {
        try
        {
            //创建一个负责监听的
            //SocketType是流式的Stream 对应的就是tcp
            //数据报式DATAGRAM 对于的是UTP
            Socket socketWatch = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            //创建IP地址和端口号对象
            //不要写死,要不然更换的时候就不好用了
            IPAddress ip = IPAddress.Any;//IPAddress.Parse(txtServer.Text);
            IPEndPoint point = new IPEndPoint(ip, Convert.ToInt32(txtPort.Text));
            //让负责监听的Socket绑定IP地址和端口号
            socketWatch.Bind(point);
            ShowMsg("监听成功");
            //设置监听队列 就是同一时间可以链接的最大客户端数量
            socketWatch.Listen(10);

            Thread th = new Thread(Listen);
            th.IsBackground = true;
            th.Start(socketWatch);
        }
        catch (Exception)
        {

            throw;
        }
    }
    /// <summary>
    /// 等待客户端的连接 并且创建与之通信用的Socket
    /// </summary>
    /// <param name="o">线程带参数,进来强转</param>
    Socket socketSend;
    void Listen(object o)
    {
        Socket socketWatch=o as Socket;
        //负责监听的Socket来接受客户端的连接,创建跟客户端通信的Socket
        while (true)
        {
            try
            {
                //负责跟客户端通信的Socket
                socketSend = socketWatch.Accept();
                //将远程连接的客户端的IP的地址和Socket存入集合
                dicSocket.Add(socketSend.RemoteEndPoint.ToString(), socketSend);
                //将远程连接的客户端的IP地址和端口号存储下拉框中
                cboUsers.Items.Add(socketSend.RemoteEndPoint.ToString());
                ShowMsg(socketSend.RemoteEndPoint.ToString() + "连接成功");
                //开启一个新线程不停的接受客户端发送过来的消息
                Thread th = new Thread(Recive);
                th.IsBackground = true;
                th.Start(socketSend);
            }
            catch (Exception)
            {

                throw;
            }
        }
    }

    //将远程连接的客户端的IP的地址和Socket存入集合
    Dictionary<string, Socket> dicSocket = new Dictionary<string, Socket>();

    /// <summary>
    /// 服务器不停的接受客户端发过来的信息
    /// </summary>
    /// <param name="o">线程带参数</param>
    void Recive(object o)
    {
        Socket socketSend = o as Socket;
        while (true)
        {
            try
            {
                //写在Listen里边执行一边以后会等待新的接受,单独写一个方法循环
                //客户端连接后,服务器应该接受客户端发来的消息
                byte[] buffer = new byte[1024 * 1024 * 2];
                //实际接收到的有效字节数
                int r = socketSend.Receive(buffer);
                if (r == 0) break;
                string str = Encoding.UTF8.GetString(buffer, 0, r);
                ShowMsg(socketSend.RemoteEndPoint + ":" + str);
            }
            catch (Exception)
            {

                throw;
            }

        }
    }

    /// <summary>
    /// 显示信息
    /// </summary>
    /// <param name="str"></param>
    void ShowMsg(string str)
    {
        txtLog.AppendText(str + "\r\n");
    }

    private void Form1_Load(object sender, EventArgs e)
    {
        Control.CheckForIllegalCrossThreadCalls = false;
    }
    /// <summary>
    /// 服务器给客户端发送消息
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void btnSend_Click(object sender, EventArgs e)
    {
        string str = txtMsg.Text;
        byte[] buffer = System.Text.Encoding.UTF8.GetBytes(str);

        //现在想要实现其他的功能 在这些buffer前面加上定义的标识符 
        List<byte> list = new List<byte>();
        list.Add(0);
        list.AddRange(buffer);
        //将泛型集合转换为数组
        buffer = list.ToArray();
        //byte[] newBuffer = list.ToArray();

        //socketSend.Send(buffer);
        //获得用户在下拉框选中的IP地址
        string ip = cboUsers.SelectedItem.ToString();
        dicSocket[ip].Send(buffer);
    }
    /// <summary>
    /// 选择要发送的文件
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void btnSelect_Click(object sender, EventArgs e)
    {
        OpenFileDialog ofd = new OpenFileDialog();
        ofd.InitialDirectory = @"D:\示例图片";
        ofd.Title = "请选择要发送的文件";
        ofd.Filter = "所有文件|*.*";
        ofd.ShowDialog();
        txtPath.Text = ofd.FileName;
    }

    private void btnSendFile_Click(object sender, EventArgs e)
    {
        //获得要发送文件的路径
        string path = txtPath.Text;
        using (FileStream fsRead = new FileStream(path, FileMode.Open, FileAccess.Read)) 
        {
            byte[] buffer = new byte[1024 * 1024 * 5];
            int r = fsRead.Read(buffer, 0, buffer.Length);

            List<byte> list = new List<byte>();
            list.Add(1);
            list.AddRange(buffer);
            byte[] newbuffer = list.ToArray();
                
            dicSocket[cboUsers.SelectedItem.ToString()].Send(newbuffer, 0, r + 1, SocketFlags.None);
        }
    }
    /// <summary>
    /// 发送震动
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void btnZD_Click(object sender, EventArgs e)
    {
        byte[] buffer = new byte[1];
        buffer[0] = 2;
        dicSocket[cboUsers.SelectedItem.ToString()].Send(buffer);
    }
}

客户端:

在这里插入图片描述

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }
    Socket socketSend;
    private void btnStart_Click(object sender, EventArgs e)
    {
        try
        {
            //创建负责通信的Socket
            socketSend = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            IPAddress ip = IPAddress.Parse(txtServer.Text);
            IPEndPoint point = new IPEndPoint(ip, Convert.ToInt32(txtPort.Text));
            //获得要连接的远程服务器应用程序的IP地址和端口号
            socketSend.Connect(point);
            ShowMsg("连接成功");

            //开启一个新的线程不停的接受服务端发来的消息
            Thread th = new Thread(Recive);
            th.IsBackground = true;
            th.Start();
        }
        catch (Exception)
        {

            throw;
        }
    }
    /// <summary>
    /// 不停的接受服务器发来的消息
    /// </summary>
    void Recive()
    {
        while (true)
        {
            try
            {
                byte[] buffer = new byte[1024 * 1024 * 3];
                //实际接收到的有效字节
                int r = socketSend.Receive(buffer);
                if (r == 0)
                {
                    break;
                }
                //表示发送的文字消息
                if (buffer[0] == 0)
                {
                    string s = Encoding.UTF8.GetString(buffer, 1, r - 1);
                    ShowMsg(socketSend.RemoteEndPoint + ":" + s);
                }
                else if (buffer[0] == 1)
                {
                    SaveFileDialog sfd = new SaveFileDialog();
                    sfd.InitialDirectory = @"D:\示例图片\测试";
                    sfd.Title = "请选择要保存的文件";
                    sfd.Filter = "所有文件|*.*";
                    sfd.ShowDialog(this);
                    string path = sfd.FileName;
                    using (FileStream fsWrite = new FileStream(path, FileMode.OpenOrCreate, FileAccess.Write))
                    {
                        fsWrite.Write(buffer, 1, r - 1);
                    }
                    MessageBox.Show("保存成功");
                }
                else if (buffer[0] == 2) 
                {
                    ZD();
                }
            }
            catch (Exception)
            {

                throw;
            }
        }
    }
    /// <summary>
    /// 震动
    /// </summary>
    void ZD()
    {
        for (int i = 0; i < 500; i++)
        {
            this.Location = new Point(200, 200);
            this.Location = new Point(280, 280);
        }
    }

    void ShowMsg(string str)
    {
        txtLog.AppendText(str + "\r\n");
    }
    /// <summary>
    /// 客户端给服务器发送消息
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void btnSend_Click(object sender, EventArgs e)
    {
        string str = txtMsg.Text.Trim();
        byte[] buffer = System.Text.Encoding.UTF8.GetBytes(str);
        socketSend.Send(buffer);
    }

    private void Form1_Load(object sender, EventArgs e)
    {
        Control.CheckForIllegalCrossThreadCalls = false;
    }
}
  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值