gpt4 book ai didi

c - 发送文件描述符时 sendmsg 不起作用

转载 作者:行者123 更新时间:2023-11-30 14:24:40 27 4
gpt4 key购买 nike

我正在使用 unix 域套接字在不同进程之间发送打开的文件描述符。 Unix 域套接字工作正常,但是当我使用 sendmsg 发送文件描述符时,发生了一些奇怪的事情。该函数在 sendmsg 之后返回,并且 sendmsg 没有返回任何内容。然后recvmsg给出Invalid Argument错误。这是我的代码。

客户端(发送文件描述符):

#include <stropts.h>
#include "accesories.c"
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#include <stdio.h>


#define CONTROLLEN CMSG_LEN(sizeof(int))
static struct cmsghdr *cmptr = NULL; /* malloc'ed first time */

int send_err(int fd, int errcode, const char *msg);
int send_fd(int fd, int fd_to_send);

int main(int argc, char const *argv[])
{
int fd_to_send;
if((fd_to_send = open("vi",O_RDONLY)) < 0)
printf("vi open failed");

struct sockaddr_un address;
int socket_fd, nbytes;
char buffer[256];

socket_fd = socket(PF_UNIX, SOCK_STREAM, 0);
if(socket_fd < 0)
{
printf("socket() failed\n");
return 1;
}

/* start with a clean address structure */
memset(&address, 0, sizeof(struct sockaddr_un));

address.sun_family = AF_UNIX;
snprintf(address.sun_path, sizeof(address.sun_path)-1, "./demo_socket");

if(connect(socket_fd, (struct sockaddr *) &address, sizeof(struct sockaddr_un)) != 0)
{
printf("connect() failed\n");
return 1;
}

nbytes = snprintf(buffer, 256, "hello from a client");
write(socket_fd, buffer, nbytes);

nbytes = read(socket_fd, buffer, 256);
buffer[nbytes] = 0;

printf("MESSAGE FROM SERVER: %s\n", buffer);

//sending the file descriptor
printf("From send_fd %d \n",send_fd(socket_fd,fd_to_send));

close(socket_fd);

exit(0);

}

int send_err(int fd, int errcode, const char *msg)
{
int n;

if ((n = strlen(msg)) > 0)
if (write(fd, msg, n) != n) /* send the error message */
return(-1);

if (errcode >= 0)
errcode = -1; /* must be negative */

if (send_fd(fd, errcode) < 0)
return(-1);

return(0);
}

int send_fd(int fd, int fd_to_send)
{

int temp;
struct iovec iov[1];
struct msghdr msg;
char buf[2]; /* send_fd()/recv_fd() 2-byte protocol */

iov[0].iov_base = buf;
iov[0].iov_len = 2;
msg.msg_iov = iov;
msg.msg_iovlen = 1;
msg.msg_name = NULL;
msg.msg_namelen = 0;
if (fd_to_send < 0) {
msg.msg_control = NULL;
msg.msg_controllen = 0;
buf[1] = -fd_to_send; /* nonzero status means error */
if (buf[1] == 0)
buf[1] = 1; /* -256, etc. would screw up protocol */
} else {
if (cmptr == NULL && (cmptr = malloc(CONTROLLEN)) == NULL)
return(-1);
cmptr->cmsg_level = SOL_SOCKET;
cmptr->cmsg_type = SCM_RIGHTS;
cmptr->cmsg_len = CONTROLLEN;
msg.msg_control = cmptr;
msg.msg_controllen = CONTROLLEN;
*(int *)CMSG_DATA(cmptr) = fd_to_send; /* the fd to pass */
buf[1] = 0; /* zero status means OK */
}
buf[0] = 0; /* null byte flag to recv_fd() */
printf("before sendmsg \n");
if (temp = sendmsg(fd, &msg, 0) != 2)
{
printf("inside sendmsg condition %d\n",temp);
return(-1);
}
printf("after sendmsg %d\n",temp);
return(0);

}

服务器(接收文件描述符):

#include <stropts.h>
#include "accesories.c"
#include <sys/ioctl.h>
#include <sys/un.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/socket.h>

#define MAXLINE 10
/* size of control buffer to send/recv one file descriptor */
#define CONTROLLEN CMSG_LEN(sizeof(int))

static struct cmsghdr *cmptr = NULL; /* malloc'ed first time */

