c# 实践笔记 2.windows应用程序之间的通讯

工作中遇到在同一个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();
  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值