C#WinForm开发笔记——进程类

一、进程(Process)

  • 我们可以把计算机中每一个运行的应用程序当作是一个进程,而一个进程又是由多个线程组成的。
  • 通过进程可以查看电脑进程状况,打开一些电脑可执行应用程序(如:计算器、绘图本等)。
  • 注意:
    在打开一些非可执行文件时,需要注意自己的环境,如果在.NET Core中,需要将ProcessStartInfo中的UseShellExecute设置为true。而在.NET FrameWork中。该属性默认为true。如不打开,系统会出现如下异常。

    在这里插入图片描述
  • UseShellExecute的默认设置
    在这里插入图片描述
using System;
using System.Diagnostics;

namespace 进程类
{
    
    
    class Program
    {
    
    
        static void Main(string[] args)
        {
    
    
            Process[] pros = Process.GetProcesses();
            foreach (var item in pros)
            {
    
    
                //item.Kill();结束所有进程,猛男建议尝试
                Console.WriteLine(item);
            }

            //通过进程打开一些应用程序
            Process.Start("calc");//打开计算器
            Process.Start("mspaint");//打开绘图本

            //打开浏览器
            #region 方法一
            //ProcessStartInfo psi = new ProcessStartInfo
            //{
    
    
            //    FileName = "http://www.baidu.com",
            //    //在.NET Core中想要打开网页链接需要将此处设为true,因为浏览器并不是可执行文件
            //    UseShellExecute = true   
            //};
            //Process.Start(psi);
            #endregion

            #region 方法二   推荐使用
            ProcessStartInfo psi = new ProcessStartInfo("http://www.baidu.com");
            psi.UseShellExecute = true;
            Process.Start(psi);
            #endregion

            #region 方法三
            //ProcessStartInfo psi = new ProcessStartInfo("msedge", "http://www.baidu.com");
            //psi.UseShellExecute = true;
            //Process pros = new Process();            
            //pros.StartInfo = psi;
            //pros.Start();
            #endregion

            //通过一个进程打开指定的文件
            ProcessStartInfo psi = new ProcessStartInfo(@"C:\Users\Administrator\Desktop\1.txt");
            psi.UseShellExecute = true;
            Process pros = new Process();
            pros.StartInfo = psi;//StartInfo需要一个ProcessStartInfo的对象
            pros.Start();
        }
    }
}

二、线程(Thread)

1、前台线程和后台线程

  • **前台线程:**只有所有的前台线程都关闭才能完成程序关闭
  • **后台线程:**只要所有的前台线程结束,后台线程自动结束

2、多线程

  • 为什么要用多线程?
    1、单线程会带来"假死"现象;
    2、让计算机"同时"做多件事件,节约时间;
    3、多线程可以让程序"同时"处理多个事情;
    4、后台运行程序,提高程序的运行效率,也不会使主界面出现无响应的情况

  • .NET如何实现多线程(线程同步)
    1、编写产生线程所要执行的方法;
    2、引用System.Threading命名空间
    3、实例化Thread类,并传入一个指向线程所要运行方法的委托。(这个时候线程已经产生,但是还没有运行)
    4、调用Thread实例的Start方法,标记该线程可以被CPU执行了,但具体执行时间由CPU决定

  • 在.Net下,不允许跨线程的访问
    在这里插入图片描述

  • 当线程被终止(Abort)后,就无法在重新启动(Start)了
    在这里插入图片描述

  • 线程在未执行完时被关闭,可能会导致系统的资源无法被释放并抛出异常,此时可判断新进程是否为null,如果不是,可手动用Abort将线程终止。
    在这里插入图片描述

  • 线程中如何访问其他控件?
    C#在线程中禁止访问别的控件,但是,可以在程序被加载时取消系统的跨线程检查;

 private void Form1_Load(object sender, EventArgs e)
{
    
    
    Control.CheckForIllegalCrossThreadCalls = false;
}
  • 线程中如何访问带参数的方法?
    1、如果线程执行的方法需要参数,那么要求这个参数必须时object类型;
    2、参数在Start中放入。

3、Thread类的一些重要成员

  • Start() 启动线程:告诉CPU该线程可以被执行,具体什么时候执行,由CPU决定
  • Abort() 终止线程:直至完成之后不能再Start();
  • Thread.Sleep():静态方法,可以使当前线程停止一段时间运行;
  • Name:线程名
  • Thread.CurrentThread:获得当前的线程引用

