有谁弄过unity3dunity 进程间通信信的东西嘛

unity3D开发中进程通信的实现方法-菜鸟在线
unity3D开发中进程通信的实现方法
unity3D开发中进程通信的实现方法
浏览次数:177
浏览次数:237
浏览次数:549
浏览次数:424
浏览次数:452
如果你对以下课程意犹未尽,,查看全部课程
HTML5全栈开发
HTML5最新课程
156 人在学
c#编程概述
C#快速入门
简单又好玩
120 人在学
没有账号?
s后重新发送
已有账号?
已有账号?
验证码确认
话题标题:
400-877-8190
登录后反馈1.进程:具有独立功能的程序在一个数据集合上一次动态的执行过程。通俗点讲就是&一个正在运行的程序&
2.程序:静态的程序以文件的形式保存在磁盘上。
3.操作系统的进程管理:
每一个正在运行的程序都对应着一个独立的进程,当这些程序装入内存开始执行时,操作系统会为每个进程创建好相关的数据结构。由于操作系统可以同时装入多个程序,为此必须有一种方法来保证这些同时运行的程序不相互影响,不会由于一个程序出现异常而直接影响其他程序,甚至操作系统的正常运行。位于操作系统核心的&进程管理&模块负责管理并行执行的多个程序。
4.操心系统的用户模式和核心模式:
Windows设计了两种代码运行的环境&&用户模式和核心模式(用户态与核心态)。普通的应用程序运行于用户模式中,而操作系统的关键代码(比如负责分配与回收内存,创建和销毁进程等功能代码)运行核心模式下。运行于核心模式下的代码可以访问系统内存和执行所有的CPU指令,用户模式下运行的代码则只拥有&有限的权限&。当用户模式下的应用程序访问系统核心数据时,它必须发出一个&系统调用&提出访问核心数据的申请,操作系统内核接到申请,有运行在核心模式下的代码去访问这些数据,然后将结果再&转发&给处于用户模式下的代码。Windows应用程序通过调用Win32API函数来实现从&用户模式&到&核心模式&的转换。
操作系统核心会不断地创建和销毁"核心对象",为了便于跟踪和访问这些对象,此操作系统为这些对象分配了标识,这是一个32位的整数,被称为"句柄(Handle)"
6.操作系统采用引用计数法来决定销毁核心对象的时机:
当一个线程调用某个Win32API函数创建一个核心对象之后,此核心对象的初始引用计数为1,应用程序代码中对其句柄的每次引用都会导致计数加1.线程用完以后应该关闭句柄,此时引用对象减1,当其值减为1时,操作系统销毁这一核心对象,并回收其占用的各种资源。
7..NET对于"普通对象"与"核心对象"不加区分,使用new关键字就可以创建任何一种类型,而对象的销毁工作由CLR负责。
线程是CPU调度的基本单位,因为操作系统会给进程分配大量的资源,如果直接以进程作为调度CPU运行的基本单位,那么当进程投入运行和退出运行时,必然花费大量的计算资源在进程运行环境的切换上(保护现场等)。这会严重影响操作系统的性能。为此,操作系统将进程切分为多个&线程(thread)",虽然线程也需要有一个运行环境,但这个运行环境往往只涉及到当前一些寄存器的值,数据量小,切换速度快得多。
9.&进程是系统分配各种资源的单位,而线程则是操作系统分配CPU的基本单位
10.线程上下文
线程的运行环境被称为&线程上下文&,包括为使线程在线程的所属进程地址空间中继续运行所需的所有信息(如线程的CPU寄存器,线程堆栈和线程局部存储区)当从一个线程切换到另一个线程时,操作系统将保存被换出线程的线程上下文。
11.CLR如何管理进程与线程
.NET是一个托管的运行环境,在其上运行的进程称为&托管进程&,而在托管进程中创建的线程自然就是&托管线程&。操作系统直接创建的进程和线程被称为本地进程和本地线程
Process类代表托管进程,它实际上封装的是本地进程。,每一个托管进程都对应着一个操作系统真实的本地进程。
Thread类代表托管线程,每一个托管线程对应着一个函数(线程函数),托管线程执行的过程就是线程函数执行的过程,线程函数的代码执行完了,线程也就执行完了。
Thread类与操心系统的真实的本地线程不是一一对应的,它代表是一个&逻辑线程&,有CLR负责创建与管理。.NET&Framework中另有一个ProcessThread用于表示操作系统真实的本地线程。
在操作系统中,线程直接运行于进程内部,而在.NET托管环境下,托管线程与托管进程之间还有一个中间层次&&应用程序域
2.进程通信
进程通信:正在运行的进程相互交换信息。
每个进程都拥有自己的地址空间,其它进程不能直接访问。通常通过一个第三方媒介间接地在进程之间交换信息。通常有下面几种方式:
剪贴板,共享同一文件,COM,.NET4.0内存映射文件,WCF
①使用剪贴板在进程间传送对象
&剪贴板是一个供应用程序使用的公共区域,在Windows上运行的所有程序在需要时都可以使用剪贴板存放的信息
namespace UseClipboard
public partial class frmMain : Form
public frmMain()
InitializeComponent();
private Image bmp
return pictureBox1.I
pictureBox1.Image =
//图片说明
private string info
return txtImageInfo.T
txtImageInfo.Text =
private void btnLoadPic_Click(object sender, EventArgs e)
ChooseImageFile();
//选择图片
private void ChooseImageFile()
if (openFileDialog1.ShowDialog() == DialogResult.OK)
bmp = new Bitmap(openFileDialog1.FileName);
//根据用户设定的信息创建对象
private MyPic CreateMyPicObj()
MyPic obj = new MyPic();
obj.picInfo =
//将对象复制到剪贴板上
private void CopyToClipboard()
//创建MyPic对象
MyPic obj = CreateMyPicObj();
//创建一个数据对象,将MyPic类型的对象装入
IDataObject dataobj = new DataObject(obj);
//其它类型的数据也可以装入到数据对象中
dataobj.SetData(DataFormats.UnicodeText, info);
dataobj.SetData(DataFormats.Bitmap, bmp);
//复制到剪贴板上,第二个参数表明程序退出时不清空剪贴板
Clipboard.SetDataObject(dataobj,true );
private void btnExit_Click(object sender, EventArgs e)
private void btnCopyToClipboard_Click(object sender, EventArgs e)
CopyToClipboard();
//从剪贴板获取数据
private void PasteFromClipboard()
//剪贴板上有我需要的数据吗?格式为&项目名称.数据格式名&
if (Clipboard.ContainsData("UseClipboard.MyPic") == false)
//读取数据
IDataObject clipobj = Clipboard.GetDataObject();
//将数据转换为需要的类型
MyPic mypicobj = clipobj.GetData("UseClipboard.MyPic") as MyP
//从数据对象中分解出需要的数据
info = mypicobj.picI
pictureBox1.Image = mypicobj.
private void btnPasteFromClipboard_Click(object sender, EventArgs e)
PasteFromClipboard();
剪贴板无法通知其它进程数据已经放到剪贴板上了。
②使用FileSystemWatcher实现进程同步
FileSystemWatcher是.NET提供组件,它可以监控特定的文件夹或文件,比如在此文件夹中的文件被删除或内容被改变时引发对应的事件。通过使用FileSystemWatcher组件,让多个进程同时监控一个文件,就可以让文件充当&临时的&进程间通信渠道。
③使用内存映射文件实现进程通信
原理:在内存中开辟出一块存放数据的专用区域,这区域往往与硬盘上特定的文件相对应。进程将这块内存区域映射到自己的地址空间中,访问它就像访问普通内存一样。
MemoryMappedFile对象表示一个内存映射文件,通过它的CreateFromFile根据磁盘现有文件创建内存映射文件。
MemoryMappedFile对象创建之后,并不能直接对其进行读写,必须通过MemoryMappedViewAccessor来访问创建的内存映射文件,MemoryMappedViewAccessor的Write&T&,Read&T&方法来执行读写操作。注意:T必须是值类型。之所以不能是引用类型,是因为引用类型保存在托管堆上面,计算机需要消耗性能来计算对象的大小。
如果需要保存引用类型(例如图片),可以采用序列化的方式。MemoryMappedFile类可以创建一个MemoryMappedViewStream对象,通过它可以序列化对象。如下:
//创建或打开内存映射文件
MemoryMappedFile memoryFile=MemoryMappedFile.CreateOrOpen(...);
//创建内存映射流
MemoryMappedViewStream stream=memoryFile.CreateViewStream();
//创建要在进程之间交换的信息对象
//向内存映射流中序列化对象
IFormatter formatter=new BinaryFormatter();
stream.Seek(0,SeekOrigin.Begin);
formatter.Serialize(stream,obj);
④使用WCF通过管道实现进程通信
管道(pipe):是Windows提供的一种进程间通信机制,用于在两个进程间相互传送数据。
Windows提供两种管道:
匿名管道(Anonymous&Pipe):单向通信,两个通信的进程应该是父子关系,父进程在创建子进程时,负责将代表匿名管道的句柄传给子进程,子进程获得句柄后,即可接收从父进程发来的消息。
命名管道(Named&Pipe):拥有在本机唯一的名字,可以用在一个服务端进程和多个客户进程同事进行单向或双向通信。命名管道支持基于消息的通信模式,这就是说,一个进程可以向另一方进程连续发送多个消息
读书笔记《.NET4.0面向对象编程漫谈》作者:金旭亮老师
阅读(...) 评论()Unity3D内部串口通信和Unity3D与Winform程序的串口通信的实现和异常问题 - 博客频道 - CSDN.NET
记录自己的成长
分类:Unity
1、有些人其实会觉得Unity3D用到的.NET是2.0的,其实不然;Unity3D有用到.NET3.5,为什么说Unity用到的是3.5呢,从一个很常用却很重要的一个命名空间说起,他就是System.Linq命名空间,这个命名空间是.NET3.5重要的一次改革和核心部分(本命名空间与该文章并没有什么很大的联系,只是提下而已)。至于为什么显示成2.0我也不是很清楚,可能只支持部分3.5吧,不过对我们来说关系并不是很大。只要支持Linq就可以了。
2、前提工作:虚拟串口和Unity3D切换成.NET。
2.1 虚拟串口的创建,可以从网上下载一个创建虚拟串口的软件,比如“VSPD虚拟串口”,还是挺好用的,不过因为我做Unity3D的虚拟串口工作,所以根据VSPD专门写了一个创建虚拟串口的程序(暂时不提供)。在创建虚拟串口的时候注意一个很重要的问题,就是尽量创建串口号大于10的,比如COM10、COM11甚至夸张点COM100等,为什么要这样子,后面我会介绍Unity3D打开串口时,串口号大于10时,打开串口方式与.NET打开串口的方式是不一样的。
2.2 将Unity3D的API平台切换成.NET2.0。如何切换“Edit–&project Setting–&Player–&Other Setting –&Api Compatibility level”。在这里将“.NET2.0 Subset”切换为“.NET2.0”
2.3 Unity的目标平台一定要切换为Windows平台,否则是其他平台会报错误,本人就是深有体会,针对这个问题找原因找了很久,什么百度、谷歌、论坛都查阅了,最后还是无意中自己发现解决的了。
切换为Web平台时报的错误
3、Unity的串口与.NET的串口对象参数有些不一样,比如在Unity3D中打开串口,SerialPort对象的属性、方法、事件等要比.NET SerialPort对象的属性、事件、方法要少一些。(图片不能显示,所以不就贴图了,只是说明下情况),甚至Unity3D的有些属性还是错误的,比如BytesToRead和BytesToWrite两个属性都是“未将对象引用值对象的实例”,但是在.NET中这两个参数默认是为0。这两个参数用于接收串口发送字节数组时,是很有用处的。
这是Unity中串口对象里的属性
这是WinForm中串口对象里的属性
4、虚拟串口的创建,不像是真实串口线那样子,它是以对来创建的,比如COM100与COM101一对……至于怎么成对完全是有那个创建虚拟串口的软件以及你输入的串口来决定的。
一、Unity3D内部串口通信
1、内部通信思路
1.1 打开串口
之前在前言中说过,Unity打开串口方式不一样,因为在.NET2.0打开串口时,如果串口超过10,则必须在前面加上“\\?\”,比如我需要打开COM301,在Unity中你实际传给串口的参数必须是“”\\?\” + “COM301””。
在命名空间中引用System.IO.Ports
创建两个串口类对象
private SerialPort gatewayPort, coorP
然后写一个打开串口方法
注意:下面的网关串口和协调器串口只是我的命名而已,其实串口之间的通信。
**打开网关串口**
gatewayPort = new SerialPort("\\\\?\\" + "COM301", 9600);
gatewayPort.ReadTimeout = 500;
gatewayPort.Open();
Debug.Log("网关串口打开成功");
tgateway = new Thread(ReceivePortThread2);
tgateway.IsBackground = true;
tgateway.Start();
*打开协调器串口*
coorPort = new SerialPort("\\\\?\\" + "COM3301", 9600);
coorPort.ReadTimeout = 500;
coorPort.Open();
Debug.Log("协调器串口打开成功");
tcoor = new Thread(ReceivePortThread1);
tcoor.IsBackground = true;
tcoor.Start();
1.2 线程接收数据
两个串口接收数据,并且打印出来,一般接收数据的方法常用的有两种,一种是接收字符串ReadLine()另一种接收字节Read,稍微我会将接收字节已注释的形式写出来。
字节接收的方式,把代码放在网关接收方法里和协调器方法里,根据个人需求吧
ClassConvert类是一些字节、字符串转化的方法,后面会提供
网关接收数据方法
private void ReceivePortThread2()
while(true) {
Thread.Sleep(1);
if(this.gatewayPort != null && this.gatewayPort.IsOpen) {
string strRec = gatewayPort.ReadLine();
Debug.Log("网关读取数据:" + strRec);
协调器接收数据方法
private void ReceivePortThread1()
while(true) {
Thread.Sleep(1);
if(this.coorPort != null && this.coorPort.IsOpen) {
string strRec = coorPort.ReadLine();
Debug.Log("协调器读取数据:" + strRec);
1.3 发送数据
将这下面两个方法分别加入到UI Button的事件中,具体如何加这里就不解释了。
public void OnGateWay()
this.gatewayPort.DiscardOutBuffer();
gatewayPort.WriteLine("FF0000");
public void OnCoor()
this.coorPort.DiscardOutBuffer();
coorPort.WriteLine("00FFFF");
主要类PortsTest.cs,字节字符串转化类ClassConvert.cs
using UnityE
using System.C
using UnityEngine.UI;
using System.IO.P
using System.T
public class PortsTest : MonoBehaviour {
private SerialPort gatewayPort, coorP
public Thread tgateway,
void Start () {
GateWayOpen();
CoorOpen();
void Update () {
void GateWayOpen()
gatewayPort = new SerialPort("\\\\?\\" + "COM301", 9600);
gatewayPort.ReadTimeout = 500;
gatewayPort.Open();
Debug.Log("网关串口打开成功");
tgateway = new Thread(ReceivePortThread2);
tgateway.IsBackground = true;
tgateway.Start();
void CoorOpen()
coorPort = new SerialPort("\\\\?\\" + "COM3301", 9600);
coorPort.ReadTimeout = 500;
coorPort.Open();
Debug.Log("协调器串口打开成功");
tcoor = new Thread(ReceivePortThread1);
tcoor.IsBackground = true;
tcoor.Start();
串口接收数据方法
private void ReceivePortThread1()
while(true) {
Thread.Sleep(1);
if(this.coorPort != null && this.coorPort.IsOpen) {
string strRec = coorPort.ReadLine();
Debug.Log("协调器读取数据:" + strRec);
串口接收数据方法
private void ReceivePortThread2()
while(true) {
Thread.Sleep(1);
if(this.gatewayPort != null && this.gatewayPort.IsOpen) {
string strRec = gatewayPort.ReadLine();
Debug.Log("网关读取数据:" + strRec);
public void OnGateWay()
this.gatewayPort.DiscardOutBuffer();
gatewayPort.WriteLine("FF0000");
public void OnCoor()
this.coorPort.DiscardOutBuffer();
coorPort.WriteLine("00FFFF");
public class ClassConvert
字节数据转字符串
public static string BytesToString(byte[] bytes)
string result = "";
foreach (byte b in bytes)
result = result + string.Format("{0:X2}", b);
字节数据转字符串(带格式)
public static string BytesToStringFormat(byte[] bytes)
string result = "";
foreach (byte b in bytes)
result = result + string.Format("{0:X2}", b) + "-";
return result.Substring(0, result.Length - 1);
2位字符串转字节
public static byte StringToByte(string str)
str = System.Convert.ToInt32(str, 16).ToString();
catch (Exception err)
byte result = 0;
if (byte.TryParse(str, out result) == true)
throw new Exception("StringToByte error");
字符串转字节数据
public static byte[] StringToBytes(string str)
byte[] result = new byte[str.Length / 2];
for (int i = 0; i & str.L i = i + 2)
result[i / 2] = StringToByte(str.Substring(i, 2));
3、运行结果和异常解析
运行程序后,会提示网关串口打开成功和协调器串口打开成功。
3.1、当以字符串形式发送串口数据和接收串口数据时,会发现一个问题就是在接收串口数据时,会出现数据丢失的情况,网关串口向协调器发送”FF0000”时,协调器接收数据偶尔会接收到“F0000”甚至是为空,只有当连续发送两次时,才会成功。
3.2、当以字节发送和接收串口数据时,会出现一条完整的数据会以两次打印出来。比如将“new byte[] { 0xFF, 0x00, 0x01 }”发送过去,然后打印出来的结果是第一条是FF 第二条是00 01等等情况,感觉像是随机的。
3、当以字节发送,字符串形式接收时,是无法接收数据的。
以上问题目前我也不知道是什么情况,解决思路是怎样的,发生该问题的原因可能是因为Unity对串口这块本身支持就不是很大,毕竟不是专门针对Windows平台的,如果有看到本文章的读者知道的话,请联系我的邮箱: 或者微博: 本人非常感谢!!
在第一部分中介绍了Unity3D内部间的通信,现在测试Unity3D与Winform程序之间的串口通信。
首先Unity3D串口程序跟第一节类似的,只不过把网关打开串口那一部分代码移植到Winform中,然后修改一下打开串口的方式即可。
1、打开串口方式
private SerialPort gatewayP
gatewayPort = new SerialPort("COM202", 9600);
gatewayPort.ReadTimeout = 500;
gatewayPort.Open();
tgateway = new Thread(new ThreadStart(ReceivePortThread2));
tgateway.IsBackground = true;
tgateway.Start();
private void ReceivePortThread2()
while(true) {
Thread.Sleep(1);
if(this.gatewayPort != null && this.gatewayPort.IsOpen) {
string strRec = gatewayPort.ReadLine();
MessageBox.Show(strRec);
以上就是核心代码。
2、遇到的问题
发送字符串和接收字符串遇到以下发生过的问题
2.1 winform程序发送数据成功了,但是Unity接收不到
2.2 Unity往Winform程序总发送数据时,是没有问题的。而Unity却接收不到。
发送字节和接收字节遇到以下发生过的问题
2.3 WinForm程序发送数据成功了,但是Unity接收到的数据存在问题,数据不符或数据中断,要想解决这个问题有两种方法:
第一可能是Unity官方的错误,如果能做成跟.NET串口通信一致的话,那么这个问题很好解决。不过这个问题不够现实,因为Unity本身就是为游戏而开发的。
第二那就自己去解决了,看到Unity接收到的数据存在数据不符,还有数据断层,只能根据自身的要求,然后去测试,添加校验位,根据首校验位和末校验位来截取你想要的字节。只有这样子你才可能接收到正常的串口数据。但是这样子也存在很多的局限性!!!
2.4 Unity往WinForm程序中发送的数据时,是没有问题的。
WinForm 接收数据关键代码:
if(gatewayPort.BytesToRead & 0) {
byte[] bufferRead = new byte[this.gatewayPort.BytesToRead];
this.gatewayPort.Read(bufferRead, 0, bufferRead.Length);
string strRec = ClassConvert.BytesToString(bufferRead);
WinForm发送数据关键代码:
gatewayPort.DiscardInBuffer();
byte[] buffer = new byte[] { 0xFF, 0x00, 0x01 };
gatewayPort.Write(buffer, 0, buffer.Length);
Unity的接收数据关键代码和发送数据关键代码已在第一节都贴出来了。
排名:千里之外
(3)(1)(1)2013年2月 移动平台大版内专家分月排行榜第三
本帖子已过去太久远了,不再提供回复功能。

我要回帖

更多关于 unity3d 进程通信 的文章

 

随机推荐