C#知识点-13(进程、多线程、使用Socket实现服务器与客户端通信)

进程

定义:每一个正在运行的应用程序,都是一个进程 
进程不等于正在运行的应用程序。而是为应用程序的运行构建一个运行环境

            Process[] pros = Process.GetProcesses();//获取电脑中所有正在运行的进程

            //通过进程,直接打开文件
            //告诉进程,要打开的文件路径,通过PSI对象进行封装
            ProcessStartInfo psi = new ProcessStartInfo(@"C:\Users\ThinkPad\Desktop\1.txt");
            Process p = new Process();
            p.StartInfo = psi;
            p.Start();

多线程

        private void button1_Click(object sender, EventArgs e)
        {
            Test();
        }
        private void Test()
        {
            for (int i = 0; i < 100000; i++)
            {
                textBox1.Text = i.ToString();
            }
        }

这段代码在执行完成之前,程序会被卡死(不能操作程序,包括关闭窗口)。因为我们程序在做一些耗时操作的时候,如果主线程去执行某段代码,就没有其余的“精力”去完成其他的操作了。
这时候,我们就需要用到多线程,再新建一个线程来完成耗时操作

        private void button1_Click(object sender, EventArgs e)
        {
            Thread th = new Thread(Test);
            th.Start();
        }
        private void Test(object str)//如果线程执行的方法,需要参数,我们要求参数的类型必须是object类型
        {
            for (int i = 0; i < 100000; i++)
            {
                textBox1.Text = i.ToString();
            }
        }

但是使用多线程,也会有很多需要注意的地方。这段代码执行时会提示异常,显示“线程间操作无效: 从不是创建控件“textBox1”的线程访问它。”
因为创建textBox1的是主线程,而你创建了一个新的线程th,th调用Test方法会访问主线程创建的控件,这个操作默认是不允许的,我们不允许跨线程的访问,因为这是不安全的。

而如果强制要跨线程访问的话,使用下面这段代码在主窗体加载的时候

        private void Form1_Load(object sender, EventArgs e)
        {
            //取消跨线程访问的检查
            Control.CheckForIllegalCrossThreadCalls = false;
        }

但是这样还是有问题,当你运行程序的时候,点击按钮开始计数。如果你在计数途中点击叉号关闭程序,程序还是再运行。这是因为你关闭了主线程(主窗体),但是另一个线程th还在执行。
这时候我们把th这个线程由前台线程转换为后台线程。
前台线程:只有所有的前台线程关闭,程序才关闭
后台线程:只要所有的前台线程结束,后台线程自动结束

        private void button1_Click(object sender, EventArgs e)
        {
            Thread th = new Thread(Test);
            th.IsBackground = true;//将th线程设置为后台线程
            th.Start();
        }

这时候,没有完成计数时关闭程序后会显示异常“创建窗口句柄时出错。”这是因为关闭程序的时候,主窗体这个前台线程关闭了,程序会调用Dispose这个方法进行线程的资源释放。但是Test方法可能还没执行完,还在使用主线程提供的textBox1这个空间资源,这时候Test方法发现找不到这个资源了,程序就会抛异常。
按理说不是已经把th变成后台线程了吗,不是只要所有的前台线程结束,后台线程就结束吗?为什么还是会抛这个异常。原因是我们的cpu不一定能及时的解决处理线程的操作,因为线程是告诉cpu,“我这个线程准备好了,随时可以操作”,但是具体啥时候操作,程序员说了不算,还要看cpu的“心情”。
我们想让程序不抛这个异常,只能是在关闭窗口的时候,强制关闭后台线程

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            th.Abort();//程序关闭时,强制后台线程关闭
        }

使用Socket实现服务器与客户端之间的通信