三、Socket网络编程

  • 人通过【电话】可以通信
    程序通过【Socket】来通信
    套接字就是程序间的电话机
  • 人和人直接打电话      ~~~~     电话      ~~~~      规定好的语言(如普通话)
    电脑和电脑进行联系      ~~~~     Socket      ~~~~      协议(如HTTP、TCP、UDP)

1、Socket相关概念

  • socket:作为进程通信机制,通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄(其实就是两个程序通信用的)
    理解:假设客户端想要和服务器的某个应用程序进行联系,就需要知道服务器的IP地址,但服务器中的IP地址都一样,想要与具体的应用程序通信,此时就需要端口号。

  • 端口:在Internet上有很多这样的主机,这些主机一般运行了多个服务软件,同时提供几种服务,每种服务都打开一个Socket,并绑定到一个端口上,不同的端口对应于不同的服务(应用程序);
    ----例如:http使用80端口、ftp使用21端口、smtp使用25端口(我们一般使用50000以后的端口)

  • Socket具有两种类型:
    1、流式Socket(STREAM):
    ----是一种面向连接的Socket,针对于面向连接的TCP服务应用,安全,但效率低;
    2、数据报式Socket(DATAGRAM):
    ----式一种无连接的Socket,对应于无连接的UDP服务应用,不安全(对视,顺序混乱,在连接端要分析重排及要求重发),但效率高

  • 注意:
    1、一个Socket一次智能连接一台主机
    2、Socket关闭后无法再次使用
    3、每个Socket对象只能一台远程主机连接,如果你想连接到多台远程主机,你必须创建多个Socket对象

  • 更贴切的理解,请点击我的另外一篇文章.

2、Socket一般应用模式

在这里插入图片描述
也可用下面这个更直观的理解
在这里插入图片描述

  • 服务端的Socket(至少需要两个)
    1、一个负责接收客户端连接请求(但不负责与客户端通信)
    2、每成功接收到一个客户端的连接,便在服务端产生一个对应的负责通信的Socket

    ----在接收到客户端连接时创建
    ----为每个连接层高的哭护短请求在服务端都创建一个对应的Socket(负责和客户端通信)
  • 客户端的Socket
    1、必须指定要连接的服务器地址和端口
    2、通过创建一个Socket对象来初始化一个到服务器端的TCP连接

3、Socket通信基本流程图

在这里插入图片描述

四、案例

1、摇奖机

在这里插入图片描述

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace 摇奖机
{
    
    
    public partial class Form1 : Form
    {
    
    
        public Form1()
        {
    
    
            InitializeComponent();
        }
        bool b = false;
        private void button1_Click(object sender, EventArgs e)
        {
    
    
            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;
        }
    }
}

2、Socket网络编程

在这里插入图片描述

在这里插入图片描述

1>服务器端

  • a、创建一个负责监听的Socket

Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

参数含义:
1、AddressFamily
在这里插入图片描述
2、SocketType
在这里插入图片描述
3、ProtocolType
在这里插入图片描述

  • b、创建IP地址和端口号对象
//创建IP地址          
IPAddress ip = IPAddress.Any;//IPAddress.Parse(txtServe.Text);
//创建端口号对象   
IPEndPoint point = new IPEndPoint(ip, Convert.ToInt32(txtPort.Text));
  • c、让负责监听的Socket绑定IP地址跟端口号
//让负责监听的Socket绑定IP地址跟端口号
socketListen.Bind(point);
  • e、设置监听队列:在某一个时间点内能够连入服务端的最大客户端数量
//设置监听队列:在某一个时间点内能够连入服务端的最大客户端数量
socketListen.Listen(10);
  • f、 负责监听的Socket 来接收客户端的连接,同时创建跟客户端通信的socket
//负责监听的Socket 来接收客户端的连接 创建跟客户端通信的socket
Socket socketSend = socketListen.Accept();//返回的socket为接收信息的eSocket
  • g、接收客户端发来的信息
byte[] buffer = new byte[1024 * 1024 * 2];
int r = socketSend.Receive(buffer);

2>客户端

  • a、创建一个负责和客户端通信的Socket
