原因
下面流程导致创建多网卡 socket 无法指定网卡
在 sal_socket 时,在 socket_init 中绑定了网卡为 default,然后通过 网卡下面的 protocol family socket 创建网卡 pf->skt_ops->socket(domain, type, protocol)
int sal_socket(int domain, int type, int protocol)
{
int retval;
int socket, proto_socket;
struct sal_socket *sock;
struct sal_proto_family *pf;
/* allocate a new socket and registered socket options */
socket = socket_new();
if (socket < 0)
{
return -1;
}
/* get sal socket object by socket descriptor */
sock = sal_get_socket(socket);
if (sock == RT_NULL)
{
socket_delete(socket);
return -1;
}
/* Initialize sal socket object */
retval = socket_init(domain, type, protocol, &sock);
if (retval < 0)
{
LOG_E("SAL socket protocol family input failed, return error %d.", retval);
socket_delete(socket);
return -1;
}
/* valid the network interface socket opreation */
SAL_NETDEV_SOCKETOPS_VALID(sock->netdev, pf, socket);
proto_socket = pf->skt_ops->socket(domain, type, protocol);
if (proto_socket >= 0)
{
#ifdef SAL_USING_TLS
if (SAL_SOCKOPS_PROTO_TLS_VALID(sock, socket))
{
sock->user_data_tls = proto_tls->ops->socket(socket);
if (sock->user_data_tls == RT_NULL)
{
socket_delete(socket);
return -1;
}
}
#endif
sock->user_data = (void *) proto_socket;
return sock->socket;
}
socket_delete(socket);
return -1;
}
创建不同协议类型的socket引用关系

