gpt4 book ai didi

c++ - 来自服务器套接字的错误 IP 和端口

转载 作者:太空狗 更新时间:2023-10-29 12:14:00 25 4
gpt4 key购买 nike

当我编写如下代码时,报告的对等方的 ip 和端口是正确的:

int main(){
int server = socket(AF_INET,SOCK_STREAM,0);
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(8080);
addr.sin_addr.s_addr = htonl(INADDR_ANY);
bind(server,(struct sockaddr *)&addr,sizeof addr);
listen(server,5);
struct sockaddr_storage inc_adrs;
socklen_t inc_len;
int client = accept(server, (struct sockaddr *) &inc_adrs,&inc_len);
struct sockaddr_in *inc_adr = (struct sockaddr_in *) &inc_adrs;
char ip [INET_ADDRSTRLEN];
inet_ntop(AF_INET,&(inc_adr->sin_addr),ip,INET_ADDRSTRLEN);
printf("Connection from %s port %d\n",ip,ntohs(inc_adr->sin_port));
return 0;
}

例如,我在本地计算机上使用 nc 连接到它:

#nc 127.0.0.1 8080

输出是:

Connection from 127.0.0.1 port 55112

但是如果我只是将它们放在另一个 block 中,例如“if”或“while”,程序会报告错误的 ip 和端口:

int main(){
if (1){
int server = socket(AF_INET,SOCK_STREAM,0);
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(8080);
addr.sin_addr.s_addr = htonl(INADDR_ANY);
bind(server,(struct sockaddr *)&addr,sizeof addr);
listen(server,5);
struct sockaddr_storage inc_adrs;
socklen_t inc_len;
int client = accept(server, (struct sockaddr *) &inc_adrs,&inc_len);
struct sockaddr_in *inc_adr = (struct sockaddr_in *) &inc_adrs;
char ip [INET_ADDRSTRLEN];
inet_ntop(AF_INET,&(inc_adr->sin_addr),ip,INET_ADDRSTRLEN);
printf("Connection from %s port %d\n",ip,ntohs(inc_adr->sin_port));
return 0;
}
}

示例输出:

Connection from 253.127.0.0 port 32323

我在 linux x64 上用“gcc code.c -o code”编译它。这很奇怪,我不知道这怎么可能。有什么想法吗?

最佳答案

好吧,看起来问题出在你如何使用man 2 accept:

The addrlen argument is a value-result argument: the caller must initialize it to contain the size (in bytes) of the structure pointed to by addr; on return it will contain the actual size of the peer address.

The returned address is truncated if the buffer provided is too small; in this case, addrlen will return a value greater than was supplied to the call.

通过以下修复加上 SO_REUSEADDR,您的代码可以正常工作:

    struct sockaddr_storage inc_adrs;
socklen_t inc_len = sizeof( inc_adrs );

此外,不要忘记检查来自socketbindlistenaccept 的结果值。

./a.out
Connection from 127.0.0.1 port 11111
---
nc 127.0.0.1 8080 -p 11111

Connection from 192.168.0.1 port 11111
---
nc 192.168.0.1 8080 -p 11111

您正在使用 struct sockaddr_storage inc_adrs;accept 之后可能(取决于 inc_len 中的随机值):

  • 将完整值复制到 inc_adrs
  • 将不完整的值复制到 inc_adrs
  • 如果 inc_len 恰好为零,则绝对不要触及 inc_adrs。

例如在我的例子中,if inc_len 为零。 inc_adrs 保持不变并包含一些垃圾:

inc_adrs = {ss_family = 0, __ss_align = 234832925920,
__ss_padding = "@\300\377\377\377\177\000\000G\004I\255\066\000\000\000X...

这个垃圾取决于编译器如何在堆栈上分配值以及以前的代码(包括 glibc)将对您的堆栈执行什么操作。

例如没有 if 的相同值:

1: inc_len = 54 <<--- this one is unitialized!!!!
2: inc_adrs = {ss_family = 49240, __ss_align = 4294967296,
__ss_padding = "\000\000\000\000\000\000\000\000\034\00

如您所见,inc_len 恰好是 54,这足以让 accept 保存 sockaddr_in,因此这种情况就好像一切正​​常一样。

ifnot-if 情况的区别:

-       leaq    -52(%rbp), %rdx
- leaq -208(%rbp), %rcx
+ leaq -180(%rbp), %rdx
+ leaq -176(%rbp), %rcx
movl -4(%rbp), %eax
movq %rcx, %rsi
movl %eax, %edi
call accept

所以它只能在偶然情况下正常工作。您可以使用 random 进行模拟:

#include <stdlib.h>

srand(time(NULL));
...
socklen_t inc_len = random() % (sizeof(struct sockaddr_in)*2)

这将填充 inc_adrs 50% 的时间,5% 的时间不碰它。

关于c++ - 来自服务器套接字的错误 IP 和端口,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32145927/

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