服务器:
服务器样式截图:

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 btnStart_Click(object sender, EventArgs e)
        {
            //1、创建一个监听连接的Socket对象socketWatch,使用IPv4,流式传输,Tcp协议
            Socket socketWatch = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            //2、创建一个ip地址
            IPAddress ip = IPAddress.Parse(txtServer.Text);
            //2.1、创建一个端口号
            IPEndPoint point = new IPEndPoint(ip,int.Parse(txtPort.Text));
            //3、将端口号绑定到socketWatch
            socketWatch.Bind(point);
            //4、设置监听队列(同一时刻最多有几台设备同时连接)
            socketWatch.Listen(10);
            ShowMsg("正在等待客户端的连接");
            //5、创建一个新线程th,创建线程用于使用新创建的Socket
            Thread th = new Thread(MyAccept);
            //6、设置th为后台线程
            th.IsBackground = true;
            //7、开启线程th
            th.Start(socketWatch);
        }

        //客户端的IP地址&端口号,服务器与客户端通讯的Socket
        Dictionary<string,Socket> dicSocket = new Dictionary<string,Socket>();
        /// <summary>
        /// 实现客户端与服务器的通讯
        /// </summary>
        /// <param name="o"></param>
        void MyAccept(object o)
        {
            //不停的接收客户端的连接
            while (true)
            {
                //o墙砖为Socket
                Socket socketWatch = o as Socket;
                //为新建连接创建新的与之通信的Socket
                Socket socketTX = socketWatch.Accept();
                //把客户端的IP地址&端口号和与客户端通信的Socket存储到键值对集合中
                dicSocket.Add(socketTX.RemoteEndPoint.ToString(), socketTX);
                //把客户端的ip地址和端口号,存储到下拉框中
                cboUsers.Items.Add(socketTX.RemoteEndPoint.ToString());
                //展示连接的ip地址和端口号
                ShowMsg(socketTX.RemoteEndPoint.ToString() + "连接成功");
                Thread th = new Thread(RecData);
                th.IsBackground = true;
                th.Start(socketTX);
            }
        }
        /// <summary>
        /// 不停的接收客户端的消息
        /// </summary>
        /// <param name="o"></param>
        void RecData(object o)
        {
            Socket socketTX = o as Socket;
            while(true)
            {
                //创建缓存区
                byte[] buffer = new byte[1024 * 1024 * 5];
                //r表示实际接受到的字节数
                int r = socketTX.Receive(buffer);
                //将接收到的字节数组使用系统默认编码格式转换为字符串
                string msg = Encoding.Default.GetString(buffer, 0, r);
                //展示接收到的信息
                ShowMsg(socketTX.RemoteEndPoint.ToString() + ":" + msg);
            }
        }
        /// <summary>
        /// 在文本框中展示信息
        /// </summary>
        /// <param name="msg"></param>
        public void ShowMsg(string msg)
        {
            txtLog.AppendText(msg + "\r\n");
        }

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

        //服务器给客户端发消息
        private void btnSend_Click(object sender, EventArgs e)
        {
            string msg = txtMsg.Text.Trim();
            byte[] buffer = Encoding.Default.GetBytes(msg);
            //制作自己的协议 0:文字 1:文件  2:震动
            List<byte> listByte = new List<byte>();
            listByte.Add(0);
            listByte.AddRange(buffer);
            //以字节形式发送个客户端的数据,第一个字节是0代表发的是文字
            buffer = listByte.ToArray();
            //获取服务器选择的客户端的ip地址
            string ip = cboUsers.SelectedItem.ToString();
            //拿着ip去找对应的socket,然后发送
            dicSocket[ip].Send(buffer);
        }

        //发送震动
        private void btnZD_Click(object sender, EventArgs e)
        {
            byte[] buffer = new byte[1];
            buffer[0] = 2;
            string ip = cboUsers.SelectedItem.ToString();
            dicSocket[ip].Send(buffer);
        }

        //选择文件
        private void btnSelect_Click(object sender, EventArgs e)
        {
            //创建打开文件对话框
            OpenFileDialog ofd = new OpenFileDialog();
            ofd.Title = "请选择要发送的文件";
            ofd.Filter = "文本文件|*.txt|多媒体文件|*.wmv|所有文件|*.*";
            //初始化路径
            ofd.InitialDirectory = "E:\\123";
            //设置不允许多选
            ofd.Multiselect = false;
            ofd.ShowDialog();
            //获取用户选择文件的全路径
            string path = ofd.FileName;
            //放到窗体展示出来
            txtPath.Text = path;

        }

        //点击发送文件
        private void btnSendFile_Click(object sender, EventArgs e)
        {
            //获取要发送文件的路径
            string path = txtPath.Text.Trim();
            using (FileStream fsRead = new FileStream(path,FileMode.Open,FileAccess.Read))
            {
                try
                {
                    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);
                    buffer = list.ToArray();
                    //调用跟客户端通信的socket,发送字节数据
                    string ip = cboUsers.SelectedItem.ToString();
                    dicSocket[ip].Send(buffer, 0, r + 1, SocketFlags.None);
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message);
                }
                
            }
        }
    }
}

