Wie zu verwenden sendmsg() zum senden einer Datei-Deskriptor über sockets zwischen 2 Prozessen?
Nachdem @cnicutar antwortet mir auf diese Frage, ich habe versucht, so senden Sie eine Datei-Deskriptor von dem übergeordneten Prozess zu seinem Kind. Basierend auf dieser Beispiel, schrieb ich diesen code:
int socket_fd ,accepted_socket_fd, on = 1;
int server_sd, worker_sd, pair_sd[2];
struct sockaddr_in client_address;
struct sockaddr_in server_address;
/* =======================================================================
* Setup the network socket.
* =======================================================================
*/
if((socket_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
perror("socket()");
exit(EXIT_FAILURE);
}
if((setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof(on))) < 0)
{
perror("setsockopt()");
exit(EXIT_FAILURE);
}
server_address.sin_family = AF_INET; /* Internet address type */
server_address.sin_addr.s_addr = htonl(INADDR_ANY); /* Set for any local IP */
server_address.sin_port = htons(port); /* Set to the specified port */
if(bind(socket_fd, (struct sockaddr *) &server_address, sizeof(server_address)) < 0)
{
perror("bind()");
exit(EXIT_FAILURE);
}
if(listen(socket_fd, buffers) < 0)
{
perror("listen()");
exit(EXIT_FAILURE);
}
if(socketpair(AF_UNIX, SOCK_DGRAM, 0, pair_sd) < 0)
{
socketpair("bind()");
exit(EXIT_FAILURE);
}
server_sd = pair_sd[0];
worker_sd = pair_sd[1];
/* =======================================================================
* Worker processes
* =======================================================================
*/
struct iovec iov[1];
struct msghdr child_msg;
char msg_buffer[80];
int pass_sd, rc;
/* Here the parent process create a pool of worker processes (its children) */
for(i = 0; i < processes; i++)
{
if(fork() == 0)
{
//...
/* Loop forever, serving the incoming request */
for(;;)
{
memset(&child_msg, 0, sizeof(child_msg));
memset(iov, 0, sizeof(iov));
iov[0].iov_base = msg_buffer;
iov[0].iov_len = sizeof(msg_buffer);
child_msg.msg_iov = iov;
child_msg.msg_iovlen = 1;
child_msg.msg_name = (char *) &pass_sd;
child_msg.msg_namelen = sizeof(pass_sd);
printf("Waiting on recvmsg\n");
rc = recvmsg(worker_sd, &child_msg, 0);
if (rc < 0)
{
perror("recvmsg() failed");
close(worker_sd);
exit(-1);
}
else if (child_msg.msg_namelen <= 0)
{
printf("Descriptor was not received\n");
close(worker_sd);
exit(-1);
}
else
{
printf("Received descriptor = %d\n", pass_sd);
}
//.. Here the child process can handle the passed file descriptor
}
}
}
/* =======================================================================
* The parent process
* =======================================================================
*/
struct msghdr parent_msg;
size_t length;
/* Here the parent will accept the incoming requests and passed it to its children*/
for(;;)
{
length = sizeof(client_address);
if((accepted_socket_fd = accept(socket_fd, NULL, NULL)) < 0)
{
perror("accept()");
exit(EXIT_FAILURE);
}
memset(&parent_msg, 0, sizeof(parent_msg));
parent_msg.msg_name = (char *) &accepted_socket_fd;
parent_msg.msg_namelen = sizeof(accepted_socket_fd);
if((sendmsg(server_sd, &parent_msg, 0)) < 0)
{
perror("sendmsg()");
exit(EXIT_FAILURE);
}
}
Aber leider bekam ich diese Fehlermeldung:
sendmsg(): Invalid argument
Was soll ich tun um dieses problem zu beheben? und bin ich mit der msghdr
Struktur korrekt? weil in dem Beispiel, das ich oben erwähnt, Sie verwenden msg_accrights
und msg_accrightslen
und ich habe einige Fehler, wenn ich Sie nutzen, so hatte ich die Verwendung msg_name
und msg_namelen
statt.
InformationsquelleAutor Eng.Fouad | 2011-12-12
Du musst angemeldet sein, um einen Kommentar abzugeben.
Dieser ist extrem schwer zu bekommen Recht. Ich würde empfehlen nur die Verwendung einer Bibliothek, die es für Sie tut. Eine der einfachsten ist libancillary. Es bietet Ihnen zwei Funktionen, eine zum senden einer Datei-Deskriptor über ein UNIX-domain-socket und zu empfangen. Sie sind absurd einfach zu bedienen.
InformationsquelleAutor David Schwartz
Das problem ist Sie übergeben, die den Datei-descriptor in einer
msg_name
Feld. Dies ist ein Feld "Adresse", und es ist nicht beabsichtigt, zu übergeben, beliebige Daten.In der Tat, die Datei-Deskriptoren übergeben werden sollen, in besonderer Weise, so dass die kernel duplizieren könnten, die den Datei-descriptor für den empfangenden Prozess (und vielleicht auch der Deskriptor wird ein weiterer Wert nach dem duplizieren). Das ist, warum es ist eine Besondere Nebenleistungen message-Typ (SCM_RIGHTS) zu übergeben, Datei-Deskriptoren.
Folgende arbeiten würde (ich weggelassen, einige der Fehlerbehandlung).
In client:
In server:
Siehe auch
man 3 cmsg
gibt es einige Beispiele.InformationsquelleAutor Inspired
Können Sie nicht schicken, Datei-Deskriptoren, über AF_INET. Verwenden Sie einen UNIX-domain-socket.
InformationsquelleAutor Per Schröder