首页 > 解决方案 > C socket programming, getting IP of server on raspberrypi

问题描述

I am writing a server application on Raspberry Pi with communication on TCP/IP sockets and I have trouble with showing an IP of socket I am listening on. I have found two solutions and none of them are working.

1st solution:

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

output: Server runs on IP: 0.0.0.0, port: 5000

2nd solution:

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

output: Server runs on IP: 127.0.1.1, port: 5000

full code:

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

output of 3rd printf is the same as 1st.

标签: craspberry-pitcp-ip

解决方案


答案 0.0.0.0 是正确的。

更准确地说,当您打开一个服务器套接字时,它没有一个特定的、明确定义的地址。因此,如果您要求任何系统调用“查找此套接字正在侦听的本地地址”,它们将返回通配符地址 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 - 服务器运行在 IP:127.1.2.3,端口: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”。


推荐阅读