客户端
客户端样式截图:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Media;
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 socket;
        private void btnStart_Click(object sender, EventArgs e)
        {
            socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            IPAddress ip = IPAddress.Parse(txtServer.Text);
            IPEndPoint point = new IPEndPoint(ip,int.Parse(txtPort.Text));
            socket.Connect(point);
            ShowMsg("连接成功");

            //不停的接收服务器发送过来的消息
            Thread th = new Thread(RecServerData);
            th.IsBackground = true;
            th.Start();
        }

        //不停地接收服务器发送过来的消息
        void RecServerData()
        {
            while (true)
            {
                //连接成功后,接收服务器发送过来的消息
                byte[] buffer = new byte[1024 * 1024 * 5];
                int r = socket.Receive(buffer);
                byte b = buffer[0];
                //对面发送过来的是文字
                if (b==0)
                {
                    string msg = Encoding.Default.GetString(buffer,1,r-1);
                    ShowMsg(msg);
                }
                else if (b==2)//对面发送过来的是震动
                {
                    ZhenDong();
                    SoundPlayer sp = new SoundPlayer();
                    sp.Play();
                }
                else if (b == 1)//对面发送过来的是文件
                {
                    //1、弹出来一个保存文件的对话框
                    SaveFileDialog sfd = new SaveFileDialog();
                    sfd.InitialDirectory = @"E:\123";
                    sfd.Title = "请选择要保存的文件路径";
                    sfd.Filter = "文本文件|*.txt|媒体文件|*.wmv|所有文件|*.*";
                    sfd.ShowDialog(this);//展示保存对话框
                    //2、用户在对话框中选择要保存文件的路径
                    string savePath = sfd.FileName;
                    //3、FileStream把数据写入到指定的路径下
                    using (FileStream fsWrite = new FileStream(savePath, FileMode.Create, FileAccess.Write))
                    {
                        fsWrite.Write(buffer, 1, r - 1);
                        MessageBox.Show("保存成功!!!!");
                    }
                }
            }
        }

        //窗体震动
        void ZhenDong()
        {
            for (int i = 0; i < 1000; i++)
            {
                this.Location = new Point(300, 300);
                this.Location = new Point(320, 320);
            }
        }
        void ShowMsg(string msg)
        {
            txtLog.AppendText(msg+"\r\n");
        }
        //客户端给服务器发送消息
        private void btnSend_Click(object sender, EventArgs e)
        {
            string msg = txtMsg.Text.Trim();
            byte[] buffer = Encoding.Default.GetBytes(msg);
            socket.Send(buffer);
        }

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/400663.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

解决IDEA搜不到插件

File -> Settings -> Plugins https://plugins.jetbrains.com/ 完成以上操作即可搜到插件

小程序--组件通信

一、父传子 与vue利用props类似&#xff0c;小程序是利用自定义属性&#xff1a;properties // components/my-nav/my-nav.js Component({// 小程序组件默认样式是隔离&#xff0c;addGlobalClass设置为true可允许外部修改样式options: {addGlobalClass: true,// 只要使用到具…

面试经典150题——生命游戏

​"Push yourself, because no one else is going to do it for you." - Unknown 1. 题目描述 2. 题目分析与解析 2.1 思路一——暴力求解 之所以先暴力求解&#xff0c;是因为我开始也没什么更好的思路&#xff0c;所以就先写一种解决方案&#xff0c;没准写着写…

OJ链接——打印从1到最大的n位数

目录 1. 题目描述2. 示例3. 分析思路4. 完整代码 1. 题目描述 输入数字 n&#xff0c;按顺序打印出从 1 到最大的 n 位十进制数。比如输入 3&#xff0c;则打印出 1、2、3 一直到最大的 3 位数 999。 用返回一个整数列表来代替打印n 为正整数&#xff0c;0 < n < 5 链接在…

mac m1调试aarch64 android kernel最终方案

问题 这是之前的&#xff0c;调试android kernel的方案还是太笨重了 完美调试android-goldfish(linux kernel) aarch64的方法 然后&#xff0c;看GeekCon AVSS 2023 Qualifier&#xff0c;通过 sdk-repo-linux_aarch64-emulator-8632828.zip 进行启动 完整编译的aosp kernnl…

Code-Audit(代码审计)习题记录4-5

4、习题4 题目内容如下&#xff1a; <?php error_reporting(0); show_source(__FILE__); $a $_REQUEST[hello]; eval("var_dump($a);"); 函数解释 $REQUEST — HTTP Request 变量&#xff0c;默认情况下包含了 [$GET]&#xff0c;[$POST] 和 [$COOKIE]的数…

Git合并固定分支的某一部分至当前分支

在 Git 中&#xff0c;通常使用 git merge 命令来将一个分支的更改合并到另一个分支。如果你只想合并某个分支的一部分代码&#xff0c;可以使用以下两种方法&#xff1a; 1.批量文件合并 1.1.创建并切换到一个新的临时分支 首先&#xff0c;从要合并的源分支&#xff08;即要…

S281 LoRa网关助力智慧城市建设的智能交通管理

S281 LoRa网关作为智慧城市建设中的重要组成部分&#xff0c;发挥着关键的作用&#xff0c;特别是在智能交通管理方面。通过连接各类传感器设备和物联网终端&#xff0c;S281 LoRa网关实现了对城市交通系统的远程监控、智能调度和信息化管理&#xff0c;为城市交通管理部门提供…

