有个问题请教一下, 有台服务器有一张网卡, 网卡上有 3个公网IP, 我创建了一个udp socket,bind 0.0.0.0 的 7000端口, 用户1 来访问IP1 的7000端口, 服务程序会用默认的IP1 给用户1回复数据, 但是用户2来访问IP2的7000端口, 服务器仍然用 IP1来给用户2 回复数据, 有办法让服务器用IP2给用户2回复吗 ? 用iptables 命令可以解决吗? 我的意思是用户有很多个, 用户的IP也不确定, 用户会用随机的公网IP 来随机访问我服务器的iP1 Ip2 i-p3 I-P4 等等 , 我希望用户访问我的哪个I P, 我的程序就用哪个i p给用户回复数据
16条回答 默认 最新
- 杨同学* 2024-06-28 09:11关注
该回答结合ChatGPT4o及杨同学*共同作答, 如有帮助,还请采纳。
要解决这个问题,您可以使用较低级的套接字接口来获取接收到的数据的目的地址。通过这种方式,您可以获取用户访问的具体服务器IP地址,然后用相同的IP地址进行回复。具体地,可以使用recvmsg
和sendmsg
系列函数,它们提供了更加灵活的控制,包括访问到达数据包的目的地址。以下是一个示例代码,展示了如何实现这一功能:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <arpa/inet.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <netinet/ip.h> #include <net/if.h> #define PORT 7000 #define BUF_SIZE 1024 int main() { int sockfd; struct sockaddr_in server_addr, client_addr; char buffer[BUF_SIZE]; socklen_t addr_len = sizeof(client_addr); // 创建套接字 if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { perror("socket creation failed"); exit(EXIT_FAILURE); } // 绑定套接字到所有可用地址 memset(&server_addr, 0, sizeof(server_addr)); server_addr.sin_family = AF_INET; server_addr.sin_addr.s_addr = INADDR_ANY; server_addr.sin_port = htons(PORT); if (bind(sockfd, (const struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) { perror("bind failed"); close(sockfd); exit(EXIT_FAILURE); } while (1) { struct iovec iov[1]; struct msghdr msg; struct cmsghdr *cmsg; char cbuf[CMSG_SPACE(sizeof(struct in_pktinfo))]; struct in_pktinfo *pktinfo; memset(&msg, 0, sizeof(msg)); iov[0].iov_base = buffer; iov[0].iov_len = sizeof(buffer); msg.msg_name = &client_addr; msg.msg_namelen = sizeof(client_addr); msg.msg_iov = iov; msg.msg_iovlen = 1; msg.msg_control = cbuf; msg.msg_controllen = sizeof(cbuf); ssize_t len = recvmsg(sockfd, &msg, 0); if (len < 0) { perror("recvmsg failed"); continue; } buffer[len] = '\0'; printf("Received message: %s\n", buffer); for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; cmsg = CMSG_NXTHDR(&msg, cmsg)) { if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_PKTINFO) { pktinfo = (struct in_pktinfo *)CMSG_DATA(cmsg); char ip[INET_ADDRSTRLEN]; inet_ntop(AF_INET, &pktinfo->ipi_addr, ip, sizeof(ip)); printf("Message received on IP address: %s\n", ip); // 使用接收到的数据的目的地址作为源地址发送回复 struct sockaddr_in reply_addr; memset(&reply_addr, 0, sizeof(reply_addr)); reply_addr.sin_family = AF_INET; reply_addr.sin_addr = pktinfo->ipi_addr; reply_addr.sin_port = htons(0); // 让系统选择端口 int reply_sock = socket(AF_INET, SOCK_DGRAM, 0); if (reply_sock < 0) { perror("reply socket creation failed"); continue; } if (bind(reply_sock, (struct sockaddr *)&reply_addr, sizeof(reply_addr)) < 0) { perror("bind failed"); close(reply_sock); continue; } sendto(reply_sock, buffer, len, 0, (struct sockaddr *)&client_addr, addr_len); close(reply_sock); break; } } } close(sockfd); return 0; }
解释
- 创建和绑定套接字:创建UDP套接字并绑定到所有可用地址(0.0.0.0)。
- 接收数据:使用
recvmsg
接收数据包,msg
结构中设置控制消息缓冲区。 - 提取目的地址:从控制消息中提取目的地址(即,客户端访问的服务器IP)。
- 发送回复:创建新的套接字,绑定到提取的目的地址,使用
sendto
发送回复给客户端。
这样,服务器将根据客户端访问的具体IP地址来发送回复。
本回答被题主选为最佳回答 , 对您是否有帮助呢?解决 1无用
悬赏问题
- ¥15 35114 SVAC视频验签的问题
- ¥15 impedancepy
- ¥15 在虚拟机环境下完成以下,要求截图!
- ¥15 求往届大挑得奖作品(ppt…)
- ¥15 如何在vue.config.js中读取到public文件夹下window.APP_CONFIG.API_BASE_URL的值
- ¥50 浦育平台scratch图形化编程
- ¥20 求这个的原理图 只要原理图
- ¥15 vue2项目中,如何配置环境,可以在打完包之后修改请求的服务器地址
- ¥20 微信的店铺小程序如何修改背景图
- ¥15 UE5.1局部变量对蓝图不可见