sockets - 套接字缓冲区在 SCM_RIGHTS 类型时会发送消息吗?
问题描述
我写了一个 SCM_RIGHTS 类型的服务器和客户端,用于在进程之间发送 fd。
服务器:
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#include <errno.h>
#include <stdio.h>
#include <string>
#include "TBufferCommon.h"
#include <iostream>
int m_bindSocket;
bool start()
{
std::string bindSocketPath = "/tmp/test";
if (access(bindSocketPath.c_str(), F_OK) == 0)
{
remove(bindSocketPath.c_str());
}
int retCode = 0;
retCode = socket(AF_UNIX, SOCK_DGRAM, 0);
if (retCode == -1)
{
printf("%s failed to setup TBufferClient recv socket , error: %s\n", __PRETTY_FUNCTION__, strerror(errno));
return false;
}
m_bindSocket = retCode;
sockaddr_un addr;
memset(&addr, 0, sizeof(addr));
addr.sun_family = AF_UNIX;
memcpy(addr.sun_path, bindSocketPath.c_str(), bindSocketPath.size());
retCode = bind(m_bindSocket, (const sockaddr *)&addr, sizeof(addr));
if (retCode == -1)
{
printf("%s failed to bind TBufferClient recv socket , error: %s\n", __PRETTY_FUNCTION__, strerror(errno));
return false;
}
return true;
}
bool recvBufferAndFd(void *buffer, int &buff_size, int &fd_recv)
{
msghdr msg;
do {
iovec iov[1];
char control[CMSG_SPACE(sizeof(int))];
msg.msg_control = control;
msg.msg_controllen = sizeof(control);
msg.msg_name = NULL;
msg.msg_namelen = 0;
iov[0].iov_base = buffer;
iov[0].iov_len = buff_size;
msg.msg_iov = iov;
msg.msg_iovlen = 1;
ssize_t status = recvmsg(m_bindSocket, &msg, MSG_DONTWAIT);
if ((status <= 0) && (errno != EAGAIN)) {
printf("%s : recvmsg failed, with error = %s\n", __PRETTY_FUNCTION__, strerror(errno));
return false;
}
BufferInfo *tmp = (BufferInfo*)buffer;
printf("ckt test:recvBufferAndFd framecount %lu\n", tmp->frameCount);
} while (errno != EAGAIN);
printf("ckt test: erron: %d\n", errno);
cmsghdr* cmsgPtr = CMSG_FIRSTHDR(&msg);
fd_recv = *((int *)CMSG_DATA(cmsgPtr));
return true;
}
int main(int argc, char const *argv[])
{
BufferInfo info;
int len = sizeof(info);
int fd;
start();
while (1)
{
recvBufferAndFd(&info, len, fd);
std::cout << "frameCount: " << info.frameCount << " len: " << len << " fd: " << fd << std::endl;
sleep(5);
close(fd);
}
return 0;
}
客户
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#include <errno.h>
#include <stdio.h>
#include <string>
#include "TBufferCommon.h"
int retCode = 0;
void start(std::string destName) {
int sendSocket;
retCode = socket(AF_UNIX, SOCK_DGRAM, 0);
if (retCode == -1) {
printf("failed to setup TBufferServer send socket , error: %s\n", strerror(errno));
return;
}
sendSocket = retCode;
sockaddr_un addr;
(void)memset(&addr, 0, sizeof(addr));
addr.sun_family = AF_UNIX;
memcpy(addr.sun_path, destName.c_str(), destName.size());
int conCode = connect(sendSocket, (const sockaddr *)&addr, sizeof(addr));
if (conCode != 0) {
close(sendSocket);
printf("failed to conect TBufferServer send socket , error: %s\n", strerror(errno));
return;
}
}
const bool sendBufferAndFdWithDestName(void *buf, int buf_size, int fd_sent)
{
msghdr msg;
iovec iov[1];
char control[CMSG_SPACE(sizeof(int))];
msg.msg_control = control;
msg.msg_controllen = sizeof(control);
cmsghdr *cmsgPtr = CMSG_FIRSTHDR(&msg);
cmsgPtr->cmsg_len = CMSG_LEN(sizeof(int));
cmsgPtr->cmsg_level = SOL_SOCKET;
cmsgPtr->cmsg_type = SCM_RIGHTS;
*((int *)CMSG_DATA(cmsgPtr)) = fd_sent;
msg.msg_name = NULL;
msg.msg_namelen = 0;
iov[0].iov_base = buf;
iov[0].iov_len = buf_size;
msg.msg_iov = iov;
msg.msg_iovlen = 1;
int sndCode = sendmsg(retCode, &msg, MSG_DONTWAIT);
if (sndCode <= 0)
{
printf("%s : sendmsg failed, with error = %s\n", __PRETTY_FUNCTION__, strerror(errno));
close(retCode);
return false;
}
return true;
}
int main(void) {
BufferInfo info;
info.frameCount = 0;
start("/tmp/test");
while (1) {
++info.frameCount;
if(sendBufferAndFdWithDestName(&info, sizeof(info), 1)) {
printf("sendBufferAndFdWithDestName: frameCount: %lu\n", info.frameCount);
}
sleep(4);
}
close(retCode);
}
您可以看到客户端发送频率大于服务器接收频率。但是我使用 do-while 循环将旧消息转储到接收缓冲区中,所以期望输出打印应该像:
- 客户端的 frameCount 比服务器增加快 2 或 3;
- 但是服务器比丢弃一些旧消息然后赶上客户端。
但事实是下面的程序打印日志:
sendBufferAndFdWithDestName: frameCount: 49
ckt test:recvBufferAndFd framecount 39
ckt test: erron: 11
frameCount: 39 len: 32 fd: 4
sendBufferAndFdWithDestName: frameCount: 50
sendBufferAndFdWithDestName: frameCount: 51
ckt test:recvBufferAndFd framecount 40
ckt test: erron: 11
frameCount: 40 len: 32 fd: 4
sendBufferAndFdWithDestName: frameCount: 52
ckt test:recvBufferAndFd framecount 41
ckt test: erron: 11
frameCount: 41 len: 32 fd: 4
sendBufferAndFdWithDestName: frameCount: 53
ckt test:recvBufferAndFd framecount 42
ckt test: erron: 11
frameCount: 42 len: 32 fd: 4
从日志中,它显示服务器没有收到消息,甚至客户端已经发送。
当我将 msg_control 设置为 NULL 时,输出打印与我期望的相同。
所以我的问题是:套接字缓冲区在 SCM_RIGHTS 类型时会发送消息吗?
感谢您的回复。
BR/蒂姆
解决方案
推荐阅读
- php - 在匿名函数上“使用”的动态元素
- python - 如何创建通过多个别名定义的递归 Python 类型?
- reporting-services - 在 SSRS 中,如何在可见性表达式解析后有条件地格式化表格行的背景颜色?
- soap - 没有标头的 SOAP 消息 - 如何处理?
- excel - 突出显示与所选单元格对应的行/列的最快方法
- python - 如果我在尝试检索值时指定参数,则会出现“对象不可调用”错误
- java - 我如何正确引用此代码中的石头重量?
- javascript - 扩展 Object.setPrototypeOf() 与 Object.create
- amazon-web-services - 如何使用 Amazon ECS 运行 docker 任务 - 出现错误`STOPPED (CannotStartContainerError: Error response from dae)`
- ios - Phonegap/Cordova Barcodescanner 在最新的 ios 13 上再次全屏显示