如何在C中实现消息传递IPC?

时间:2018-03-08 03:19:57

标签: c ipc

我正在尝试编写一个程序来实现父进程和子进程之间的基本消息传递。我之前从未使用过C,所以过去两天我一直在磕磕绊绊地阅读教程,但我似乎无法让它发挥作用。我能做的最多就是创建没有错误的消息队列。 这是我的代码,评论我对我正在做的事情的最佳理解:

package soq

import (
    "fmt"
    "net"
    "syscall"
    "unsafe"
)

const (
    retErrInsufficientBuffer = 122
)

var (
    kernel32, _  = syscall.LoadLibrary("kernel32")
    heapAlloc, _ = syscall.GetProcAddress(kernel32, "HeapAlloc")
    heapFree, _  = syscall.GetProcAddress(kernel32, "HeapFree")

    getProcessHeap, _ = syscall.GetProcAddress(kernel32, "GetProcessHeap")
    processHeap, _, _ = syscall.Syscall6(getProcessHeap, 0, 0, 0, 0, 0, 0, 0)

    libIphlpapi, _  = syscall.LoadLibrary("iphlpapi")
    pGetUDPTable, _ = syscall.GetProcAddress(libIphlpapi, "GetUdpTable")

    pUDPTable uintptr
)

// UDPTableRow .
type UDPTableRow struct {
    LocalAddr net.IP
    LocalPort uint32
}

// UDPTable .
type UDPTable struct {
    NumEntries uint32
    Table      []UDPTableRow
}

// HeapAlloc .
func HeapAlloc(size uint32) uintptr {
    pMem, _, _ := syscall.Syscall(
        heapAlloc, 3,
        processHeap,
        0,
        uintptr(size),
    )
    return pMem
}

// HeapFree .
func HeapFree(pMem uintptr) {
    syscall.Syscall(
        heapFree,
        3,
        processHeap,
        0,
        pMem,
    )
}

// GetUDPTable .
func GetUDPTable() (*UDPTable, error) {
    var dwSize uint32

    if r1, _, _ := syscall.Syscall(
        pGetUDPTable,
        3,
        pUDPTable,
        uintptr(unsafe.Pointer(&dwSize)),
        0,
    ); r1 == retErrInsufficientBuffer {
        HeapFree(pUDPTable)
        pUDPTable = HeapAlloc(dwSize)
    }

    if r1, _, _ := syscall.Syscall(
        pGetUDPTable,
        3,
        pUDPTable,
        uintptr(unsafe.Pointer(&dwSize)),
        0,
    ); r1 != 0 {
        fmt.Println("GetUdpTable() failed with return value", r1)
    }

    /*
        How to retrive data from "pUDPTable"
        It's structure is

        https://msdn.microsoft.com/en-us/library/windows/desktop/aa366930(v=vs.85).aspx

        typedef struct _MIB_UDPTABLE {
            DWORD      dwNumEntries;
            MIB_UDPROW table[ANY_SIZE];
        } MIB_UDPTABLE, *PMIB_UDPTABLE;

        https://msdn.microsoft.com/en-us/library/windows/desktop/aa366926(v=vs.85).aspx

        typedef struct _MIB_UDPROW {
          DWORD dwLocalAddr;
          DWORD dwLocalPort;
        } MIB_UDPROW, *PMIB_UDPROW;
    */

    fmt.Printf("%#v", pUDPTable)

    return nil, nil
}

当我跑步时,我收到消息发送和接收失败。我完全迷失在IPC_CREATE意味着什么,IPC_NOWAIT等等。通常是msgsnd和msgrcv中的最后一个参数。在示例中,我看到人们使用0660 | IPC_CREAT,没有解释0660是什么。任何人都能解释我在我的代码中做错了什么,或者一般来说解释C中的消息传递给那些通常使用C#和Java的人,因为它现在基本上是黑魔法。到目前为止,我发现的每一个资源或教程一旦达到某一点就会超过我的头脑。感谢。

1 个答案:

答案 0 :(得分:4)

你没有在纯标准C中实现 Inter Process Communication,因为C11标准(读n1570)不知道它们,因为任何IPC工具都是特定于操作系统(特别是Windows上的IPC设施与Linux上的设施非常不同)。

但是,某些操作系统提供进程间通信工具。然后,您可以使用它们(无需实现它们),当然也可以采用某种特定于操作系统的方式。

在Linux上,更喜欢使用POSIX消息工具(而不是svipc(7)中记录的旧SystemV IPC),请参阅mq_overview(7)。还要注意pipe(7)fifo(7)socket(7)unix(7)signal(7)shm_overview(7)sem_overview(7)(因为有很多)进行进程间通信的方式。)

  

我完全迷失在IPC_CREATE意味着什么

你需要先阅读svipc(7),它说:

  

IPC_CREAT如果密钥不存在,则创建条目。

然后你问:

  

任何人都可以在我的代码中解释我的错误

您忘了对失败进行测试(另请参阅errno(3)& perror(3)& strerror(3))。您正在使用的每个函数都已记录(您应该阅读该文档)并且可能会失败(并且您需要以某种方式处理失败案例)。首先阅读msgget(2),然后通过添加适当的检查进行编码,至少:

 int msqid = msgget(key, IPC_CREAT);
 if (msgid<0) { perror("msgget"); exit(EXIT_FAILURE); }

同样适用于您使用的每个其他系统功能。

不要忘记仔细阅读 您使用的每个功能的man页面。另请参阅man(1)

一旦收到错误消息,您就可以再次参考文档并改进代码。

您可以使用strace(1)(通过某些流程或命令完成system call中列出的每个syscalls(2) - 来了解正在发生的事情。

您需要花费几天或几周阅读有关C编程和Unix系统编程的更多信息(例如,阅读旧的ALP或更新的东西)。您还应该阅读有关操作系统的内容,例如Operating Systems: Three Easy Pieces(可免费下载)。

  

0660是什么

可能与文件访问和权限相关(八进制0660可能对应rw-rw----)。另请参阅credentials(7)chmod(2)stat(2)inode(7)

PS。在更改单行代码之前,您确实需要在几天或几周内阅读,一旦您了解了如何编写Linux系统的编程,就可以从头开始重新启动。

还要了解与您的关注点和兴趣相关的现有 free software项目(例如github)的灵感。