//在客户端创建一个负责跟客户端通信使用的socket
Socket socketSend = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
  • b、获得想要通信的服务器的IP地址和端口号
//获得要连接的服务器的IP地址
IPAddress ip = IPAddress.Parse(tbIP.Text);
//获得要连接服务器的端口号
IPEndPoint point = new IPEndPoint(ip, Convert.ToInt32(tbCOM.Text));
  • c、客户端负责通信的Socket去连接服务端的IP地址跟端口号
socketSend.Connect(point);
  • d、客户端给服务器发送信息
//获得客户端想要发送的信息
string str = txtMsg.Text.Trim();
byte[] buffer = Encoding.UTF8.GetBytes(str);
socketSend.Send(buffer);
  • e、接收服务器发送的信息
byte[] buffer = new byte[1024 * 1024 * 2];
int r = socketSend.Receive(buffer);

3>自定义"协议"

  • 当客户端或者服务器想要给对方发送文档时,该文档可能是文件,也可使是字符串文本,因此,可以通过自定义的协议来完成区分文档类型
    1、把要传递的字节数组签名都加上一个字节作为标识(比如:0:表示文字,1:表示文件)
    2、经过以上操作,传输的文字流就变成了:0 + 文字(字节数组表示);
    传输的文件就变成了:1+文件的二进制信息;
    3、接收信息时,就可以通过第一个字节来区分文档,同时从第二个字节开始保存或输出文档;
  • 除了区分这种大的文档形式外,还可以通过自定义协议区分文件的类型(比如在文件的字节数组中在添加一个标识,作为文件的分类标识)

4>代码

a、服务器

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace Server
{
    
    
    public partial class Form1 : Form
    {
    
    
        public Form1()
        {
    
    
            InitializeComponent();
        }

        private void btnListen_Click(object sender, EventArgs e)
        {
    
    
            try
            {
    
    
            //创建一个负责监听的Socket
            Socket socketListen = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            //创建IP地址          
            IPAddress ip = IPAddress.Any;//IPAddress.Parse(txtServe.Text);
            //创建端口号对象   
            IPEndPoint point = new IPEndPoint(ip, Convert.ToInt32(txtPort.Text));
            //让负责监听的Socket绑定IP地址跟端口号
            socketListen.Bind(point);
            ShowMsg("监听成功");
            //设置监听队列:在某一个时间点内能够连入服务端的最大客户端数量
            socketListen.Listen(10);
            //开启新的线程来执行Listen方法
            Thread th1 = new Thread(Listen);
            th1.IsBackground = true;
            th1.Start(socketListen);
            }
            catch
            {
    
    

            }

        }

        void ShowMsg(string str)
        {
    
    
            txtLog.AppendText(str + "\r\n");
        }

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

        /// <summary>
        /// 监听客户端请求 并创建与之通信的Socket
        /// </summary>
        /// <param name="obj">负责监听的Socket,因为要放入线程,所以参数必须为object类型</param>
        void Listen(object obj)
        {
    
    
            Socket socketListen = obj as Socket;//里氏转换
            while (true)
            {
    
    
                try
                {
    
    
                    //负责监听的Socket 来接收客户端的连接 创建跟客户端通信的socket
                    socketSend = socketListen.Accept();//返回的socket为接收信息的eSocket
                    dicSocket.Add(socketSend.RemoteEndPoint.ToString(), socketSend);
                    //将远程连接的客户端的IP地址和端口号存储在下拉框中
                    cboUsers.Items.Add(socketSend.RemoteEndPoint.ToString());
                    ShowMsg(socketSend.RemoteEndPoint.ToString() + "连接成功");//获得远程通信的客户端的IP地址和端口号

                    //开启新线程,不停的接收客户端发来的信息
                    Thread th2 = new Thread(Recept);
                    th2.IsBackground = true;
                    th2.Start(socketSend);
                }
                catch 
                {
    
    
                    
                }               
            }
        }        

        /// <summary>
        /// 不停的接收客户端发来的信息
        /// </summary>
        /// <param name="obj"></param>
        private void Recept(object obj)
        {
    
    
            Socket socketSend = obj as Socket;
            while (true)
            {
    
    
                try 
                {
    
     
                    //服务端开始接收客户端发来的数据
                    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.ToString() + ":" + str);
                }
                catch
                {
    
    

                }
            }            
        }

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

            List<byte> list = new List<byte>();
            list.Add(0);
            list.AddRange(buffer);
            //将泛型集合转换为数组
            byte[] newBuffer = list.ToArray();

            string ip = cboUsers.SelectedItem.ToString();
            dicSocket[ip].Send(newBuffer);
        }

        /// <summary>
        /// 选择要发送的文件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnSelect_Click(object sender, EventArgs e)
        {
    
    
            OpenFileDialog ofd = new OpenFileDialog();
            ofd.Title = "请选择您要发送的文件";
            ofd.InitialDirectory = @"C:\Users\Administrator\Desktop";
            ofd.Filter = "文本文件|*.txt|音乐文件|*.wav|所有文件|*.*";
            ofd.ShowDialog();

            txtPath.Text = ofd.FileName;
        }

        /// <summary>
        /// 服务器给客户端发送选中的文件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        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 * 2];
                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(buffer,0,r+1,SocketFlags.None);
            }
        }

        /// <summary>
        /// 发送振动
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnGo_Click(object sender, EventArgs e)
        {
    
    
            byte[] buffer = new byte[1];
            buffer[0] = 2;
            dicSocket[cboUsers.SelectedItem.ToString()].Send(buffer);
        }
    }
}

