c - 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.
解决方案
答案 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”。
推荐阅读
- r - 有没有办法在 R 中折叠加权平均值?
- react-native - 无法连接到开发环境
- cmd - 如何从命令提示符接收 WM_COPYDATA?
- arrays - 快速将 Xml 解析为字典
- node.js - 在 nodejs 中存储 api 访问令牌的位置
- javascript - 如何使用地图为表格单元格生成唯一ID
- python - 如何扩展 django-allauth 的注册模型并添加名字和姓氏字段?
- android - Firebase 无法与 Firebase 服务器通信
- github-actions - FTP-Deploy-Action:致命:肮脏的存储库:有未提交的更改。退出
- python - Python:为什么使用 for 循环将其从列表类型打印为空白(已编辑:案例已解决)