int recv_fd(int fd, ssize_t (*userfunc)(int, const void *, size_t));
ssize_t errcheckfunc(int a,const void *b, size_t c);
int connection_handler(int connection_fd);

int main(int argc, char const *argv[])
{
struct sockaddr_un address;
int socket_fd, connection_fd;
socklen_t address_length;
pid_t child;

socket_fd = socket(PF_UNIX, SOCK_STREAM, 0);
if(socket_fd < 0)
{
printf("socket() failed\n");
return 1;
}

unlink("./demo_socket");

/* start with a clean address structure */
memset(&address, 0, sizeof(struct sockaddr_un));

address.sun_family = AF_UNIX;
snprintf(address.sun_path, sizeof(address.sun_path)-1, "./demo_socket");

if(bind(socket_fd, (struct sockaddr *) &address, sizeof(struct sockaddr_un)) != 0)
{
printf("bind() failed\n");
return 1;
}

if(listen(socket_fd, 5) != 0)
{
printf("listen() failed\n");
return 1;
}

while((connection_fd = accept(socket_fd, (struct sockaddr *) &address,&address_length)) > -1)
{
connection_handler(connection_fd);

int fd_to_recv;
fd_to_recv = recv_fd(socket_fd,&errcheckfunc);

if(read(fd_to_recv,msgbuf,5) < 0)
printf("message read failed");
printf("message received:%s\n",msgbuf);

close(connection_fd);
}

close(socket_fd);
unlink("./demo_socket");

return 0;
}

int recv_fd(int fd, ssize_t (*userfunc)(int, const void *, size_t))
{
int newfd, nr, status;
char *ptr;
char buf[MAXLINE];
struct iovec iov[1];
struct msghdr msg;

status = -1;
for ( ; ; )
{
iov[0].iov_base = buf;
iov[0].iov_len = sizeof(buf);
msg.msg_iov = iov;
msg.msg_iovlen = 1;
msg.msg_name = NULL;
msg.msg_namelen = 0;
if (cmptr == NULL && (cmptr = malloc(CONTROLLEN)) == NULL)
return(-1);
msg.msg_control = cmptr;
msg.msg_controllen = CONTROLLEN;
if ((nr = recvmsg(fd, &msg, 0)) < 0)
{
printf("recvmsg errrrror %d %d %s\n",nr,errno,strerror(errno));
//perror("recvmsg errrrror");
} else if (nr == 0)
{
perror("connection closed by server");
return(-1);
}
/*
* See if this is the final data with null & status. Null
* is next to last byte of buffer; status byte is last byte.
* Zero status means there is a file descriptor to receive.
*/
for (ptr = buf; ptr < &buf[nr]; )
{
if (*ptr++ == 0)
{
if (ptr != &buf[nr-1])
perror("message format error");
status = *ptr & 0xFF; /* prevent sign extension */
if (status == 0)
{
if (msg.msg_controllen != CONTROLLEN)
perror("status = 0 but no fd");
newfd = *(int *)CMSG_DATA(cmptr);
} else
{
newfd = -status;
}
nr -= 2;
}
}
if (nr > 0 && (*userfunc)(STDERR_FILENO, buf, nr) != nr)
return(-1);
if (status >= 0) /* final data has arrived */
return(newfd); /* descriptor, or -status */
}
}

ssize_t errcheckfunc(int a,const void *b, size_t c)
{
return 0;
}

int connection_handler(int connection_fd)
{
int nbytes;
char buffer[256];

nbytes = read(connection_fd, buffer, 256);
buffer[nbytes] = 0;

printf("MESSAGE FROM CLIENT: %s\n", buffer);
nbytes = snprintf(buffer, 256, "hello from the server");
write(connection_fd, buffer, nbytes);


return 0;
}

客户端输出:

MESSAGE FROM SERVER: hello from the server
before sendmsg

甚至不在sendmsg条件内在sendmsg打印?

最佳答案

自从功能请求 mark a comment as an answer仍被拒绝,我将上述解决方案复制到此处。

您对recvmsg()的调用正在尝试从监听套接字而不是连接的套接字接收数据,因为您的主循环将socket_fd传递给recv_fd()而不是connection_fd。 ——马修·斯莱特里

关于c - 发送文件描述符时 sendmsg 不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11481780/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com