C套接字编程,获取树莓派上服务器的IP

标签 c raspberry-pi tcp

我正在 Raspberry Pi 上编写一个通过 TCP/IP 套接字进行通信的服务器应用程序,但在显示我正在监听的套接字的 IP 时遇到了问题。我找到了两种解决方案,但没有一个有效。

第一个解决方案:

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

输出:服务器运行在IP:0.0.0.0,端口: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);

输出:服务器运行在IP:127.0.1.1,端口: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 是正确的。

更准确地说,当您打开服务器套接字时,它没有特定的、定义良好的地址。因此,如果您要求任何系统调用“查找此套接字正在监听的本地地址”,它们将返回通配符地址 0.0.0.0。 此外,您可以使用许多不同的目标地址连接到服务器:例如“127.0.0.1”、“127.1.2.3”、“192.168.40.21”(您的网络接口(interface)的地址)等。

如果你想监听一个特定的地址,你需要将该地址传递给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”。

关于C套接字编程,获取树莓派上服务器的IP,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52389255/

相关文章:

c - 尝试接受多个字符串输入

c - 使用一组元素初始化数组

linux - 尽管 ping 有效,但 apt-get 在树莓派上失败

java - 使用java sockets时是否保证数据有效性?

c# - 使用 TcpClient 类 C# 的异步套接字客户端

c++ - 委托(delegate)使用 boost asio TCP/IP 套接字

c - 如何在不使用数组的情况下检查整数中相同的数字?

关于grep的c程序

python - 如何使用 ADC 在 Raspberry Pi 中获得最高采样率?

python - 如何通过 I2C 使用 Raspberry pi 从 Arduino 读取数据