0

作業中のUDPサーバーに奇妙な問題があります。受信した最初のudpパケットには、パケットの送信元に関する情報がありません。後続のudpパケットはすべて正常であるように見え、パケットの受信元のIPアドレスが正しく表示されます。何がこの振る舞いを引き起こしているのか、おそらくいくつかの愚かな間違い、またはいくつかのあいまいなバグの原因がわかりません。Debianを実行しているLinuxマシンで使用しています。

fd_set master;
fd_set read_fds;
int fdmax;
int i;
int bytes_sent;
int bytes_recv;
socklen_t addr_len;
struct sockaddr_storage their_addr;

// provides users information needed to connect
serv_info *server_info;
server_info = (serv_info*) serv_config;

// Create UDP listener socket
int info_sock = createDGRAMSocket(NULL, server_info->port, 1);
char buffer[1024];
int len;
int send_response;

FD_SET(info_sock, &master);
fdmax = info_sock;
bytes_recv = recvfrom(i, buffer, sizeof(buffer), 0, (struct sockaddr *)&their_addr, &addr_len);
printf("Info started \n");
while (running) {
    read_fds = master;
    select(fdmax+1, &read_fds, NULL, NULL, NULL);
    for (i = 0; i <= fdmax; i++) {
        if (FD_ISSET(i, &read_fds)) {
            bytes_recv = recvfrom(i, buffer, sizeof(buffer), 0, (struct sockaddr *)&their_addr, &addr_len);
            printf("length %u: %s\n", bytes_recv, buffer);
            send_response = 0;

            switch (buffer[0]) {
                // Handle different packet types

            }

            struct sockaddr_in *sin = (struct sockaddr_in *)&their_addr;
            unsigned char *ip = (unsigned char *)&sin->sin_addr.s_addr;
            printf("IP: %d.%d.%d.%d\n", ip[0], ip[1], ip[2], ip[3]);

            if (send_response) {
                bytes_sent = sendto(info_sock, buffer, len, 0, (struct sockaddr *)&their_addr, sizeof(struct sockaddr_storage));
                if (bytes_sent < 0) {
                    printf("[ERROR] Packet Send Failed %d (%s) %d\n", bytes_sent, buffer, len);
                }
            }
        }
    }
};
close(info_sock);
4

1 に答える 1

5

addr_lenに初期化する必要がありますsizeof(their_addr)。マニュアルページによると:

引数addrlenは値結果引数であり、呼び出し元はsrc_addrに関連付けられたバッファーのサイズを呼び出す前に初期化し、戻り時に送信元アドレスの実際のサイズを示すように変更する必要があります。提供されたバッファが小さすぎる場合、返されるアドレスは切り捨てられます。この場合、addrlenは呼び出しに提供された値よりも大きい値を返します。

初期化addr_lenしていないため、値は0になっているようです(これは非常に未定義の動作です)。この場合、はバッファをrecvfrom()埋めませんが、マニュアルページが示すように、呼び出しに提供された値よりも大きい値を返します。したがって、最初の呼び出しが次の呼び出しでバッファーを適切に埋めることができる値を取得した後。ただし、これに依存することは安全ではありません。their_addraddr_lenaddr_lenrecvfrom()their_addr

于 2013-01-30T01:25:33.093 に答える