Почему netcat не может получить второе широковещательное сообщение?

Экспериментируя с широковещательными сообщениями (на виртуальной машине Debian 8.3, работающей на VirtualBox 5.0.14 на ноутбуке с Windows 7), я обнаружил, что netcat (nc) получает только первое широковещательное сообщение. Он не получает второе широковещательное сообщение.

Программы

Вот клиентская программа.

// client.c
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>

#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netdb.h>

int main()
{
    int sockfd;
    int ret;
    char buffer[1024];
    ssize_t bytes;
    int yes = 1;
    struct addrinfo hints, *ai, *aii;

    memset(&hints, 0, sizeof hints);
    hints.ai_family = AF_INET;
    hints.ai_socktype = SOCK_DGRAM;

    if ((ret = getaddrinfo("255.255.255.255", "9090", &hints, &ai)) == -1) {
        fprintf(stderr, "client: getaddrinfo() error: %s\n", gai_strerror(ret));
        return EXIT_FAILURE;
    }

    for (aii = ai; aii != NULL; aii = aii->ai_next) {
        sockfd = socket(aii->ai_family, aii->ai_socktype, aii->ai_protocol);
        if (sockfd == -1) {
            perror("client: socket()");
            continue;
        }
        break;
    }

    freeaddrinfo(ai);

    if (aii == NULL) {
        fprintf(stderr, "client: cannot create socket\n");
        return EXIT_FAILURE;
    }

    if (setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &yes, sizeof yes) == -1) {
        perror("client: setsockopt()");
        return EXIT_FAILURE;
    }

    // 1st sendto().
    strncpy(buffer, "hello from client\n", sizeof buffer);
    bytes = sendto(sockfd, buffer, strlen(buffer), 0,
                   aii->ai_addr, aii->ai_addrlen);
    printf("client: sent %jd bytes\n", (intmax_t) bytes);

    // 2nd sendto().
    strncpy(buffer, "bye from client\n", sizeof buffer);
    bytes = sendto(sockfd, buffer, strlen(buffer), 0,
                   aii->ai_addr, aii->ai_addrlen);
    printf("client: sent %jd bytes\n", (intmax_t) bytes);

    close(sockfd);
    return EXIT_SUCCESS;
}

Вот серверная программа.

// server.c
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>

#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netdb.h>

int main()
{
    int sockfd;
    int ret;
    struct addrinfo hints, *ai, *aii;
    char ip[INET_ADDRSTRLEN];
    struct sockaddr_in *sa;

    memset(&hints, 0, sizeof hints);
    hints.ai_family = AF_INET;
    hints.ai_socktype = SOCK_DGRAM;
    hints.ai_flags = AI_PASSIVE;

    if ((ret = getaddrinfo(NULL, "9090", &hints, &ai)) == -1) {
        fprintf(stderr, "server: getaddrinfo() error: %s\n", gai_strerror(ret));
        return EXIT_FAILURE;
    }

    for (aii = ai; aii != NULL; aii = aii->ai_next) {

        sockfd = socket(aii->ai_family, aii->ai_socktype, aii->ai_protocol);
        if (sockfd == -1) {
            perror("socket()");
            continue;
        }

        if (bind(sockfd, aii->ai_addr, aii->ai_addrlen) == -1) {
            perror("bind()");
            close(sockfd);
            continue;
        }

        break;
    }

    if (aii == NULL) {
        fprintf(stderr, "server: error: could not bind to any address\n");
        return EXIT_FAILURE;
    }

    sa = (struct sockaddr_in *) aii->ai_addr;
    inet_ntop(AF_INET, &sa->sin_addr, ip, sizeof ip);
    printf("Bound to %s:%d.\n", ip, ntohs(sa->sin_port));

    freeaddrinfo(ai);

    /* recvfrom() loop */
    while (1) {
        struct sockaddr_storage conn_addr;
        socklen_t conn_addrlen = sizeof conn_addr;
        char buffer[1024];
        ssize_t bytes;

        bytes = recvfrom(sockfd, buffer, sizeof buffer, 0,
                         (struct sockaddr *) &conn_addr, &conn_addrlen);

        if (bytes <= 0)
            break;

        sa = (struct sockaddr_in *) &conn_addr;
        inet_ntop(AF_INET, &sa->sin_addr, ip, sizeof ip);

        printf("server: recvfrom() %jd bytes from %s:%d: %.*s",
               (intmax_t) bytes, ip, ntohs(sa->sin_port), (int) bytes,
               buffer);
    }

    close(sockfd);
    return EXIT_FAILURE;
}

