有一種情況,一個進程打開串口並配置它的終端參數。如何將這個文件描述符共享到另外兩個也將通過串口傳輸數據的進程。 是否可以共享打開的文件描述符?如果是的話,那怎麼可能?在不同進程之間共享打開的文件描述符
編輯:注意一件事這三個過程是不相關的進程(不是父/子進程)
有一種情況,一個進程打開串口並配置它的終端參數。如何將這個文件描述符共享到另外兩個也將通過串口傳輸數據的進程。 是否可以共享打開的文件描述符?如果是的話,那怎麼可能?在不同進程之間共享打開的文件描述符
編輯:注意一件事這三個過程是不相關的進程(不是父/子進程)
最簡單的事情是在分離其他進程之前打開並配置文件描述符。這將爲您節省最多的麻煩。
假設這是不可能的,有一種方法。
創建一個unix域套接字。讓主進程在該套接字上偵聽。只要有人連接到它,發送SCM_RIGHTS cmsg。在我的Linux系統上,這是在手冊頁「cmsg(3)」中記錄的。在我的MacOS(我編寫示例代碼的地方),我無法找到它的記錄位置。
現在,在需要特殊文件描述符副本的進程中,打開unix域套接字,讀取cmsg,並且您現在擁有文件描述符。
下面是一些示例代碼。這很長,因爲整個過程非常冗長。它會做的是不共享任何文件描述符,它將描述符發送到文件'/ tmp/magic'到客戶端,客戶端將寫入一條消息給它。傳遞的文件描述符位於客戶端和服務器的本地變量magic
中。
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#include <stdio.h>
#include <err.h>
#include <fcntl.h>
#include <assert.h>
#include <string.h>
#include <stdlib.h>
#define SOCKET_NAME "/tmp/socket"
#define SPECIAL_FILE "/tmp/magic"
void
server(void)
{
struct sockaddr_un sun = { 0 };
socklen_t sunlen;
int l, fd, magic;
if ((magic = open(SPECIAL_FILE, O_RDWR|O_CREAT|O_TRUNC, 0600)) == -1)
err(1, "open");
if ((l = socket(PF_UNIX, SOCK_STREAM, 0)) == -1)
err(1, "server socket");
unlink(SOCKET_NAME);
sun.sun_family = AF_UNIX;
snprintf(sun.sun_path, sizeof(sun.sun_path), SOCKET_NAME);
if (bind(l, (struct sockaddr *)&sun, sizeof(sun)) == -1)
err(1, "bind");
if (listen(l, 5) == -1)
err(1, "listen");
sunlen = sizeof(sun);
while ((fd = accept(l, (struct sockaddr *)&sun, &sunlen)) != -1) {
struct msghdr msg = { 0 };
struct cmsghdr *cmsg;
struct iovec iov;
char buf[CMSG_SPACE(sizeof(magic))];
iov.iov_base = (void *)"ok";
iov.iov_len = 2;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = buf;
msg.msg_controllen = sizeof(buf);
cmsg = CMSG_FIRSTHDR(&msg);
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_RIGHTS;
cmsg->cmsg_len = CMSG_LEN(sizeof(magic));
*((int *)(void *)CMSG_DATA(cmsg)) = magic;
if (sendmsg(fd, &msg, 0) == -1)
err(1, "sendmsg");
close(fd);
}
close(l);
unlink(SOCKET_NAME);
}
void
client(void)
{
struct sockaddr_un sun = { 0 };
struct msghdr msg = { 0 };
struct cmsghdr *cmsg;
struct iovec iov;
int fd, magic;
char cbuf[CMSG_SPACE(sizeof(int))];
char buf[16];
if ((fd = socket(PF_UNIX, SOCK_STREAM, 0)) == -1) {
err(1, "socket");
}
sun.sun_family = AF_UNIX;
snprintf(sun.sun_path, sizeof(sun.sun_path), SOCKET_NAME);
if (connect(fd, (struct sockaddr *)&sun, sizeof(sun)) == -1) {
err(1, "connect");
}
iov.iov_base = buf;
iov.iov_len = sizeof(buf);
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = cbuf;
msg.msg_controllen = sizeof(cbuf);
if (recvmsg(fd, &msg, 0) == -1)
err(1, "recvmsg");
cmsg = CMSG_FIRSTHDR(&msg);
assert(cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS);
magic = *(int *)(void *)CMSG_DATA(cmsg);
if (write(magic, "hello", strlen("hello")) != strlen("hello"))
err(1, "write(magic)");
close(magic);
close(fd);
}
int
main(int argc, char **argv)
{
switch (fork()) {
case 0:
sleep(2); /* poor mans synchronization */
printf("starting client\n");
client();
_exit(0);
break;
case -1:
err(1, "fork");
default:
printf("starting server\n");
server();
exit(1);
}
return 1;
}
有關的例子一些注意事項:
malloc
甚至posix_memalign
更好的對齊緩衝區。雖然我不是OP,但是謝謝你的努力!已經學會了東西.. :) – hek2mgl
@藝術感謝您的幫助 –
有一種方法可以做到這一點無論是使用管道或Unix域套接字。詳細信息請見here。
您必須擁有一個擁有串口的主進程,另一個進程將連接到主進程並請求主進程通過套接字發送數據。 –
請參閱此鏈接http://www.lst.de/~okir/blackhats/node121.html在此答案中給出:http://stackoverflow.com/a/9913281/694576 – alk
可能的重複[傳遞文件描述符從一個程序到另一個在同一主機上使用UNIX套接字](http://stackoverflow.com/questions/9911613/passing-file-descriptor-from-one-program-to-another-on-the-same-host-using- unix) – alk