gpt4 book ai didi

C套接字编程: get IP address (IPv6 or IPv4) server bounds to, 与客户端连接到?

转载 作者:行者123 更新时间:2023-11-30 14:57:09 26 4
gpt4 key购买 nike

我写了如下代码。此代码应该能够检索 PASSIVE_SOCKET(服务器绑定(bind)其套接字的位置)和 CONNECTION_SOCKET(客户端已连接的位置)的 IP 地址。

result_t print_socket_address(int sockfd, socket_type_t socket_type) {

char *ip_address; // address (passive) socket was binded to
int port; // port (passive) socket was binded to

switch(socket_type)
{
case PASSIVE_SOCKET:
if(get_current_address_and_port(sockfd, &ip_address, &port) == FAILURE) {
fprintf(stderr, "get_current_address_and_port: faild!\n");
free(ip_address);
return FAILURE;
}
printf("Created passive socket %d binded to %s:%d\n", sockfd, ip_address, port);
break;
case CONNECTION_SOCKET:
if(get_peer_address_and_port(sockfd, &ip_address, &port) == FAILURE) {
fprintf(stderr, "get_peer_address_and_port: faild!\n");
free(ip_address);
return FAILURE;
}
printf("Socket %d connected to %s:%d\n", sockfd, ip_address, port);
break;
default:
fprintf(stderr, "Incorrect socket type!\n");
free(ip_address);
return FAILURE;
}

free(ip_address);
return SUCCESS;
}

/**
* function retrieves current ip address and port
* socket is bound to for given socket file descriptor
*/
result_t get_current_address_and_port(int sockfd, char **ip_address, int *port) {

struct sockaddr sockaddr;
socklen_t sockaddrlen = sizeof(sockaddr);

if(getsockname(sockfd, &sockaddr, &sockaddrlen) < 0) {
fprintf(stderr, "getsockname: %s\n", strerror(errno));
return FAILURE;
}

sockaddr.sa_family = AF_INET6;

return get_address_and_port_from_sockaddr(&sockaddr, ip_address, port);
}

/**
* function retrieves peer ip address and port
* socket is connected to for given socket file descriptor
*/
result_t get_peer_address_and_port(int sockfd, char **ip_address, int *port) {

struct sockaddr sockaddr;
socklen_t sockaddrlen = sizeof(sockaddr);

if(getpeername(sockfd, &sockaddr, &sockaddrlen) < 0) {
fprintf(stderr, "getpeername: %s\n", strerror(errno));
return FAILURE;
}

return get_address_and_port_from_sockaddr(&sockaddr, ip_address, port);
}

/**
* function unwrap ip address and port from addrinfo structure
*/
result_t get_address_and_port_from_addrinfo(const struct addrinfo *addrinfo, char **ip_address, int *port) {

return get_address_and_port_from_sockaddr((struct sockaddr *)addrinfo->ai_addr, ip_address, port);
}

/**
* function unwrap ip address and port from sockaddr structure
*/
result_t get_address_and_port_from_sockaddr(const struct sockaddr *sockaddr, char **ip_address, int *port) {

*ip_address = (char *) malloc(INET6_ADDRSTRLEN * sizeof(char));

// converting network address to presentation address
if(inet_ntop(sockaddr->sa_family, get_in_addr(sockaddr), *ip_address, INET6_ADDRSTRLEN * sizeof(char)) == NULL) {
fprintf(stderr, "inet_ntop: %s\n", strerror(errno));
return FAILURE;
}

// converting network port to host port
*port = ntohs(get_in_port(sockaddr));

return SUCCESS;
}

/**
* function unwrap in_addr or in6_addr structure from
* sockaddr structure depending on address family
* AF_INET or AF_INET6
*/
void *get_in_addr(const struct sockaddr *sa) {

if( sa->sa_family == AF_INET) // IPv4 address
return &(((struct sockaddr_in*)sa)->sin_addr);
// else IPv6 address
return &(((struct sockaddr_in6*)sa)->sin6_addr);
}

