嵌入式技术论坛
直播中

杨平

7年用户 1675经验值
私信 关注
[问答]

多网卡情况下如何判断是哪个网卡接收到的数据包呢?

在多网卡情况下,不同网卡有不同的地址。
在socket中使用udp协议监听了一个端口,监听的地址为0.0.0.0表示任意网卡都可以接收到数据。现在的问题是,接收数据包我可以用(recvfrom)获取到发送方的ip地址和端口。但是我不知道是从哪个网卡接收到的。
查询了linux头文件

#include <sys/socket.h>
ssize_t recvmsg(int socket, struct msghdr *message, int flags);
可以拿到本地接收端地址,但是这个函数在rtt中好像没有实现

连lwip中也只有

int lwip_sendmsg(int s, const struct msghdr *message, int flags);
没有找到recvmsg函数

代码如下

void task_udp(void p)
{
int err = 0;
int sockfd = 0;
struct sockaddr_in bindAddr = {0};
struct sockaddr_in destAddr = {0};
struct sockaddr_in sourceAddr = {0};
int udp_tick = 0;
int len = 0;
char addr_str[128];
struct timeval tv;
char * rx_buffer = malloc(UDP_BUF_SIZE);
char * tx_buffer = malloc(UDP_BUF_SIZE);
while(1)
{
sockfd = socket(AF_INET,SOCK_DGRAM,IPPROTO_IP);
LOG_D("socket created :%d",sockfd);
bindAddr.sin_family = AF_INET;
bindAddr.sin_port = htons(UDP_BIND_PORT);
bindAddr.sin_addr.s_addr = htonl(IPADDR_ANY);
err = bind(sockfd, (struct sockaddr )&bindAddr, sizeof(bindAddr));
if (err < 0)
{
LOG_D( "Failed to bind socket. Error %d", errno);
}
LOG_D( "socket bind :%d",ntohs(bindAddr.sin_port));
destAddr.sin_family = AF_INET;
destAddr.sin_port = htons(UDP_SEND_PORT);
// destAddr.sin_addr.s_addr = inet_addr(MULTICAST_IPV4_ADDR);
destAddr.sin_addr.s_addr = inet_addr("255.255.255.255"); //htonl(IPADDR_BROADCAST);
int mode = 0;
ioctlsocket(sockfd, FIONBIO, &mode);
/
Set recv timeout of this fd as per config /
tv.tv_sec = 10;
tv.tv_usec = 0;
setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (const char
)&tv, sizeof(tv));
/
Set send timeout of this fd as per config /
tv.tv_sec = 3;
tv.tv_usec = 0;
setsockopt(sockfd, SOL_SOCKET, SO_SNDTIMEO, (const char
)&tv, sizeof(tv));
const int opt = 1;
setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, (char *)&opt, sizeof(opt));
// this is also a listening socket, so add it to the multicast
// group for listening...
// socket_add_ipv4_multicast_group(sockfd, true);
socklen_t socklen = sizeof(sourceAddr);
while(1)
{
//len = recv(sockfd, rx_buffer, 1024-1, 0);
len = recvfrom(sockfd, rx_buffer, UDP_BUF_SIZE-1, 0,(struct sockaddr *)&sourceAddr,&socklen);
// Error occured during receiving
if (len > 0)
{
inet_ntoa_r(((struct sockaddr_in *)&sourceAddr)->sin_addr.s_addr, addr_str, sizeof(addr_str) - 1);
rx_buffer[len] = 0;
LOG_D( "recvfrom from %s : %d , %d bytes", addr_str,ntohs(sourceAddr.sin_port) , len);
LOG_D( "%s", rx_buffer);
len = udpfind_json_process(rx_buffer,UDP_BUF_SIZE,board_ip_str_get(),board_mac_str_get() , board_unique_id_str() );
LOG_D( "send %d bytes", len);
int err = sendto(sockfd,rx_buffer, len, 0,(struct sockaddr *)&destAddr,sizeof(destAddr));
if (err < 0)
{
LOG_D( "Error occured during sending: errno %d", errno);
break;
}
}else
{
if(!(errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN))
{
// LOG_E("net recv err :%d",rc);
LOG_D( "recvfrom failed: errno %d", errno);
break;
}
}
//vTaskDelay(100 / portTICK_RATE_MS);
}
if (sockfd != -1) {
LOG_D( "Shutting down socket and restarting...");
shutdown(sockfd, 0);
closesocket(sockfd);
}
}
free(rx_buffer);
free(tx_buffer);
}

回帖(3)

杨海清

2023-2-8 11:11:13
2.jpg
举报

杨平

2023-2-8 11:11:20
那这样就得每次网卡地址变化就得重新创建socket
举报

杨平

2023-2-8 11:11:32
在LWIP 2.1.2版本的源码下
rt-thread/components/net/lwip-2.1.2/src/api/sockets.c
找到了函数
ssize_t
lwip_recvmsg(int s, struct msghdr *message, int flags)
不知道是否可以直接跳过SAL调用这个函数
举报

更多回帖

发帖
×
20
完善资料,
赚取积分