Программы были составлены.

gcc -std=c99 -pedantic -Wall -Wextra -D_POSIX_C_SOURCE=200112L client.c -o client
gcc -std=c99 -pedantic -Wall -Wextra -D_POSIX_C_SOURCE=200112L server.c -o server

Эксперимент 1: клиент => сервер (трансляция)

Клиентская программа показывает следующий вывод.

$ ./client
client: sent 18 bytes
client: sent 16 bytes

Оба широковещательных сообщения принимаются серверной программой.

$ ./server 
Bound to 0.0.0.0:9090.
server: recvfrom() 18 bytes from 10.0.2.15:45807: hello from client
server: recvfrom() 16 bytes from 10.0.2.15:45807: bye from client

Эксперимент 2: клиент => nc (трансляция)

Однако, если вместо этого запустить netcat в качестве слушателя на порту 9090, он получит только первое широковещательное сообщение.

Вот вывод клиентской программы.

$ ./client
client: sent 18 bytes
client: sent 16 bytes

Программа сервера не получает второе широковещательное сообщение.

$ nc -vvnulp 9090
listening on [any] 9090 ...
connect to [10.0.2.15] from (UNKNOWN) [10.0.2.15] 39126
hello from client

Эксперимент 3: клиент => nc (уникаст)

Затем клиентская программа client.c модифицируется для создания новой программы client2.c, которая выполняет одноадресную рассылку.

$ diff -u client.c client2.c
--- client.c    2016-10-22 16:13:46.637123187 +0530
+++ client2.c   2016-10-22 16:13:41.313123187 +0530
@@ -16,14 +16,13 @@
     int ret;
     char buffer[1024];
     ssize_t bytes;
-    int yes = 1;
     struct addrinfo hints, *ai, *aii;

     memset(&hints, 0, sizeof hints);
     hints.ai_family = AF_INET;
     hints.ai_socktype = SOCK_DGRAM;

-    if ((ret = getaddrinfo("255.255.255.255", "9090", &hints, &ai)) == -1) {
+    if ((ret = getaddrinfo("10.0.2.15", "9090", &hints, &ai)) == -1) {
         fprintf(stderr, "client: getaddrinfo() error: %s\n", gai_strerror(ret));
         return EXIT_FAILURE;
     }
@@ -44,11 +43,6 @@
         return EXIT_FAILURE;
     }