b、客户端

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace Client
{
    
    
    public partial class Form1 : Form
    {
    
    
        public Form1()
        {
    
    
            InitializeComponent();
        }

        Socket socketSend;
        private void btnConnect_Click(object sender, EventArgs e)
        {
    
    
            try 
            {
    
    
            //在客户端创建一个负责跟客户端通信使用的socket
            socketSend = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            //获得要连接的服务器的IP地址
            IPAddress ip = IPAddress.Parse(tbIP.Text);
            //获得要连接服务器的端口号
            IPEndPoint point = new IPEndPoint(ip, Convert.ToInt32(tbCOM.Text));
            //客户端负责通信的Socket去连接服务端的IP地址跟端口号
            socketSend.Connect(point);
            ShowMsg("连接成功");

            //开启一个新的线程不停的接收服务器发来的信息
            Thread th = new Thread(Recept);
            th.IsBackground = true;
            th.Start();
            }
            catch
            {
    
     }
        }

        void ShowMsg(string str)
        {
    
    
            txtLog.AppendText(str + "\r\n");
        }

        /// <summary>
        /// 客户端给服务器发送信息
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnSent_Click(object sender, EventArgs e)
        {
    
    
            //获得客户端想要发送的信息
            string str = txtMsg.Text.Trim();
            byte[] buffer = Encoding.UTF8.GetBytes(str);
            socketSend.Send(buffer);
        }


        void Recept()
        {
    
    
            while (true)
            {
    
    
                try
                {
    
     
                    byte[] buffer = new byte[1024 * 1024 * 2];
                    int r = socketSend.Receive(buffer);
                    if (r == 0)
                        break;
                    //如果服务器发送的是文本
                    if (buffer[0] == 0)
                    {
    
    
                        string str = Encoding.UTF8.GetString(buffer, 1, r-1);
                        ShowMsg(socketSend.RemoteEndPoint.ToString() + ":" + str);
                    }
                    //如果客户端发送的是文件
                    else if(buffer[0]==1)
                    {
    
    
                        SaveFileDialog sfd = new SaveFileDialog();
                        sfd.Title = "请选择你要保存的路径";
                        sfd.InitialDirectory = @"C:\Users\Administrator\Desktop";
                        sfd.Filter = "文本文件|*.txt|音频文件|*.wav|所有文件|*.*";
                        sfd.ShowDialog();

                        string path = sfd.FileName;
                        using(FileStream fsWrite =new FileStream(path,FileMode.OpenOrCreate,FileAccess.Write))
                        {
    
    
                            fsWrite.Write(buffer, 1, r - 1);
                        }
                        ShowMsg("文件保存成功");
                    }
                    else if(buffer[0]==2)
                    {
    
    
                        ZD();
                    }
                    
                }
                catch
                {
    
     }
            }
        }

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

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

猜你喜欢

转载自blog.csdn.net/Lcl_huolitianji/article/details/121693295
今日推荐