解决办法
解决方案要基于前篇文章2021/07/14 LwIP 2.0.2 多网卡 ping;LwIP 指定网卡ping
在创建 socket 的过程中,通过 sin_family 指定使用 AF_WIZ, AF_AT, AF_INET(lwip), 然后通过 bind 函数,二次选择网卡;
socket(AF_INET, SOCK_STREAM, 0)
wiznet
family = AF_WIZ
sec_family = AF_INET
lwip
family=AF_INET
sec_family = AF_UNSPEC
at device
family=AF_AT
sec_family = AF_INET
修改过程
修改函数 socket_init
rt-threadcomponents
etsal_socketsrcsal_socket.c
修改函数,通过 sin_family 指定使用 AF_WIZ, AF_AT, AF_INET(lwip);
static int socket_init(int family, int type, int protocol, struct sal_socket **res) // 420 行
/**
* This function will initialize sal socket object and set socket options
*
* @param family protocol family * @param type socket type
* @param protocol transfer Protocol
* @param res sal socket object address
*
* @Return 0 : socket initialize success * -1 : input the wrong family
* -2 : input the wrong socket type
* -3 : get network interface failed
*/
static int socket_init(int family, int type, int protocol, struct sal_socket **res)
{
struct sal_socket *sock;
struct sal_proto_family *pf;
struct netdev *netdv_def = netdev_default;
struct netdev *netdev = RT_NULL;
rt_bool_t flag = RT_FALSE;
if (family < 0 || family > AF_MAX)
{
return -1;
}
if (type < 0 || type > SOCK_MAX)
{
return -2;
}
sock = *res;
sock->domain = family;
sock->type = type;
sock->protocol = protocol;
netdv_def = netdev_get_by_family(family);
if (netdv_def == RT_NULL)
{
netdv_def = netdev_default;
}
if (netdv_def && netdev_is_up(netdv_def))
{
/* check default network interface device protocol family */
pf = (struct sal_proto_family *) netdv_def->sal_user_data;
if (pf != RT_NULL && pf->skt_ops && (pf->family == family || pf->sec_family == family))
{
sock->netdev = netdv_def;
flag = RT_TRUE;
}
}
if (flag == RT_FALSE)
{
/* get network interface device by protocol family */
netdev = netdev_get_by_family(family);
if (netdev == RT_NULL)
{
LOG_E("not find network interface device by protocol family(%d).", family);
return -3;
}
sock->netdev = netdev;
}
LOG_I("use network interface: %s", sock->netdev->name);
return 0;
}
测试多网卡功能
#include
#include /* 使用BSD socket,需要包含socket.h头文件 */
#include
#include
#include
#include
#define LOG_TAG "test_multi_netif"
#define LOG_LVL LOG_LVL_DBG
#define BUFSZ 256
#define SEND_DATASZ 256
#define SAY_BUFSZ 240
#define THREAD_PRIORITY 20
#define THREAD_STACK_SIZE 2048
#define THREAD_TIMESLICE 5
#define EVENT_CLOSE_SOCK 0x01
#define SERVER_E0 "139.155.51.105"
#define SERVER_W0 "172.18.44.66"
static int close_socket(int *sock);
static char send_data[80] = {0}; /* 发送用到的数据 */
typedef struct TEST_MULTI_NETIF
{
char netdev_name[8];
int sock;
int netdev_type;
rt_event_t event;
}TCP_CLIENT;
TCP_CLIENT tcp_e0;
TCP_CLIENT tcp_w0;
static int socket_connect(const char *dest, struct netdev *dev)
{
struct hostent *host;
struct sockaddr_in server_addr;
int sock = -1;
int port = 9008;
struct sockaddr_in local;
/* 通过函数入口参数url获得host地址(如果是域名,会做域名解析) */
host = gethostbyname(dest);
/* 创建一个socket,类型是SOCKET_STREAM,TCP类型 */
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
/* 创建socket失败 */
log_e("create socket error");
/* 释放接收缓冲 */
/* rt_free(recv_data); */
return -1;
}
log_i("create success");
/* 初始化预连接的服务端地址 */
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(port);
server_addr.sin_addr = *((struct in_addr *)host->h_addr);
rt_memset(&(server_addr.sin_zero), 0, sizeof(server_addr.sin_zero));
local.sin_len = sizeof(local);
local.sin_family = AF_INET;
local.sin_port = 0;
local.sin_addr.s_addr = dev->ip_addr.addr;
if (dev->ip_addr.addr != 0)
{
bind(sock, (struct sockaddr *)&local, sizeof(struct sockaddr_in));
}
log_i("bind %x success", local.sin_addr.s_addr);
/* 连接到服务端 */
if (connect(sock, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) != RT_EOK)
{
/* 连接失败 */
log_e("Connect server [%s] failed!
", dest);
closesocket(sock);
return -1;
}
log_i("connect server success");
return sock;
}
static int close_socket(int *sock)
{
if (*sock > 0)
{
log_d("disconnect server!
");
closesocket(*sock);
*sock = -1;
}
}
/* create receive thread */
static void thread_rece_entry(void* parameter)
{
char *recv_data;
int bytes_received;
TCP_CLIENT *client = (TCP_CLIENT *)parameter;
/* int no = (int) parameter; #<{(| 获得线程的入口参数 |)}># */
/* 分配用于存放接收数据的缓冲 */
recv_data = rt_malloc(BUFSZ);
if (recv_data == RT_NULL)
{
rt_kprintf("No memory
");
}
while(1)
{
/* 从sock连接中接收最大BUFSZ - 1字节数据 */
bytes_received = recv(client->sock, recv_data, BUFSZ - 1, 0);
if (bytes_received < 0)
{
/* 接收失败,关闭这个连接 */
log_d("received less than zero, close the socket.");
rt_free(recv_data);
rt_event_send(client->event, EVENT_CLOSE_SOCK);
return;
}
else if (bytes_received == 0)
{
/* 默认 recv 为阻塞模式,此时收到0认为连接出错,关闭这个连接 */
log_d("received equal zero, close the socket.");
rt_free(recv_data);
rt_event_send(client->event, EVENT_CLOSE_SOCK);
return;
}
recv_data[bytes_received] = '