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”。
我正在 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”。