use*_*143 10 c sockets webserver fork file-descriptor
我在Linux上的C程序中遇到了问题.
我知道当一个进程被分叉时,子进程从父进程继承了一些东西,包括打开文件描述符.
问题是我正在编写一个多进程服务器应用程序,其主进程接受新连接并将描述符放入共享内存.
当子进程尝试从共享内存中读取其中一个描述符时,select()我收到EBADF错误!
子进程如何读取并使用父进程分叉后创建的套接字(或一般的任何文件描述符)?
Rob*_*nes 15
当您调用fork时,子进程继承所有打开的文件描述符的副本.执行此操作的典型方法是父进程打开侦听套接字,调用accept阻塞直到连接到达,然后在接收连接后调用fork.然后父节点关闭它的文件描述符副本,而新的子进程可以继续使用文件描述符并进行所需的任何处理.孩子完成后,它也会关闭插座.记住两件事是很重要的:1.文件描述符/套接字是操作系统中的资源,在fork之后,父和子每个都有一个该资源的句柄,这有点像引用计数的智能指针.我在这里更详细地解释这一点.第二件事是,只有在调用fork 之前打开的文件描述符才被共享,因为在分配父和子之后是完全独立的进程,即使它们可能共享一些资源,比如在fork之前存在的文件描述符.如果您正在使用您希望将父工作分发给工作进程的模型,那么考虑使用线程和线程池可能会更好.
顺便说一下,你可以从Unix网络编程网站下载很多服务器和客户端的好例子.
Cel*_*ada 13
您不能通过共享内存将套接字(或任何其他文件描述符)从一个进程传输到另一个进程.文件描述符只是一个小整数.将此整数放在共享内存中并从另一个进程访问它不会从另一个进程的角度自动将相同的整数转换为有效的文件描述符.
将文件描述符从一个进程发送到另一个进程的正确方法是通过两个进程之间的现有套接字通信通道将其作为SCM_RIGHTS辅助数据发送sendmsg().
首先,socketpair()在您之前创建您的沟通渠道fork().现在,在父级中,关闭套接字对的一端,并在子级中关闭另一端.您现在可以sendmsg()从此套接字一端的父级接收,recvmsg()并使用另一端接收子级.
发送一条SCM_RIGHTS看起来像这样的消息:
struct msghdr m;
struct cmsghdr *cm;
struct iovec iov;
char buf[CMSG_SPACE(sizeof(int))];
char dummy[2];
memset(&m, 0, sizeof(m));
m.msg_controllen = CMSG_SPACE(sizeof(int));
m.msg_control = &buf;
memset(m.msg_control, 0, m.msg_controllen);
cm = CMSG_FIRSTHDR(&m);
cm->cmsg_level = SOL_SOCKET;
cm->cmsg_type = SCM_RIGHTS;
cm->cmsg_len = CMSG_LEN(sizeof(int));
*((int *)CMSG_DATA(cm)) = your_file_descriptor_to_send;
m.msg_iov = &iov;
m.msg_iovlen = 1;
iov.iov_base = dummy;
iov.iov_len = 1;
dummy[0] = 0; /* doesn't matter what data we send */
sendmsg(fd, &m, 0);
Run Code Online (Sandbox Code Playgroud)
SCM_RIGHTS在其中接收消息是这样的:
struct msghdr m;
struct cmsghdr *cm;
struct iovec iov;
struct dummy[100];
char buf[CMSG_SPACE(sizeof(int))];
ssize_t readlen;
int *fdlist;
iov.iov_base = dummy;
iov.iov_len = sizeof(dummy);
memset(&m, 0, sizeof(m));
m.msg_iov = &iov;
m.msg_iovlen = 1;
m.msg_controllen = CMSG_SPACE(sizeof(int));
m.msg_control = buf;
readlen = recvmsg(fd, &m, 0);
/* Do your error handling here in case recvmsg fails */
received_file_descriptor = -1; /* Default: none was received */
for (cm = CMSG_FIRSTHDR(&m); cm; cm = CMSG_NXTHDR(&m, cm)) {
if (cm->cmsg_level == SOL_SOCKET && cm->cmsg_type == SCM_RIGHTS) {
nfds = (cm->cmsg_len - CMSG_LEN(0)) / sizeof(int);
fdlist = (int *)CMSG_DATA(cm);
received_file_descriptor = *fdlist;
break;
}
}
Run Code Online (Sandbox Code Playgroud)