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、将端口号绑定到socketWatchsocketWatch.Bind(point);//4、设置监听队列(同一时刻最多有几台设备同时连接)socketWatch.Listen(10);ShowMsg("正在等待客户端的连接");//5、创建一个新线程th,创建线程用于使用新创建的SocketThread th = new Thread(MyAccept);//6、设置th为后台线程th.IsBackground = true;//7、开启线程thth.Start(socketWatch);}//客户端的IP地址&端口号,服务器与客户端通讯的SocketDictionary<string,Socket> dicSocket = new Dictionary<string,Socket>();/// <summary>/// 实现客户端与服务器的通讯/// </summary>/// <param name="o"></param>void MyAccept(object o){//不停的接收客户端的连接while (true){//o墙砖为SocketSocket socketWatch = o as Socket;//为新建连接创建新的与之通信的SocketSocket 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;}}
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

cmd命令开启windows桌面远程控制并设置防火墙允许远程

cmd命令开启桌面远程控制 1、开启之前&#xff1a; 2、使用管理员身份运行cmd 3、执行cmd命令 reg add "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlset\Control\Terminal server" /v fDenyTSConnections /t REG_DWORD /d 0 /f4、如果这台电脑的防火墙打开&#xff…

Android14 InputManager-InputManagerService环境的构造

IMS分为Java层与Native层两个部分&#xff0c;其启动过程是从Java部分的初始化开始&#xff0c;进而完成Native部分的初始化。 □创建新的IMS对象。 □调用IMS对象的start&#xff08;&#xff09;函数完成启动 同其他系统服务一样&#xff0c;IMS在SystemServer中的ServerT…

股票K线认知从形态到逻辑,仓位管理与交易体系实战

一、教程描述 本套教程内容分为三个部分&#xff0c;1、基础篇&#xff1a;讲的都是干货基础&#xff0c;有些是书本上没有的&#xff0c;通过对基础知识的掌握&#xff0c;对技术形态会有更深的理解&#xff0c;比如集合竞价、K线指标、盘中看盘技巧等等。2、交易篇&#xff…

boolean在Java中占几个字节?(企业真题)

boolean 占几个字节 编译时不谈占几个字节。 但是JVM在给boolean类型分配内存空间时&#xff0c;boolean类型的变量占据一个槽位(slot(狭槽、窄口、扁口)&#xff0c;等于4个字节)。 细节&#xff1a;true:1 false:0 拓展&#xff1a;在内存中&#xff0c;byte\short\char\boo…

express静态资源访问错误 xxx.js was blocked due to MIME type (“text/html“)

归根结底原因是没有静态资源xxx.js的访问权限 如何在express中给静态资源添加访问权限&#xff0c;我在express js中添加以下语句解决了该问题&#xff1a; app.use(express.static(public)); 此时访问public文件夹中的xxx.js文件时&#xff0c;只需要使用路径 http://127.0…

备战蓝桥杯 Day9(背包dp)

01背包问题 1267&#xff1a;【例9.11】01背包问题 【题目描述】 一个旅行者有一个最多能装 M&#xfffd; 公斤的背包&#xff0c;现在有 n&#xfffd; 件物品&#xff0c;它们的重量分别是W1&#xff0c;W2&#xff0c;...,Wn&#xfffd;1&#xff0c;&#xfffd;2&#…

CentOS升级python

1、下载python39 https://mirrors.huaweicloud.com/python/3.9.0/Python-3.9.0.tgz2、拷贝到Linux环境&#xff08;当然也可以直接在Linux环境使用wget直接下载&#xff09; 先安装一下依赖&#xff0c;不然编译会有问题 sudo yum -y install zlib-devel bzip2-devel openssl…

【day02】每天三道 java后端面试题:Java、C++和Go的区别 | Redis的特点和应用场景 | 计算机网络七层模型

文章目录 1. Java、C和 Go 语言的区别&#xff0c;各自的优缺点&#xff1f;2. 什么是Redis&#xff1f;Redis 有哪些特点&#xff1f; Redis有哪些常见的应用场景&#xff1f;3. 简述计算机网络七层模型和各自的作用&#xff1f; 1. Java、C和 Go 语言的区别&#xff0c;各自的…

hsv Matlab

HSV 色彩空间 1.1 色调&#xff08;Hue&#xff09; 1.2 饱和度&#xff08;Saturation&#xff09; 1.3 明度&#xff08;Value&#xff09; 参考&#xff1a; HSV matlab

C#算法(12)—对图像像素做X/Y方向的偏移

