2

Unix ドメイン ソケットと sendmsg/recvmsg を使用して 2 つのプロセス間で fd を送信するコードがあります。このコードは、Linux と Mac の両方で実行する必要があります (両方のプラットフォームで個別にコンパイルされます)。SOCK_DGRAM (データグラム) ソケットを使用しています。

コードで一度に 1 つの fd を送信します。Mac では、この方法でいくつかの fd を正常に送信した後、recvmsg() は EMSGSIZE で失敗します。recvmsg のマンページによると、これは msg->msg_iovlen <=0 または >= Mac では 2048 の定数である場合にのみ発生します。私のコードでは、msg_iovlen を常に 1 に固定しています。送信側と受信側でこれを確認し、recvmsg() 障害の直後にメッセージ ヘッダーを読み取って確認しました。この同じコードは、Linux でも正常に動作します。

XNU カーネル ソースを見ると、レシーバーが fd を使い果たした可能性がありますが、エラーが発生する前に 4 つまたは 5 つの fd しか送信していないため、十分な fd が残っているはずです。

fd を送信せず、データのみを送信すると、このエラーは発生しません。

コントロール メッセージをパックするコードは次のようになります。

// *obj is the fd, objSize is sizeof(*obj)
// cmsg was allocated earlier as a 512 byte buffer

cmsgLength = CMSG_LEN(objSize);

cmsgSpace = CMSG_SPACE(objSize);

cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_RIGHTS;
cmsg->cmsg_len = cmsgLength;

memcpy(CMSG_DATA(cmsg), obj, objSize);

msg->msg_control = cmsg;
msg->msg_controllen = cmsgSpace;

そして、ここに受信機があります:

msg = (struct msghdr *)pipe->msg;
iov = msg->msg_iov;
iov->iov_base = buf;
iov->iov_len = size;

// msg->msg_control was set earlier
msg->msg_controllen = 512;

return recvmsg(sockFd, msg, 0);

手がかりはありますか?前もって感謝します

4

1 に答える 1

0

受け取った cmsg を実際に使用していますか? msg_controllen を 512 に設定していることに気付きました。msg_flags を何に設定しましたか?

次の1つの追加で同じことを試すことができますか.

msg = (struct msghdr *)pipe->msg;

memset (msg, 0, sizeof(msghdr)); /* added this */

iov = msg->msg_iov;
iov->iov_base = buf;
iov->iov_len = size;

// msg->msg_control was set earlier
msg->msg_controllen = 512;

return recvmsg(sockFd, msg, 0);
于 2013-08-18T13:17:40.083 に答える