赞
踩
定义:每一个正在运行的应用程序,都是一个进程
进程不等于正在运行的应用程序。而是为应用程序的运行构建一个运行环境
- 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();//程序关闭时,强制后台线程关闭
- }
服务器:
服务器样式截图:
- 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;
- }
- }
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。