/**
* function unwrap in_port from sockaddr structure
* depending on address family AF_INET or AF_INET6
*/
in_port_t get_in_port(const struct sockaddr *sa)
{
if( sa->sa_family == AF_INET ) // IPv4 address
return (((struct sockaddr_in*)sa)->sin_port);
// else IPv6 address
return (((struct sockaddr_in6*)sa)->sin6_port);
}

但是当我使用这段代码时,我得到了一些奇怪的行为。返回的我的服务器绑定(bind)套接字的 IP 地址例如:

Created passive socket 4 binded to ::ba54:431c:f9:55401

55401是端口号,它是正确的。但这是什么::ba54:431c:f9?我想这可能是 IPv6 的一部分。但为什么?我的电脑在局域网中的IP地址是192.168.8.102!此外,当我尝试通过客户端程序连接此服务器时,我必须使用 192.168.8.102 IP 地址进行连接,否则使用这个::ba54:431c:f9 我会收到类似“找不到路由”的错误?当客户端使用 192.168.8.102 IP 地址与服务器连接,然后打印它所连接的计算机的 IP 地址和端口号时,我得到另一个 ODD IP 地址,如下所示:

Socket 3 connected to ::3300:5208:6d16:9c88:55401

所以这里只有端口号匹配,IP地址不正确!更多关于客户端套接字在与服务器连接之前在本地绑定(bind)时绑定(bind)的 IP 地址与其所连接的计算机的 IP 地址相同(它是我的 LAN 网络中物理上不同的计算机),即::3300:5208:6d16:9c88:52040 ,其中 52040 是客户端绑定(bind)其套接字的端口。

我什至尝试将服务器计算机 192.168.8.1 的 IP 地址转换为 IPv6,但我得到的是这样的结果: 0:0:0:0:0:ffff:c0a8:866 以及在客户端程序中使用时的地址连接到服务器工作正常!但是使用上述函数的客户端打印出这个完全不同的IP地址,例如:::3300:5208:6d16:9c88:52040

那么我应该如何编写这个函数:

  1. 启用服务器打印其绑定(bind)的IP地址和端口号(一般来说IPv6或IPv4可以连接到它选择的任何地址/任何端口)

  2. 使客户端能够打印其绑定(bind)和连接的IP地址和端口号(通常可以根据需要使用IPv4或IPv6)。

我想在服务器程序中显示IP地址和端口号,然后我可以在客户端程序中使用它们来连接两者。现在我需要猜测它应该是在网络偏好设置中找到的我的计算机地址,并假设端口号是正确的,然后尝试连接。

最佳答案

get_current_address_and_port 中删除此行。

    sockaddr.sa_family = AF_INET6;

我不知道该行是如何写入您的代码中的,但它是不正确的。

通过删除该行,将解决 IPv4 的大部分问题。

您的代码被硬连线为使用struct sockaddr。 IIRC,无论如何,sockaddr 对于 IPv6 地址来说都不够大。我可以建议将其转换为 sockaddr_storage 以便初始调用 getsocknamegetpeername 以便您的代码可以更好地支持 IPv4 和 IPv6。

修复示例:

result_t get_current_address_and_port(int sockfd, char **ip_address, int *port) {

struct sockaddr_storage address = {0};
socklen_t sockaddrlen = sizeof(address);

if(getsockname(sockfd, (struct sockaddr*)(&address), &sockaddrlen) < 0) {
fprintf(stderr, "getsockname: %s\n", strerror(errno));
return FAILURE;
}

return get_address_and_port_from_sockaddr((struct sockaddr*)(&address), ip_address, port);
}


result_t get_peer_address_and_port(int sockfd, char **ip_address, int *port) {
struct sockaddr_storage address = {0};
socklen_t sockaddrlen = sizeof(address);

if(getpeername(sockfd, (struct sockaddr*)(&address), &sockaddrlen) < 0) {
fprintf(stderr, "getpeername: %s\n", strerror(errno));
return FAILURE;
}

return get_address_and_port_from_sockaddr((struct sockaddr*)(&address), ip_address, port);
}

关于C套接字编程: get IP address (IPv6 or IPv4) server bounds to, 与客户端连接到?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44098511/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com