-    if (setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &yes, sizeof yes) == -1) {
-        perror("client: setsockopt()");
-        return EXIT_FAILURE;
-    }
-
     // 1st sendto().
     strncpy(buffer, "hello from client\n", sizeof buffer);
     bytes = sendto(sockfd, buffer, strlen(buffer), 0,

Вот вывод клиентской программы.

$ gcc -std=c99 -pedantic -Wall -Wextra -D_POSIX_C_SOURCE=200112L client2.c -o client2
$ ./client2 
client: sent 18 bytes
client: sent 16 bytes

На этот раз netcat получает оба одноадресных сообщения.

$ nc -vvnulp 9090                                                                                                                                   
listening on [any] 9090 ...
connect to [10.0.2.15] from (UNKNOWN) [10.0.2.15] 55522
hello from client
bye from client

Трассировка системного вызова

Вот трассировка системного вызова для netcat в эксперименте 2.

$ strace nc -vvnulp 9090
execve("/bin/nc", ["nc", "-vvnulp", "9090"], [/* 39 vars */]) = 0
brk(0)                                  = 0xc19000
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f2fcd7ed000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=76016, ...}) = 0
mmap(NULL, 76016, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f2fcd7da000
close(3)                                = 0
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
open("/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0P\34\2\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=1738176, ...}) = 0
mmap(NULL, 3844640, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f2fcd224000
mprotect(0x7f2fcd3c6000, 2093056, PROT_NONE) = 0
mmap(0x7f2fcd5c5000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1a1000) = 0x7f2fcd5c5000
mmap(0x7f2fcd5cb000, 14880, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f2fcd5cb000
close(3)                                = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f2fcd7d9000
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f2fcd7d8000
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f2fcd7d7000
arch_prctl(ARCH_SET_FS, 0x7f2fcd7d8700) = 0
mprotect(0x7f2fcd5c5000, 16384, PROT_READ) = 0
mprotect(0x605000, 4096, PROT_READ)     = 0
mprotect(0x7f2fcd7ef000, 4096, PROT_READ) = 0
munmap(0x7f2fcd7da000, 76016)           = 0
getpid()                                = 4161
brk(0)                                  = 0xc19000
brk(0xc3a000)                           = 0xc3a000
open("/etc/resolv.conf", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=248, ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f2fcd7ec000
read(3, "# Generated by NetworkManager\nna"..., 4096) = 248
read(3, "", 4096)                       = 0
close(3)                                = 0
munmap(0x7f2fcd7ec000, 4096)            = 0
uname({sys="Linux", node="debian1", ...}) = 0
rt_sigaction(SIGINT, {0x4025d0, [INT], SA_RESTORER|SA_RESTART, 0x7f2fcd2590e0}, {SIG_DFL, [], 0}, 8) = 0
rt_sigaction(SIGQUIT, {0x4025d0, [QUIT], SA_RESTORER|SA_RESTART, 0x7f2fcd2590e0}, {SIG_DFL, [], 0}, 8) = 0
rt_sigaction(SIGTERM, {0x4025d0, [TERM], SA_RESTORER|SA_RESTART, 0x7f2fcd2590e0}, {SIG_DFL, [], 0}, 8) = 0
rt_sigaction(SIGURG, {SIG_IGN, [URG], SA_RESTORER|SA_RESTART, 0x7f2fcd2590e0}, {SIG_DFL, [], 0}, 8) = 0
rt_sigaction(SIGPIPE, {SIG_IGN, [PIPE], SA_RESTORER|SA_RESTART, 0x7f2fcd2590e0}, {SIG_DFL, [], 0}, 8) = 0
socket(PF_LOCAL, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0) = 3
connect(3, {sa_family=AF_LOCAL, sun_path="/var/run/nscd/socket"}, 110) = -1 ENOENT (No such file or directory)
close(3)                                = 0
socket(PF_LOCAL, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0) = 3
connect(3, {sa_family=AF_LOCAL, sun_path="/var/run/nscd/socket"}, 110) = -1 ENOENT (No such file or directory)
close(3)                                = 0
open("/etc/nsswitch.conf", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=529, ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f2fcd7ec000
read(3, "# /etc/nsswitch.conf\n#\n# Example"..., 4096) = 529
read(3, "", 4096)                       = 0
close(3)                                = 0
munmap(0x7f2fcd7ec000, 4096)            = 0
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=76016, ...}) = 0
mmap(NULL, 76016, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f2fcd7da000
close(3)                                = 0
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
open("/lib/x86_64-linux-gnu/tls/x86_64/libnss_db.so.2", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/lib/x86_64-linux-gnu/tls/x86_64", 0x7ffe5c622430) = -1 ENOENT (No such file or directory)
open("/lib/x86_64-linux-gnu/tls/libnss_db.so.2", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/lib/x86_64-linux-gnu/tls", 0x7ffe5c622430) = -1 ENOENT (No such file or directory)
open("/lib/x86_64-linux-gnu/x86_64/libnss_db.so.2", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/lib/x86_64-linux-gnu/x86_64", 0x7ffe5c622430) = -1 ENOENT (No such file or directory)
open("/lib/x86_64-linux-gnu/libnss_db.so.2", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/lib/x86_64-linux-gnu", {st_mode=S_IFDIR|0755, st_size=12288, ...}) = 0
open("/usr/lib/x86_64-linux-gnu/tls/x86_64/libnss_db.so.2", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/usr/lib/x86_64-linux-gnu/tls/x86_64", 0x7ffe5c622430) = -1 ENOENT (No such file or directory)
open("/usr/lib/x86_64-linux-gnu/tls/libnss_db.so.2", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/usr/lib/x86_64-linux-gnu/tls", 0x7ffe5c622430) = -1 ENOENT (No such file or directory)
open("/usr/lib/x86_64-linux-gnu/x86_64/libnss_db.so.2", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/usr/lib/x86_64-linux-gnu/x86_64", 0x7ffe5c622430) = -1 ENOENT (No such file or directory)
open("/usr/lib/x86_64-linux-gnu/libnss_db.so.2", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/usr/lib/x86_64-linux-gnu", {st_mode=S_IFDIR|0755, st_size=49152, ...}) = 0
open("/lib/tls/x86_64/libnss_db.so.2", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/lib/tls/x86_64", 0x7ffe5c622430) = -1 ENOENT (No such file or directory)
open("/lib/tls/libnss_db.so.2", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/lib/tls", 0x7ffe5c622430)        = -1 ENOENT (No such file or directory)
open("/lib/x86_64/libnss_db.so.2", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/lib/x86_64", 0x7ffe5c622430)     = -1 ENOENT (No such file or directory)
open("/lib/libnss_db.so.2", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/lib", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
open("/usr/lib/tls/x86_64/libnss_db.so.2", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/usr/lib/tls/x86_64", 0x7ffe5c622430) = -1 ENOENT (No such file or directory)
open("/usr/lib/tls/libnss_db.so.2", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/usr/lib/tls", 0x7ffe5c622430)    = -1 ENOENT (No such file or directory)
open("/usr/lib/x86_64/libnss_db.so.2", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/usr/lib/x86_64", 0x7ffe5c622430) = -1 ENOENT (No such file or directory)
open("/usr/lib/libnss_db.so.2", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/usr/lib", {st_mode=S_IFDIR|0755, st_size=12288, ...}) = 0
munmap(0x7f2fcd7da000, 76016)           = 0
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=76016, ...}) = 0
mmap(NULL, 76016, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f2fcd7da000
close(3)                                = 0
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
open("/lib/x86_64-linux-gnu/libnss_files.so.2", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\240\"\0\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0644, st_size=47712, ...}) = 0
mmap(NULL, 2144392, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f2fcd018000
mprotect(0x7f2fcd023000, 2093056, PROT_NONE) = 0
mmap(0x7f2fcd222000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0xa000) = 0x7f2fcd222000
close(3)                                = 0
mprotect(0x7f2fcd222000, 4096, PROT_READ) = 0
munmap(0x7f2fcd7da000, 76016)           = 0
open("/etc/services", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=19605, ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f2fcd7ec000
read(3, "# Network services, Internet sty"..., 4096) = 4096
read(3, "\t\t# IPX\nipx\t\t213/udp\nimap3\t\t220/"..., 4096) = 4096
read(3, "nessus\t\t1241/tcp\t\t\t# Nessus vuln"..., 4096) = 4096
read(3, "347/tcp\t\t\t# gnutella\ngnutella-rt"..., 4096) = 4096
read(3, "ureg\t779/udp\t\tmoira_ureg\t# Moira"..., 4096) = 3221
read(3, "", 4096)                       = 0
close(3)                                = 0
munmap(0x7f2fcd7ec000, 4096)            = 0
socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP) = 3
setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0
setsockopt(3, SOL_SOCKET, SO_REUSEPORT, [1], 4) = 0
bind(3, {sa_family=AF_INET, sin_port=htons(9090), sin_addr=inet_addr("0.0.0.0")}, 16) = 0
getsockname(3, {sa_family=AF_INET, sin_port=htons(9090), sin_addr=inet_addr("0.0.0.0")}, [16]) = 0
write(2, "listening on [any] 9090 ...", 27listening on [any] 9090 ...) = 27
write(2, "\n", 1
)                       = 1
rt_sigaction(SIGALRM, {SIG_IGN, [ALRM], SA_RESTORER|SA_RESTART, 0x7f2fcd2590e0}, {SIG_DFL, [], 0}, 8) = 0
alarm(0)                                = 0
rt_sigprocmask(SIG_BLOCK, NULL, [], 8)  = 0
recvfrom(3, "hello from client\n", 8192, MSG_PEEK, {sa_family=AF_INET, sin_port=htons(44926), sin_addr=inet_addr("10.0.2.15")}, [16]) = 18
rt_sigaction(SIGALRM, {SIG_IGN, [ALRM], SA_RESTORER|SA_RESTART, 0x7f2fcd2590e0}, {SIG_IGN, [ALRM], SA_RESTORER|SA_RESTART, 0x7f2fcd2590e0}, 8) = 0
alarm(0)                                = 0
connect(3, {sa_family=AF_INET, sin_port=htons(44926), sin_addr=inet_addr("10.0.2.15")}, 16) = 0
getsockopt(3, SOL_IP, IP_OPTIONS, "", [0]) = 0
getsockname(3, {sa_family=AF_INET, sin_port=htons(9090), sin_addr=inet_addr("10.0.2.15")}, [16]) = 0
write(2, "connect to [10.0.2.15] from (UNK"..., 55connect to [10.0.2.15] from (UNKNOWN) [10.0.2.15] 44926) = 55
write(2, "\n", 1
)                       = 1
select(4, [0 3], NULL, NULL, NULL)      = 1 (in [3])
read(3, "hello from client\n", 8192)    = 18
write(1, "hello from client\n", 18hello from client
)     = 18
select(4, [0 3], NULL, NULL, NULL

Вот трассировка системного вызова для netcat в эксперименте 3.

$ strace nc -vvnulp 9090
execve("/bin/nc", ["nc", "-vvnulp", "9090"], [/* 39 vars */]) = 0
brk(0)                                  = 0x198e000
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fcec1035000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=76016, ...}) = 0
mmap(NULL, 76016, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7fcec1022000
close(3)                                = 0
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
open("/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0P\34\2\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=1738176, ...}) = 0
mmap(NULL, 3844640, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fcec0a6c000
mprotect(0x7fcec0c0e000, 2093056, PROT_NONE) = 0
mmap(0x7fcec0e0d000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1a1000) = 0x7fcec0e0d000
mmap(0x7fcec0e13000, 14880, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7fcec0e13000
close(3)                                = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fcec1021000
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fcec1020000
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fcec101f000
arch_prctl(ARCH_SET_FS, 0x7fcec1020700) = 0
mprotect(0x7fcec0e0d000, 16384, PROT_READ) = 0
mprotect(0x605000, 4096, PROT_READ)     = 0
mprotect(0x7fcec1037000, 4096, PROT_READ) = 0
munmap(0x7fcec1022000, 76016)           = 0
getpid()                                = 4181
brk(0)                                  = 0x198e000
brk(0x19af000)                          = 0x19af000
open("/etc/resolv.conf", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=248, ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fcec1034000
read(3, "# Generated by NetworkManager\nna"..., 4096) = 248
read(3, "", 4096)                       = 0
close(3)                                = 0
munmap(0x7fcec1034000, 4096)            = 0
uname({sys="Linux", node="debian1", ...}) = 0
rt_sigaction(SIGINT, {0x4025d0, [INT], SA_RESTORER|SA_RESTART, 0x7fcec0aa10e0}, {SIG_DFL, [], 0}, 8) = 0
rt_sigaction(SIGQUIT, {0x4025d0, [QUIT], SA_RESTORER|SA_RESTART, 0x7fcec0aa10e0}, {SIG_DFL, [], 0}, 8) = 0
rt_sigaction(SIGTERM, {0x4025d0, [TERM], SA_RESTORER|SA_RESTART, 0x7fcec0aa10e0}, {SIG_DFL, [], 0}, 8) = 0
rt_sigaction(SIGURG, {SIG_IGN, [URG], SA_RESTORER|SA_RESTART, 0x7fcec0aa10e0}, {SIG_DFL, [], 0}, 8) = 0
rt_sigaction(SIGPIPE, {SIG_IGN, [PIPE], SA_RESTORER|SA_RESTART, 0x7fcec0aa10e0}, {SIG_DFL, [], 0}, 8) = 0
socket(PF_LOCAL, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0) = 3
connect(3, {sa_family=AF_LOCAL, sun_path="/var/run/nscd/socket"}, 110) = -1 ENOENT (No such file or directory)
close(3)                                = 0
socket(PF_LOCAL, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0) = 3
connect(3, {sa_family=AF_LOCAL, sun_path="/var/run/nscd/socket"}, 110) = -1 ENOENT (No such file or directory)
close(3)                                = 0
open("/etc/nsswitch.conf", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=529, ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fcec1034000
read(3, "# /etc/nsswitch.conf\n#\n# Example"..., 4096) = 529
read(3, "", 4096)                       = 0
close(3)                                = 0
munmap(0x7fcec1034000, 4096)            = 0
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=76016, ...}) = 0
mmap(NULL, 76016, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7fcec1022000
close(3)                                = 0
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
open("/lib/x86_64-linux-gnu/tls/x86_64/libnss_db.so.2", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/lib/x86_64-linux-gnu/tls/x86_64", 0x7ffcde8fa140) = -1 ENOENT (No such file or directory)
open("/lib/x86_64-linux-gnu/tls/libnss_db.so.2", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/lib/x86_64-linux-gnu/tls", 0x7ffcde8fa140) = -1 ENOENT (No such file or directory)
open("/lib/x86_64-linux-gnu/x86_64/libnss_db.so.2", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/lib/x86_64-linux-gnu/x86_64", 0x7ffcde8fa140) = -1 ENOENT (No such file or directory)
open("/lib/x86_64-linux-gnu/libnss_db.so.2", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/lib/x86_64-linux-gnu", {st_mode=S_IFDIR|0755, st_size=12288, ...}) = 0
open("/usr/lib/x86_64-linux-gnu/tls/x86_64/libnss_db.so.2", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/usr/lib/x86_64-linux-gnu/tls/x86_64", 0x7ffcde8fa140) = -1 ENOENT (No such file or directory)
open("/usr/lib/x86_64-linux-gnu/tls/libnss_db.so.2", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/usr/lib/x86_64-linux-gnu/tls", 0x7ffcde8fa140) = -1 ENOENT (No such file or directory)
open("/usr/lib/x86_64-linux-gnu/x86_64/libnss_db.so.2", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/usr/lib/x86_64-linux-gnu/x86_64", 0x7ffcde8fa140) = -1 ENOENT (No such file or directory)
open("/usr/lib/x86_64-linux-gnu/libnss_db.so.2", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/usr/lib/x86_64-linux-gnu", {st_mode=S_IFDIR|0755, st_size=49152, ...}) = 0
open("/lib/tls/x86_64/libnss_db.so.2", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/lib/tls/x86_64", 0x7ffcde8fa140) = -1 ENOENT (No such file or directory)
open("/lib/tls/libnss_db.so.2", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/lib/tls", 0x7ffcde8fa140)        = -1 ENOENT (No such file or directory)
open("/lib/x86_64/libnss_db.so.2", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/lib/x86_64", 0x7ffcde8fa140)     = -1 ENOENT (No such file or directory)
open("/lib/libnss_db.so.2", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/lib", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
open("/usr/lib/tls/x86_64/libnss_db.so.2", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/usr/lib/tls/x86_64", 0x7ffcde8fa140) = -1 ENOENT (No such file or directory)
open("/usr/lib/tls/libnss_db.so.2", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/usr/lib/tls", 0x7ffcde8fa140)    = -1 ENOENT (No such file or directory)
open("/usr/lib/x86_64/libnss_db.so.2", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/usr/lib/x86_64", 0x7ffcde8fa140) = -1 ENOENT (No such file or directory)
open("/usr/lib/libnss_db.so.2", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/usr/lib", {st_mode=S_IFDIR|0755, st_size=12288, ...}) = 0
munmap(0x7fcec1022000, 76016)           = 0
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=76016, ...}) = 0
mmap(NULL, 76016, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7fcec1022000
close(3)                                = 0
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
open("/lib/x86_64-linux-gnu/libnss_files.so.2", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\240\"\0\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0644, st_size=47712, ...}) = 0
mmap(NULL, 2144392, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fcec0860000
mprotect(0x7fcec086b000, 2093056, PROT_NONE) = 0
mmap(0x7fcec0a6a000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0xa000) = 0x7fcec0a6a000
close(3)                                = 0
mprotect(0x7fcec0a6a000, 4096, PROT_READ) = 0
munmap(0x7fcec1022000, 76016)           = 0
open("/etc/services", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=19605, ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fcec1034000
read(3, "# Network services, Internet sty"..., 4096) = 4096
read(3, "\t\t# IPX\nipx\t\t213/udp\nimap3\t\t220/"..., 4096) = 4096
read(3, "nessus\t\t1241/tcp\t\t\t# Nessus vuln"..., 4096) = 4096
read(3, "347/tcp\t\t\t# gnutella\ngnutella-rt"..., 4096) = 4096
read(3, "ureg\t779/udp\t\tmoira_ureg\t# Moira"..., 4096) = 3221
read(3, "", 4096)                       = 0
close(3)                                = 0
munmap(0x7fcec1034000, 4096)            = 0
socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP) = 3
setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0
setsockopt(3, SOL_SOCKET, SO_REUSEPORT, [1], 4) = 0
bind(3, {sa_family=AF_INET, sin_port=htons(9090), sin_addr=inet_addr("0.0.0.0")}, 16) = 0
getsockname(3, {sa_family=AF_INET, sin_port=htons(9090), sin_addr=inet_addr("0.0.0.0")}, [16]) = 0
write(2, "listening on [any] 9090 ...", 27listening on [any] 9090 ...) = 27
write(2, "\n", 1
)                       = 1
rt_sigaction(SIGALRM, {SIG_IGN, [ALRM], SA_RESTORER|SA_RESTART, 0x7fcec0aa10e0}, {SIG_DFL, [], 0}, 8) = 0
alarm(0)                                = 0
rt_sigprocmask(SIG_BLOCK, NULL, [], 8)  = 0
recvfrom(3, "hello from client\n", 8192, MSG_PEEK, {sa_family=AF_INET, sin_port=htons(50392), sin_addr=inet_addr("10.0.2.15")}, [16]) = 18
rt_sigaction(SIGALRM, {SIG_IGN, [ALRM], SA_RESTORER|SA_RESTART, 0x7fcec0aa10e0}, {SIG_IGN, [ALRM], SA_RESTORER|SA_RESTART, 0x7fcec0aa10e0}, 8) = 0
alarm(0)                                = 0
connect(3, {sa_family=AF_INET, sin_port=htons(50392), sin_addr=inet_addr("10.0.2.15")}, 16) = 0
getsockopt(3, SOL_IP, IP_OPTIONS, "", [0]) = 0
getsockname(3, {sa_family=AF_INET, sin_port=htons(9090), sin_addr=inet_addr("10.0.2.15")}, [16]) = 0
write(2, "connect to [10.0.2.15] from (UNK"..., 55connect to [10.0.2.15] from (UNKNOWN) [10.0.2.15] 50392) = 55
write(2, "\n", 1
)                       = 1
select(4, [0 3], NULL, NULL, NULL)      = 1 (in [3])
read(3, "hello from client\n", 8192)    = 18
write(1, "hello from client\n", 18hello from client
)     = 18
select(4, [0 3], NULL, NULL, NULL)      = 1 (in [3])
read(3, "bye from client\n", 8192)      = 16
write(1, "bye from client\n", 16bye from client
)       = 16
select(4, [0 3], NULL, NULL, NULL

Вопрос

Почему netcat не получает оба широковещательных сообщения в эксперименте 2?


person Susam Pal    schedule 22.10.2016    source источник
comment
Пожалуйста, укажите, решает ли ответ @bjorn-a вашу проблему   -  person Bodo Thiesen    schedule 01.11.2016
comment
@BodoThiesen Ответ Бьорна не сработал для меня в моей среде. Я добавил комментарий к его ответу, чтобы отметить это.   -  person Susam Pal    schedule 02.11.2016


Ответы (1)


Ниже представлена ​​модифицированная копия вашей клиентской программы. Я добавил несколько отсутствующих операторов включения, удалил несколько приведений типов, добавил дополнительную проверку ошибок и, что важно, переместил вызов freeaddrinfo() вниз. Много. Указатель aii, указывающий на ai, использовался в вызовах sendto(), это не очень хорошая идея.

Теперь netcat видит оба отправленных сообщения, по крайней мере, на моей машине с Fedora 24. Исходная клиентская программа фактически сообщила об ошибке при втором вызове sendto().

ХТН

PS: Спасибо за очень хорошо сформулированный вопрос.

#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main(void)
{
    int sockfd;
    int ret;
    ssize_t bytes;
    int yes = 1;
    struct addrinfo hints, *ai, *aii;
    char *msg;

    memset(&hints, 0, sizeof hints);
    hints.ai_family = AF_INET;
    hints.ai_socktype = SOCK_DGRAM;

    if ((ret = getaddrinfo("255.255.255.255", "9090", &hints, &ai)) == -1) {
        fprintf(stderr, "client: getaddrinfo() error: %s\n", gai_strerror(ret));
        return EXIT_FAILURE;
    }

    for (aii = ai; aii != NULL; aii = aii->ai_next) {
        sockfd = socket(aii->ai_family, aii->ai_socktype, aii->ai_protocol);
        if (sockfd == -1) {
            perror("client: socket()");
            continue;
        }
        break;
    }

    if (aii == NULL) {
        fprintf(stderr, "client: cannot create socket\n");
        return EXIT_FAILURE;
    }

    if (setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &yes, sizeof yes) == -1) {
        perror("client: setsockopt()");
        return EXIT_FAILURE;
    }

    // 1st sendto().
    msg = "hello from client\n";
    bytes = sendto(sockfd, msg, strlen(msg), 0, aii->ai_addr, aii->ai_addrlen);
    if (bytes == -1) {
        perror("sendto 1");
        return EXIT_FAILURE;
    }
    printf("client: sent %zd bytes\n", bytes);

    // 2nd sendto().
    msg = "bye from client\n";
    bytes = sendto(sockfd, msg, strlen(msg), 0, aii->ai_addr, aii->ai_addrlen);
    if (bytes == -1) {
        perror("sendto 2");
        return EXIT_FAILURE;
    }

    printf("client: sent %zd bytes\n", bytes);

    close(sockfd);
    freeaddrinfo(ai);
    return EXIT_SUCCESS;
}
person Bjorn A.    schedule 26.10.2016
comment
Спасибо за подробный ответ. Я скопировал вашу программу в файл с именем foo.c и запустил gcc -std=c99 -pedantic -Wall -Wextra -D_POSIX_C_SOURCE=200112L foo.c && ./a.out, в то время как nc -vvnulp 9090 уже работал на другом терминале. Хотя ./a.out показывает, что отправлено два сообщения, nc показывает, что получено только первое сообщение. Так что это решение не сработало для моей виртуальной машины Debian 8.3, работающей на VirtualBox 5.0.14 на ноутбуке с Windows 7. - person Susam Pal; 02.11.2016
comment
Я присудил награду за ваш ответ, потому что ваш ответ хорошо написан и решает проблему для вашей конкретной среды (Fedora 24). Тем не менее, я оставляю свой вопрос без ответа, так что любой, кто наткнется на этот вопрос, может опубликовать ответ, который решает проблему для моей конкретной среды (Debian 8.3). Я могу начать еще одну награду за этот вопрос в будущем. - person Susam Pal; 02.11.2016