在多网卡环境中,udp ipv6 socket 通过设置套接字选项IPV6_PKTINFO,然后在发送数据的时候携带辅助数据指定出口网卡ip发送.c代码实现:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <linux/ipv6.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/udp.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <fcntl.h>
#define SOURCE_IP "2001:db8::2" // Replace with your source IPv6 address
#define DESTINATION_IP "2001:db8::1"
#define UDP_PORT 12345
int sockfd;
int sock_init()
{
int val = 1;
struct sockaddr_in6 addr;
addr.sin6_family = AF_INET6;
addr.sin6_port = htons(12345);
addr.sin6_addr = in6addr_any;
struct in6_pktinfo info;
memset(&info, 0, sizeof(info));
info.ipi6_addr = in6addr_any;
sockfd = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
if (sockfd == -1) {
perror("socket");
exit(EXIT_FAILURE);
}
if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_PKTINFO, &info, sizeof(info)) != 0)
{
perror("set IPPROTO_IPV6 IPV6_PKTINFO");
goto quit;
}
if (bind(sockfd, (struct sockaddr *)&addr, sizeof(struct sockaddr_in6)) != 0)
{
perror("bind");
}
return 0;
quit:
close(sockfd);
return -1;
}
int main() {
struct sockaddr_in6 dest_addr;
struct msghdr msg;
struct iovec iov;
struct cmsghdr *cmsg;
char control_buf[CMSG_SPACE(sizeof(struct in6_pktinfo))];
char data[] = "Hello, UDP!";
// Create UDP socket
if (sock_init() != 0)
{
printf("socket init error\n");
return -1;
}
// Set destination address
memset(&dest_addr, 0, sizeof(dest_addr));
dest_addr.sin6_family = AF_INET6;
inet_pton(AF_INET6, DESTINATION_IP, &dest_addr.sin6_addr);
dest_addr.sin6_port = htons(UDP_PORT);
// Prepare message
memset(&msg, 0, sizeof(msg));
msg.msg_name = &dest_addr;
msg.msg_namelen = sizeof(dest_addr);
// Prepare data to send
iov.iov_base = data;
iov.iov_len = sizeof(data);
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
// Prepare control message with source IP information
memset(control_buf, 0, sizeof(control_buf));
msg.msg_control = control_buf;
msg.msg_controllen = sizeof(control_buf);
cmsg = CMSG_FIRSTHDR(&msg);
cmsg->cmsg_level = IPPROTO_IPV6;
cmsg->cmsg_type = IPV6_PKTINFO;
cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
struct in6_pktinfo *pktinfo = (struct in6_pktinfo *)CMSG_DATA(cmsg);
inet_pton(AF_INET6, SOURCE_IP, &pktinfo->ipi6_addr);
// Send the message
if (sendmsg(sockfd, &msg, 0) == -1) {
perror("sendmsg");
close(sockfd);
exit(EXIT_FAILURE);
}
printf("Data sent successfully.\n");
close(sockfd);
return 0;
}
others:
如果是ipv4, 在套接字设置时应该为:
int on = 1;
setsockopt(sockfd, IPPROTO_IP, IP_PKTINFO, &on, sizeof(on));
在发送udp报文的时候辅助数据结构体采用struct in_pktinfo