工作中遇到在同一个pc上不同程序之间的通讯,那就梳理记录一下。
目前常用的方式有3种:1.使用Windows的API 2.共享内存 3.通过socket
1.使用windows的API
使用C#来测试
转载代码地址
//发送
private const int WM_COPYDATA = 0x004A;
private const int WM_DATA_TRANSFER = 0x0437;
// 使用Windows API的FindWindow方法
[DllImport("User32.dll", EntryPoint = "FindWindow")]
private static extern int FindWindow(string lpClassName, string lpWindowName);
//使用Windows API的IsWindow方法
[DllImport("User32.dll", EntryPoint = "IsWindow")]
private static extern bool IsWindow(int hWnd);
// 使用Windows API的SendMessage方法
[DllImport("User32.dll", EntryPoint = "SendMessage")]
private static extern int SendMessage(
int hWnd,
int Msg,
int wParam,
ref COPYDATASTRUCT lParam
);
// 使用Windows API的SendMessage方法
[DllImport("User32.dll", EntryPoint = "SendMessage")]
private static extern int SendMessage(
int hWnd,
int Msg,
int wParam,
string lParam
);
private struct COPYDATASTRUCT
{
public IntPtr dwData;
public int cbData;
public IntPtr lpData;
}
public static bool SendMessageToTargetWindow(string wndName, string msg)
{
Debug.WriteLine(string.Format("SendMessageToTargetWindow: 向目标窗口发送消息 {0}: {1}", wndName, msg));
int iHWnd = FindWindow(null, wndName);
if (iHWnd == 0)
{
string strError = string.Format("SendMessageToTargetWindow: 没有发现{0}窗体!", wndName);
MessageBox.Show(strError, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
Debug.WriteLine(strError);
return false;
}
else
{
byte[] bytData = null;
bytData = Encoding.Default.GetBytes(msg);
COPYDATASTRUCT cdsBuffer;
cdsBuffer.dwData = (IntPtr)100;
cdsBuffer.cbData = bytData.Length;
cdsBuffer.lpData = Marshal.AllocHGlobal(bytData.Length);
Marshal.Copy(bytData, 0, cdsBuffer.lpData, bytData.Length);
// 使用系统定义的消息wmcopydata来发送消息。
int iReturn = SendMessage(iHWnd, WM_COPYDATA, 0, ref cdsBuffer);
if (iReturn < 0)
{
string strError = string.Format("SendMessageToTargetWindow: 没有发现{0}窗体!", wndName);
MessageBox.Show(strError, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
Debug.WriteLine(strError);
return false;
}
return true;
}
}
public static bool SendMessageToTargetWindow(string wndName, int wParam, string lParam)
{
Debug.WriteLine(string.Format("SendMessageToTargetWindow: Send message to target window {0}: wParam:{1}, lParam:{2}", wndName, wParam, lParam));
int iHWnd = FindWindow(null, wndName);
if (iHWnd == 0)
{
string strError = string.Format("SendMessageToTargetWindow: The target window [{0}] was not found!", wndName);
MessageBox.Show(strError, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
Debug.WriteLine(strError);
return false;
}
else
{
//使用定义的消息wmdatatransfer来发送消息。
int iReturn = SendMessage(iHWnd, WM_DATA_TRANSFER, wParam, lParam);
if (iReturn < 0)
{
string strError = string.Format("SendMessageToTargetWindow: Send message to the target window [{0}] failed!", wndName);
MessageBox.Show(strError, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
Debug.WriteLine(strError);
return false;
}
return true;
}
}
//接收 只要重写DefWndProc
protected override void DefWndProc(ref System.Windows.Forms.Message m)
{
switch (m.Msg)
{
// 这里,我们使用wmcopydata消息来接收COPYDATASTRUCT
case WM_COPYDATA:
COPYDATASTRUCT cds = new COPYDATASTRUCT();
cds = (COPYDATASTRUCT)m.GetLParam(typeof(COPYDATASTRUCT));
byte[] bytData = new byte[cds.cbData];
Marshal.Copy(cds.lpData, bytData, 0, bytData.Length);
break;
// 在这里,我们使用我们定义的消息wmdatatransfer来接收
// 普通数据,例如整数,字符串。
case WM_DATA_TRANSFER:
int iWParam = (int)m.WParam;
string sLParam = m.LParam.ToString();
break;
default:
base.DefWndProc(ref m);
break;
}
}
2.通过共享内存
1.什么是共享内存。
在系统中,两个不同的进程都会维护自己的一块地址空间,这个地址空间一般是虚拟地址,会通过mmu和页表映射到对应的物理内存中,因为不同的进程会有不同的内存空间,因此两个进程之间是无法看见彼此的数据的,而共享内存就是使两个进程看到同一块地址空间,以此来实现不同进程间的数据交互。
2.共享内存的方式。
通过共享内存也有2种方式1.windowsAPI 2.使用.net提供的MemoryMappedFile 类。
这里我们只记录下使用MemoryMappedFile 的情况(其实.net中的MemoryMappedFile 是对windowsAPI的封装)。
引用原文地址
持久化的MMF
持久化的MMF是与磁盘上的文件相关,调用MemoryMappedFile.CreateFromFile方法创建的。当最后一个进程完成操作MMF操作之后,操作系统会将修改写回磁盘中。这个方式特别适合操作特别大的文件。
非持久化的MMF
这种MMF不与磁盘上的文件相关联,调用MemoryMappedFile.CreateNew方法创建的。当最后一个进程使用完毕之后,映射到内存的MMF被垃圾回收机制回收。这种方式适合用于多个进程之间通信(IPC)
MemoryMappedViewAccessor: ramdom access view,适合与持久化MMF一起使用
MemoryMappedViewStream: sequence access view,适合与非持久MMF或IPC
3.示例
1.创建持久化MMF
app1:
//step1 创建MMF对象
MemoryMappedFile mmf = MemoryMappedFile.CreateFromFile(@"e:内存映射文件.txt", FileMode.Open, "公用名");//注意文件不能是空的否则会报异常
//step2 创建View对象
MemoryMappedViewAccessor viewAccessor = mmf.CreateViewAccessor(0, 0);
//step3 写or读
viewAccessor.Write(0, 10);
app2:
//step1 创建MMF对象
MemoryMappedFile mmf = MemoryMappedFile.OpenExisting("公用名");
//step2 创建View对象
MemoryMappedViewAccessor viewAccessor = mmf.CreateViewAccessor(0, 0);
//step3 写or读
viewAccessor.ReadInt32(0);
2.创建非持久化MMF
app1:
//step1 创建MMF对象
MemoryMappedFile mmf = MemoryMappedFile.CreateNew("testmap", 10000);
//step2 创建View对象
MemoryMappedViewStream stream = mmf.CreateViewStream(); //创建文件内存视图流 基于流的操作
//step3 初始化写入流的 BinaryWriter 类的新实例,当然也可以用MemoryMappedViewAccessor的方式
BinaryWriter writer = new BinaryWriter(stream);
//step4 写or读
writer.Write(++i);
app2:
//step1 创建MMF对象
MemoryMappedFile mmf = MemoryMappedFile.CreateNew("testmap", 10000);
//step2 创建View对象
MemoryMappedViewStream stream = mmf.CreateViewStream(); //创建文件内存视图流 基于流的操作
//step3 初始化写入流的 BinaryWriter 类的新实例,当然也可以用MemoryMappedViewAccessor的方式
BinaryWriter reader= new BinaryWriter(stream);
//step4 写or读
reader.ReadInt32();
3.通过socket的方式
C#Socket类实现 Berkeley 套接字接口
1.什么是socket?
网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个socket。(server,Client)
2.socket基本流程图
3.服务器端代码
//step1 设定ip地址和端口号
IPAddress ip = IPAddress.Parse("127.0.0.1");
IPEndPoint point = new IPEndPoint(ip, 5000);
//stpe2 创建Socket对像
Socket server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//stpe3 用socket对像的Bind()方法绑定EndPoint;
server.Bind(point);
//stpe4 用socket对像的Listen()方法开始监听
server.Listen(5);
//stpe5 等待客户端的连接,并且创建一个用于通信的Socket
Socket connect = server.Accept();
//stpe6 通过创建与客户端的连接进行信息的发送和接收
byte[] tmp = new byte[1];
connect.Send(tmp, 0, 0);
byte[] l_pucRcvData = new byte[4];
connect.Receive(l_pucRcvData, 4, SocketFlags.None);
//step7 通讯结束关闭socket
server.Close();
connect.Close();
4.客户端代码
//step1 设定ip地址和端口号
IPAddress ip = IPAddress.Parse("127.0.0.1");
IPEndPoint point = new IPEndPoint(ip, 5000);
//stpe2 创建Socket对像
Socket connect = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//stpe3 连接服务器
connect .Connect(point );
//stpe4 通过与服务器的连接进行信息的发送和接收
byte[] tmp = new byte[1];
connect.Send(tmp, 0, 0);
byte[] l_pucRcvData = new byte[4];
connect.Receive(l_pucRcvData, 4, SocketFlags.None);
//step5 通讯结束关闭socket
connect.Close();