为什么netcat无法接收第二个广播消息?

时间:2016-10-22 17:20:33

标签: c sockets broadcast datagram netcat

在试验广播消息时(在Windows 7笔记本电脑上的VirtualBox 5.0.14上运行的Debian 8.3 VM上),我发现netcat(nc)只接收第一条广播消息。它不接收第二个广播消息。

程序

这是客户端程序。

If IsLiability Then
                    Set BalanceCell = .Offset(0, 2).Resize(1, 1)
                    BalanceCell.FormulaR1C1 = "=""Bal. "" & TEXT(SUM(R[-" & x & "]C:R[-1]C)-SUM(R[-" & x & "]C[1]:R[-1]C[1]),""$#,###"")"

                    y = Mid(BalanceCell.Value, 6, Len(BalanceCell.Value))

                    Debug.Print "Common Stock Balance is "; y

这是服务器程序。

// 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;
}

实验1:客户端=&gt;服务器(广播)

客户端程序显示以下输出。

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

服务器程序接收两个广播消息。

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

实验2:client =&gt; nc(广播)

但是,如果netcat作为端口9090上的侦听器运行,那么它 只接收第一个广播消息。

以下是客户端程序的输出。

$ ./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

服务器程序不接收第二个广播消息。

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

实验3:客户端=&gt; nc(单播)

接下来修改客户端程序client.c以创建新程序 client2.c,它使它单播。

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

以下是客户端程序的输出。

$ 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,

这次netcat收到两条单播消息。

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

系统调用跟踪

以下是实验2中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

以下是实验3中netcat的系统调用跟踪。

$ 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在实验2中没有收到两个广播消息?

1 个答案:

答案 0 :(得分:4)

以下是客户端程序的修改副本。我添加了一些缺少的include语句,删除了一些强制转换,添加了更多错误检查,并且,重要的更改,将调用移动到freeaddrinfo()。很多。 aii指针指向ai,用于调用sendto(),这不是一个好主意。

现在netcat看到两条消息都发送了,至少在我的机器上运行了Fedora 24.最初的客户端程序实际上在第二次调用sendto()时报告了一个错误。

HTH

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;
}