学习鸿蒙基础(5)

一、honmonyos的page路由界面的路径 新建了一个page,然后删除了。运行模拟器的时候报错了。提示找不到这个界面。原来是在路由界面没有删除这个page。新手刚接触找了半天才找到这个路由。在resources/base/profile/main_pages.json 这个和微信小程序好类似呀。 吐槽&#xf…

MKS T3BI集成蝶阀说明T3B-T3PRS-232Supplement

MKS T3BI集成蝶阀说明T3B-T3PRS-232Supplement

常见的排序算法整理

1.冒泡排序 1.1 冒泡排序普通版 每次冒泡过程都是从数列的第一个元素开始&#xff0c;然后依次和剩余的元素进行比较&#xff0c;若小于相邻元素&#xff0c;则交换两者位置&#xff0c;同时将较大元素作为下一个比较的基准元素&#xff0c;继续将该元素与其相邻的元素进行比…

人工智能_CPU安装运行ChatGLM大模型_安装清华开源人工智能AI大模型ChatGlm-6B_004---人工智能工作笔记0099

上一节003节我们安装到最后,本来大模型都可以回答问题了,结果, 5分钟后给出提示,需要GPU,我去..继续看官网,如何配置CPU运行 没办法继续看: https://github.com/THUDM/ChatGLM-6B 这里是官网可以看到 需要gcc的版本是11.3.0,这里我们先没有去安装,直接试试再说 yum instal…

在UE5中使用OverlayMaterial制作多材质效果

UE5.1中新增了OverlayMaterial&#xff0c;可以让物体套用2个材质球效果&#xff0c;如A材质球为正常材质内容&#xff0c;B材质球为菲涅尔&#xff0c;或是B材质球是法线外拓描边等&#xff0c;该功能类似Unity的多pass效果&#xff0c;方便了日常使用。 下面就讲将怎么用Ove…

手把手教你如何搭建性能测试环境

前言 在进行性能则试前&#xff0c;需要完成性能测试的搭建工作&#xff0c;一般包括硬件环境、软件环境及网络环境&#xff0c;可以要求配置和开发工程师协助完成&#xff0c;但是作为一个优秀性能测试工程师&#xff0c;这也是你的必备技能之一。 性能测试环境与功能测试环…

4款文案神器,为你写作高质量文案

4款文案神器&#xff0c;为你写作高质量文案!在当今信息爆炸的时代&#xff0c;写作成为了一项重要的技能&#xff0c;无论是在工作中、学习中还是生活中&#xff0c;我们都需要用文字来传达信息、表达想法。然而&#xff0c;要写出高质量的文案并非易事&#xff0c;需要不断地…

开源软件的影响力及未来发展趋势

开源软件的影响力 在当今数字化时代&#xff0c;开源软件已经成为技术创新、商业模式和安全风险等方面不可或缺的一部分。本文将从开源软件如何推动技术创新、开源软件的商业模式、开源软件的安全风险、开源软件的未来发展趋势以及开源软件在各行业的应用案例几个方面进行深入…

如何利用Shopee卖家中心资源和策略进行有效选品?

在Shopee卖家中心进行选品是提高产品市场竞争力和销售业绩的关键环节。为了帮助卖家更好地利用Shopee提供的资源和策略进行选品&#xff0c;以下是一些实用建议&#xff1a; 先给大家推荐一款shopee知虾数据运营工具知虾免费体验地址&#xff08;复制浏览器打开&#xff09;&a…

【力扣hot100】刷题笔记Day7

前言 身边同学已经陆陆续续回来啦&#xff0c;舍友都开始投简历了&#xff0c;我也要加油啦&#xff01;刷完hot100就投&#xff01; 73. 矩阵置零 - 力扣&#xff08;LeetCode&#xff09; 标记数组&#xff1a;空间复杂度O(mn) class Solution:def setZeroes(self, matrix:…

第十七届“挑战杯”广东大学生课外学术科技作品比赛感想

博主曾在2023年参加了第十七届“挑战杯”广东大学生课外学术科技作品比赛&#xff0c;也就是人们俗称的大挑&#xff0c;在团队赛里面含金量应该是排在第一档的了&#xff0c;当初我们有幸作为学校唯一一支科技创新B类进入到线下答辩&#xff0c;线下答辩就是区分银奖和金奖和特…

设计模式-创建型模式-抽象工厂模式

抽象工厂模式&#xff08;Abstract Factory Pattern&#xff09;&#xff1a;提供一个创建一系列相关或相互依赖对象的接口&#xff0c;而无须指定它们具体的类。抽象工厂模式又称为Kit模式&#xff0c;它是一种对象创建型模式。 由于工厂方法模式中的每个工厂只生产一类产品&…