在只有一个物理网卡的情况下,可以通过软件虚拟多个 IP地址 ,分时通讯。
协议栈: LwIP
主芯片:STM32F107VC
实现
首先移植 LwIP ,保证单个 IP地址 时可用。
然后添加虚拟网卡:
void LwIP_Init(void)
{
/* 添加网卡1 */
IP4_ADDR( ipaddr1, 192, 168, 0, 234);
IP4_ADDR( netmask1, 255, 255, 255, 0);
IP4_ADDR( gw1, 192, 168, 0, 1);
netif_add( netif1, ipaddr1, netmask1, gw1, NULL, ethernetif_init, ethernet_input);
netif_set_up( netif1);
netif_set_default( netif1);
/* 添加网卡2 */
IP4_ADDR( ipaddr2, 192, 168, 1, 234);
IP4_ADDR( netmask2, 255, 255, 255, 0);
IP4_ADDR( gw2, 192, 168, 1, 1);
netif_add( netif2, ipaddr2, netmask2, gw2, NULL, ethernetif_init, ethernet_input);
netif_set_up( netif2);
/* 新建UDP通信 */
struct udp_pcb *UdpPcb;
/* Create a new UDP control block */
UdpPcb = udp_new();
/* Bind the upcb to any IP address and the UDP_PORT port*/
udp_bind(UdpPcb, IP_ADDR_ANY, UDP_CLIENT_PORT);
/* Set a receive callback for the upcb */
udp_recv(UdpPcb, udp_client_callback, NULL);
}
这样处理之后,出现下面的问题:
有些数据包会在网卡中逗留,在不确定的时间后,发出去
数据包每次都发了两次
第一张网卡的 IP地址 收不到数据,甚至于使用以太网调试助手向该 IP 发送数据都抓不到数据包。
根据以太网通信协议,局域网内数据收发,需要使用 MAC 地址通讯,因此首先需要发送 ARP 数据包,需要向目的 IP地址 发送协议包,请求对方的 MAC地址 。通过抓包工具查看,果然是这样,电脑端发送的 ARP 数据包,设备没有回复。
因此修改 ARP层 。
/*
*********************************************************************************************************
* Function Name : GetActiveNetif
* Description : 获取当前活动的网卡
* Input : None
* Output : None
* Return : None
*********************************************************************************************************
*/
struct netif *GetActiveNetif(struct ip_addr *src_ip)
{
struct netif *curNetif = NULL;
if (ip_addr_cmp(src_ip, netif1.ip_addr)) {
curNetif = netif1;
} else if (ip_addr_cmp(src_ip, netif2.ip_addr)) {
curNetif = netif2;
}
return curNetif;
}
通过解析数据包中的 源IP 字段,和当前 2 张网卡中的 源IP 字段进行比较,从而找到数据包是发送给哪一张网卡的。
void
etharp_arp_input(struct netif *netif, struct eth_addr *ethaddr, struct pbuf *p)
{
/* this interface is not configured? */
if (netif->ip_addr.addr == 0) {
for_us = 0;
} else {
/* ARP packet directed to us? */
struct netif *GetActiveNetif(struct ip_addr *src_ip);
struct netif *activeNetif = GetActiveNetif( dipaddr);
if (activeNetif != NULL) {
for_us = 1;
netif = activeNetif;
}
}
/* ARP message directed to us? */
if (for_us) {
/* add IP address in ARP cache; assume requester wants to talk to us.
* can result in directly sending the queued packets for this host. */
update_arp_entry(netif, sipaddr, (hdr->shwaddr), ETHARP_TRY_HARD);
/* ARP message not directed to us? */
} else {
/* update the source IP address in the cache, if present */
update_arp_entry(netif, sipaddr, (hdr->shwaddr), 0);
}
}
通过上述修改,上位机的数据包就可以收到了。
/**
* In this function, the hardware should be initialized.
* Called from ethernetif_init().
*
* @param netif the already initialized lwip network interface structure
* for this ethernetif
*/
static void
low_level_init(struct netif *netif)
{
/* device capabilities */
/* don't set NETIF_FLAG_ETHARP if this device is not an ethernet one */
netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_LINK_UP;
}
根据上面提示,如果有多个网络,需要去掉 NETIF_FLAG_ETHARP 字段。
OK ,经过上述修改,两个 IP地址 都可以收到数据包。
总结
IP地址 需要配置为不同网段
参考 IP 路由规则:
/**
* Finds the appropriate network interface for a given IP address. It
* searches the list of network interfaces linearly. A match is found
* if the masked IP address of the network interface equals the masked
* IP address given to the function.
*
* @param dest the destination IP address for which to find the route
* @return the netif on which to send to reach dest
*/
struct netif *
ip_route(struct ip_addr *dest)
{
struct netif *netif;
/* iterate through netifs */
for(netif = netif_list; netif != NULL; netif = netif->next) {
/* network mask matches? */
if (netif_is_up(netif)) {
if (ip_addr_netcmp(dest, (netif->ip_addr), (netif->netmask))) {
/* return netif on which to forward IP packet */
return netif;
}
}
}
if ((netif_default == NULL) || (!netif_is_up(netif_default))) {
LWIP_DEBUGF(IP_DEBUG | 2, ("ip_route: No route to 0x%"X32_F"n", dest->addr));
IP_STATS_INC(ip.rterr);
snmp_inc_ipoutnoroutes();
return NULL;
}
/* no matching netif found, use default netif */
return netif_default;
}
如果两张网卡的 IP地址 在同一个网段,那么在遍历网卡时,会优先找到最后添加的网卡,也就是说,不管你往哪个网卡发送数据包,在设备回复数据时,都会从第二张网卡回复数据。
比如说:向 IP (192, 168, 0, 234) 发送数据包,收到数据回复时,源 IP地址 会变成 IP(192, 168, 1, 234) 。
如果想要两张网卡独立工作,都可以正常收发数据,需要将两张网卡的 IP地址 设置为不同的网段,同时电脑端需要和设备端设置在同一个网段!
比如:
主机1:
IP: 192.168.0.88
MASK: 255.255.255.0
GATEWAY:192.168.0.1
设备1:
IP: 192.168.0.249
MASK: 255.255.255.0
GATEWAY:192.168.0.1
这样,主机1 和 设备1 可以正常通讯。
主机2:
IP: 192.168.1.88
MASK: 255.255.255.0
GATEWAY:192.168.1.1
设备2:
IP: 192.168.1.249
MASK: 255.255.255.0
GATEWAY:192.168.1.1
这样,主机2 和 设备2 可以正常通讯。
如果交叉会怎么样呢?你会发现抓包工具会显示目标不可达,因为他们不再同一个子网内!
如果设备1和设备2在同一个子网内会怎么样呢?
主机:
IP: 192.168.0.88
MASK: 255.255.255.0
GATEWAY:192.168.0.1
设备1:
IP: 192.168.0.249
MASK: 255.255.255.0
GATEWAY:192.168.0.1
设备2:
IP: 192.168.0.248
MASK: 255.255.255.0
GATEWAY:192.168.0.1
现象:
主机 –> 设备1:设备2 –> 主机
主机 –> 设备2:设备2 –>主机
因此,我们得出结论:
只有在同一个子网内的主机和设备才可以正常收发数据
如果两台设备在同一个子网内,主机只能和最后添加的网卡绑定的 IP地址 正常通讯。和最开始添加的网卡通讯时,由于 ip_rout 的关系,将使用最后绑定网卡的 IP地址 回复!
在只有一个物理网卡的情况下,可以通过软件虚拟多个 IP地址 ,分时通讯。
协议栈: LwIP
主芯片:STM32F107VC
实现
首先移植 LwIP ,保证单个 IP地址 时可用。
然后添加虚拟网卡:
void LwIP_Init(void)
{
/* 添加网卡1 */
IP4_ADDR( ipaddr1, 192, 168, 0, 234);
IP4_ADDR( netmask1, 255, 255, 255, 0);
IP4_ADDR( gw1, 192, 168, 0, 1);
netif_add( netif1, ipaddr1, netmask1, gw1, NULL, ethernetif_init, ethernet_input);
netif_set_up( netif1);
netif_set_default( netif1);
/* 添加网卡2 */
IP4_ADDR( ipaddr2, 192, 168, 1, 234);
IP4_ADDR( netmask2, 255, 255, 255, 0);
IP4_ADDR( gw2, 192, 168, 1, 1);
netif_add( netif2, ipaddr2, netmask2, gw2, NULL, ethernetif_init, ethernet_input);
netif_set_up( netif2);
/* 新建UDP通信 */
struct udp_pcb *UdpPcb;
/* Create a new UDP control block */
UdpPcb = udp_new();
/* Bind the upcb to any IP address and the UDP_PORT port*/
udp_bind(UdpPcb, IP_ADDR_ANY, UDP_CLIENT_PORT);
/* Set a receive callback for the upcb */
udp_recv(UdpPcb, udp_client_callback, NULL);
}
这样处理之后,出现下面的问题:
有些数据包会在网卡中逗留,在不确定的时间后,发出去
数据包每次都发了两次
第一张网卡的 IP地址 收不到数据,甚至于使用以太网调试助手向该 IP 发送数据都抓不到数据包。
根据以太网通信协议,局域网内数据收发,需要使用 MAC 地址通讯,因此首先需要发送 ARP 数据包,需要向目的 IP地址 发送协议包,请求对方的 MAC地址 。通过抓包工具查看,果然是这样,电脑端发送的 ARP 数据包,设备没有回复。
因此修改 ARP层 。
/*
*********************************************************************************************************
* Function Name : GetActiveNetif
* Description : 获取当前活动的网卡
* Input : None
* Output : None
* Return : None
*********************************************************************************************************
*/
struct netif *GetActiveNetif(struct ip_addr *src_ip)
{
struct netif *curNetif = NULL;
if (ip_addr_cmp(src_ip, netif1.ip_addr)) {
curNetif = netif1;
} else if (ip_addr_cmp(src_ip, netif2.ip_addr)) {
curNetif = netif2;
}
return curNetif;
}
通过解析数据包中的 源IP 字段,和当前 2 张网卡中的 源IP 字段进行比较,从而找到数据包是发送给哪一张网卡的。
void
etharp_arp_input(struct netif *netif, struct eth_addr *ethaddr, struct pbuf *p)
{
/* this interface is not configured? */
if (netif->ip_addr.addr == 0) {
for_us = 0;
} else {
/* ARP packet directed to us? */
struct netif *GetActiveNetif(struct ip_addr *src_ip);
struct netif *activeNetif = GetActiveNetif( dipaddr);
if (activeNetif != NULL) {
for_us = 1;
netif = activeNetif;
}
}
/* ARP message directed to us? */
if (for_us) {
/* add IP address in ARP cache; assume requester wants to talk to us.
* can result in directly sending the queued packets for this host. */
update_arp_entry(netif, sipaddr, (hdr->shwaddr), ETHARP_TRY_HARD);
/* ARP message not directed to us? */
} else {
/* update the source IP address in the cache, if present */
update_arp_entry(netif, sipaddr, (hdr->shwaddr), 0);
}
}
通过上述修改,上位机的数据包就可以收到了。
/**
* In this function, the hardware should be initialized.
* Called from ethernetif_init().
*
* @param netif the already initialized lwip network interface structure
* for this ethernetif
*/
static void
low_level_init(struct netif *netif)
{
/* device capabilities */
/* don't set NETIF_FLAG_ETHARP if this device is not an ethernet one */
netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_LINK_UP;
}
根据上面提示,如果有多个网络,需要去掉 NETIF_FLAG_ETHARP 字段。
OK ,经过上述修改,两个 IP地址 都可以收到数据包。
总结
IP地址 需要配置为不同网段
参考 IP 路由规则:
/**
* Finds the appropriate network interface for a given IP address. It
* searches the list of network interfaces linearly. A match is found
* if the masked IP address of the network interface equals the masked
* IP address given to the function.
*
* @param dest the destination IP address for which to find the route
* @return the netif on which to send to reach dest
*/
struct netif *
ip_route(struct ip_addr *dest)
{
struct netif *netif;
/* iterate through netifs */
for(netif = netif_list; netif != NULL; netif = netif->next) {
/* network mask matches? */
if (netif_is_up(netif)) {
if (ip_addr_netcmp(dest, (netif->ip_addr), (netif->netmask))) {
/* return netif on which to forward IP packet */
return netif;
}
}
}
if ((netif_default == NULL) || (!netif_is_up(netif_default))) {
LWIP_DEBUGF(IP_DEBUG | 2, ("ip_route: No route to 0x%"X32_F"n", dest->addr));
IP_STATS_INC(ip.rterr);
snmp_inc_ipoutnoroutes();
return NULL;
}
/* no matching netif found, use default netif */
return netif_default;
}
如果两张网卡的 IP地址 在同一个网段,那么在遍历网卡时,会优先找到最后添加的网卡,也就是说,不管你往哪个网卡发送数据包,在设备回复数据时,都会从第二张网卡回复数据。
比如说:向 IP (192, 168, 0, 234) 发送数据包,收到数据回复时,源 IP地址 会变成 IP(192, 168, 1, 234) 。
如果想要两张网卡独立工作,都可以正常收发数据,需要将两张网卡的 IP地址 设置为不同的网段,同时电脑端需要和设备端设置在同一个网段!
比如:
主机1:
IP: 192.168.0.88
MASK: 255.255.255.0
GATEWAY:192.168.0.1
设备1:
IP: 192.168.0.249
MASK: 255.255.255.0
GATEWAY:192.168.0.1
这样,主机1 和 设备1 可以正常通讯。
主机2:
IP: 192.168.1.88
MASK: 255.255.255.0
GATEWAY:192.168.1.1
设备2:
IP: 192.168.1.249
MASK: 255.255.255.0
GATEWAY:192.168.1.1
这样,主机2 和 设备2 可以正常通讯。
如果交叉会怎么样呢?你会发现抓包工具会显示目标不可达,因为他们不再同一个子网内!
如果设备1和设备2在同一个子网内会怎么样呢?
主机:
IP: 192.168.0.88
MASK: 255.255.255.0
GATEWAY:192.168.0.1
设备1:
IP: 192.168.0.249
MASK: 255.255.255.0
GATEWAY:192.168.0.1
设备2:
IP: 192.168.0.248
MASK: 255.255.255.0
GATEWAY:192.168.0.1
现象:
主机 –> 设备1:设备2 –> 主机
主机 –> 设备2:设备2 –>主机
因此,我们得出结论:
只有在同一个子网内的主机和设备才可以正常收发数据
如果两台设备在同一个子网内,主机只能和最后添加的网卡绑定的 IP地址 正常通讯。和最开始添加的网卡通讯时,由于 ip_rout 的关系,将使用最后绑定网卡的 IP地址 回复!
举报