我们在上位机开发领域有时候需要对获取的图像的像素做整体的偏移,比如所有像素在X方向上偏移几个像素,或者所有像素在Y方向上偏移几个像素,本文就是开发了像素整体偏移算法来解决这个问题。 比如有一个图像大小为3*3,像素值如下图1,如果我想实现将这个幅图像的像素整体往右…

Neon简介

欢迎关注“安全有理”微信公众号。 概述 本文介绍了 Arm Neon 技术&#xff0c;一种⾼级 SIMD&#xff08;Single Instruction Multiple Data&#xff0c;一条指令操作多个数据&#xff09;架构扩展&#xff0c;Armv8‑A 和 Armv8-R 架构支持了 Neon 技术扩展。 Neon 技术是指…

探索海洋世界,基于YOLOv7【tiny/l/x】不同系列参数模型开发构建海洋场景下海洋生物检测识别分析系统

前面的博文中&#xff0c;开发实践过海底相关生物检测识别的项目&#xff0c;对于海洋场景下的海洋生物检测则很少有所涉及&#xff0c;这里本文的主要目的就是想要开发构建基于YOLOv7不同系列参数模型的海洋场景下的海洋生物检测识别系统。 前文已有相关实践&#xff0c;感兴…

如何在debian上实现一键恢复操作系统?

在Debian或任何其他Linux发行版上实现一键恢复操作系统&#xff0c;需要创建一个系统镜像或快照&#xff0c;并设置一个简单的方法来从该镜像恢复。以下是创建和恢复系统的基本步骤&#xff1a; 1. 创建系统镜像&#xff1a; 使用像dd&#xff0c;rsync或专门的备份工具&#…

CDC 整合方案:MySQL > Flink CDC > Kafka > Hudi

继上一篇 《CDC 整合方案:MySQL > Kafka Connect + Schema Registry + Avro > Kafka > Hudi》 讨论了一种典型的 CDC 集成方案后,本文,我们改用 Flink CDC 完成同样的 CDC 数据入湖任务。与上一个方案有所不同的是:借助现有的 Flink 环境,我们可以直接使用 Flink CDC 从…

STM32—触摸键

目录 1 、 电路构成及原理图 2 、编写实现代码 3、代码讲解 4、烧录到开发板调试、验证代码 5、检验效果 此笔记基于朗峰 STM32F103 系列全集成开发板的记录。 1 、 电路构成及原理图 触摸键简单的了解就是一次电容的充放电过程。从原理图可以看出&#xff0c;触摸键 …

4.网络游戏逆向分析与漏洞攻防-游戏启动流程漏洞-模拟游戏登陆器启动游戏并且完成注入

内容参考于&#xff1a;易道云信息技术研究院VIP课 上一个内容&#xff1a;游戏启动流程的分析 码云地址&#xff08;master 分支&#xff09;&#xff1a;https://gitee.com/dye_your_fingers/titan 码云版本号&#xff1a;bcf7559184863febdcad819e48aaacad9f25d633 代码下…

Docker介绍与使用

Docker介绍与使用 目录&#xff1a; 一、Docker介绍 1、Docker概述与安装 2、Docker三要素 二、Docker常用命令的使用 1、镜像相关命令 2、容器相关命令 三、Docker实战之下载mysql、redis、zimg 一、Docker介绍 Docker是一个开源的应用容器引擎&#xff0c;让开发者可以打包…

C#上位机与三菱PLC的通信09---开发自己的通讯库(A-3E版)

1、A-3E报文回顾 具体细节请看&#xff1a; C#上位机与三菱PLC的通信05--MC协议之QnA-3E报文解析 C#上位机与三菱PLC的通信06--MC协议之QnA-3E报文测试 2、为何要开发自己的通讯库 前面开发了自己的A-1E协议的通讯库&#xff0c;实现了数据的读写&#xff0c;对于封装的通…

Kubernetes二进制搭建

目录 1.操作系统初始化配置&#xff08;所有节点同此操作&#xff09; 2.部署etcd集群 etcd概述 准备签发证书环境 在master01节点上操作&#xff08;192.168.88.22&#xff09; 在两个node节点上操作 总结&#xff1a; 3.部署docker引擎 4.部署Master组件 总结&…

SQL语法-DQL-测试练习

因篇幅原因&#xff0c;本篇承接此篇->第八篇&#xff1a;SQL语法-DQL-数据查询语言-CSDN博客 本篇是对于SQL语法DQL语句的练习&#xff0c;因水平和精力有限&#xff08;就不像前两篇的DDL&#xff0c;DML那样自出练习了&#xff09;直接照搬了【黑马程序员】在哔哩哔哩的…