C socket编程,在树莓派上获取服务器IP

C socket programming, getting IP of server on raspberrypi

我正在 Raspberry Pi 上编写一个服务器应用程序,并在 TCP/IP 套接字上进行通信,但我无法显示我正在监听的套接字的 IP。我找到了两个解决方案,其中 none 个有效。

第一个解决方案:

char hostName[255];
struct hostent *host_entry;
char * szLocalIP;
gethostname(hostName, 255);
host_entry = gethostbyname(hostName);
szLocalIP = inet_ntoa (*(struct in_addr *)host_entry->h_addr);
printf("Server runs on IP: %s, port: %d\n\n", szLocalIP, ntohs(server_address.sin_port));

输出:Server runs on IP: 0.0.0.0, port: 5000

第二种解决方案:

struct sockaddr_in server_address;
char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV];
if (getnameinfo((struct sockaddr *)&server_address, server_len, hbuf, sizeof(hbuf), sbuf, sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV) == 0)
         printf("Server runs on IP: %s, port: %s\n\n", hbuf, sbuf);

输出:Server runs on IP: 127.0.1.1, port: 5000

完整代码:

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

#define PORT 5000
#define MAX_QUEUE 3
#define NAME "Server"

int main()
{
    int server_file_descriptor, new_connection;
    long valread;
    unsigned long counter = 1;
    struct sockaddr_in server_address, client_address;
    socklen_t server_len, client_len;
    int opt = 1;
    char buffer[1024] = {0};

    char hostName[255];
    struct hostent *host_entry;
    char * szLocalIP;

    char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV];

    char *hello = "Temperature send";

    if ((server_file_descriptor = socket(AF_INET, SOCK_STREAM, 0)) == -1)
    {
        perror("socket failed");
        exit(EXIT_FAILURE);
    }

    if (setsockopt(server_file_descriptor, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt)))
    {
        perror("setsockopt");
        exit(EXIT_FAILURE);
    }

    server_address.sin_family = AF_INET;
    server_address.sin_addr.s_addr = INADDR_ANY;
    server_address.sin_port = htons(PORT);

    server_len = sizeof(server_address);

    if (bind(server_file_descriptor, (struct sockaddr *)&server_address, server_len))
    {
        perror("bind failed");
        exit(EXIT_FAILURE);
    }

    if (listen(server_file_descriptor, MAX_QUEUE))
    {
        perror("listen failed");
        exit(EXIT_FAILURE);
    }

    gethostname(hostName, 255);
    host_entry = gethostbyname(hostName);
    szLocalIP = inet_ntoa (*(struct in_addr *)host_entry->h_addr);

    if (getnameinfo((struct sockaddr *)&server_address, server_len, hbuf, sizeof(hbuf), sbuf, sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV) == 0)
         printf("1 - Server runs on IP: %s, port: %s\n\n", hbuf, sbuf);

    printf("2 - Server runs on IP: %s, port: %d\n\n", szLocalIP, ntohs(server_address.sin_port));
    printf("3 - Server runs on IP: %s, port: %d\n\n", inet_ntoa(server_address.sin_addr), ntohs(server_address.sin_port));

    client_len = sizeof(client_address);

    for (;;counter++)
    {
        if ((new_connection = accept(server_file_descriptor, (struct sockaddr *)&client_address, &client_len)) == -1)
        {
            perror("accept failed");
            exit(EXIT_FAILURE);
        }

        printf("%s: got connection from %s on port: %d.\n", NAME, inet_ntoa(client_address.sin_addr), ntohs(client_address.sin_port));

        valread = read( new_connection , buffer, 1024);

        printf("%s sends request: %s\n", inet_ntoa(client_address.sin_addr), buffer);

        if (strcmp(buffer, "get_temp") == 0)
        {
            send(new_connection , hello , strlen(hello) , 0 );
            printf("%s: message \"%s\" send to %s.\n", NAME, hello, inet_ntoa(client_address.sin_addr));
        }
        else
        {
            send(new_connection , "Unknown command\n" , 15 , 0 );
            printf("%s: message \"Unknown command\" send to %s.\n", NAME, inet_ntoa(client_address.sin_addr));
        }
        printf("%s: closing connection with: %s.\n", NAME, inet_ntoa(client_address.sin_addr));
        printf("Handled calls: %ld\n\n", counter);
        close(new_connection);
        memset(buffer, 0, sizeof(buffer));
    }
}

第三个 printf 的输出与第一个相同。

答案 0.0.0.0 是正确的。

更准确地说,当您打开一个服务器套接字时,它并没有一个特定的、明确定义的地址。因此,如果您向 "find the local address this socket is listening to" 请求任何系统调用,它们将 return 通配符地址 0.0.0.0。 此外,您可以使用许多不同的目标地址连接到服务器:例如“127.0.0.1”、“127.1.2.3”、“192.168.40.21”(您的网络接口地址)等

如果您想收听特定地址,您需要将该地址传递给bind()。例如,这段代码监听一个特定的本地地址 127.1.2.3:

server_address.sin_family = AF_INET;
server_address.sin_addr.s_addr = inet_addr("127.1.2.3");
server_address.sin_port = htons(PORT);
if (bind(server_file_descriptor, (struct sockaddr *)&server_address, sizeof(server_address)))
   ...

输出:

3 - Server runs on IP: 127.1.2.3, port: 5000

问题是与“127.0.0.1”、“192.168.40.21”和所有其他地址的连接现在将失败,因为您已将服务器限制为只能在特定地址上访问。

但是,在您的初始示例中确实有一个明确定义的地址。它是接受连接后创建的客户端套接字。如果在 accept() 调用之后添加此代码,您将看到客户端已连接到的地址:

    struct sockaddr_in addr;
    socklen_t len;
    len = sizeof(addr);
    getsockname(new_connection, (struct sockaddr *)&addr, &len);
    printf("Client connected to: %s, port: %d\n\n", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));

此地址对于不同的客户端可能不同:即一个客户端可能连接到“127.0.0.1”,另一个连接到“192.168.40.21”。