Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
LWIP
双网口_多网口_多IP
netdev
RT-Thread 按指定网卡创建socket
发布于 2021-07-16 16:32:36 浏览:2296
订阅该版
[tocm] # socket 无法指定多网卡原因 ## 原因 下面流程导致创建多网卡 socket 无法指定网卡 在 sal_socket 时,在 socket_init 中绑定了网卡为 default,然后通过 网卡下面的 protocol family socket 创建网卡 **pf->skt_ops->socket(domain, type, protocol)** ```c 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引用关系 ![df796d02cba442799a85d97acc40546d.png](https://oss-club.rt-thread.org/uploads/20210716/c8f23aa2571875bd62bf482bde121475.png.webp) ![5cc036d1856c4da39fab8993c649543f.png](https://oss-club.rt-thread.org/uploads/20210716/d7d977c6be4656cd60954f44476c6536.png.webp) ![5d3cbe16021b4829b3edd7e596ce3ac3.png](https://oss-club.rt-thread.org/uploads/20210716/6691930c0b0fab53ecd4f61a2e11ef53.png.webp) ![158444d745a943a8b38c984bc8f590da.png](https://oss-club.rt-thread.org/uploads/20210716/97fe133b3717407e990c66ffb20ebb29.png.webp) ## 解决办法 解决方案要基于前篇文章[2021/07/14 LwIP 2.0.2 多网卡 ping](:/dded4acd2f3b453f850678a024a9dbf9);[LwIP 指定网卡ping](https://club.rt-thread.org/ask/article/2883.html) 在创建 socket 的过程中,通过 sin_family 指定使用 AF_WIZ, AF_AT, AF_INET(lwip), 然后通过 bind 函数,二次选择网卡; ```c 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-thread\components\net\sal_socket\src\sal_socket.c ` 修改函数,通过 sin_family 指定使用 AF_WIZ, AF_AT, AF_INET(lwip); ```c static int socket_init(int family, int type, int protocol, struct sal_socket **res) // 420 行 ``` ```c /** * 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; } ``` ## 测试多网卡功能 ```c #include
#include
/* 使用BSD socket,需要包含socket.h头文件 */ #include
#include
#include
#include
#include
#define LOG_TAG "test_multi_netif" #define LOG_LVL LOG_LVL_DBG #include
#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!\n", 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!\n"); 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\n"); } 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] = '\0'; /* 在控制终端显示收到的数据 */ log_i("recv:%s", recv_data); } } // static void send_chat_data(char *p_send, int len) static void thread_send_entry(void* parameter) { int ret; char *send_str = rt_calloc(20, 1); rt_thread_t tid; TCP_CLIENT *client = (TCP_CLIENT *)parameter; rt_uint32_t e; char *thread_name = rt_calloc(8, 1); sprintf(send_str, "I am netif %s", client->netdev_name); if (client->sock >= 0) { #if 1 sprintf(thread_name, "Recv_%s", client->netdev_name); tid = rt_thread_create(thread_name, thread_rece_entry, (void*)parameter, /* 线程入口是thread_entry, 入口参数是1 */ THREAD_STACK_SIZE, THREAD_PRIORITY, THREAD_TIMESLICE); if (tid != RT_NULL) { log_d("Create receive thread %s receive.\n", client->netdev_name); rt_thread_startup(tid); } else { if (thread_name != RT_NULL) { rt_free(thread_name); } if (send_str != RT_NULL) { rt_free(send_str); } return; } #endif } if (thread_name != RT_NULL) { rt_free(thread_name); } log_i("socket %s id: %d", client->netdev_name, client->sock); while(1) { #if 1 if (rt_event_recv(client->event, EVENT_CLOSE_SOCK, RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR, RT_WAITING_NO, &e) == RT_EOK) { if (EVENT_CLOSE_SOCK == (e & EVENT_CLOSE_SOCK)) { close_socket(&client->sock); if (send_str != RT_NULL) { rt_free(send_str); } return; } } #endif if (client->sock >= 0) { ret = send(client->sock, send_str, strlen(send_str), 0); if (ret < 0) { log_e("send error,close the socket."); } else if (ret == 0) { log_e("Send warning,send function return 0."); } } rt_thread_mdelay(1000); } } static int net_start(int argc, char *argv[]) { rt_thread_t tid1; TCP_CLIENT *client = RT_NULL; char *server = RT_NULL; int index = 0; char *str = rt_calloc(10, 1); /* 是否创建Socket */ if (argc == 1) { memcpy(tcp_e0.netdev_name, "e0", 2); client = &tcp_e0; server = SERVER_E0; index = 0; } else { memcpy(tcp_w0.netdev_name, "w0", 2); client = &tcp_w0; server = SERVER_W0; index = 1; } if (client->sock >= 0) { log_i("socket already exist"); } if ((client->sock = socket_connect(server, netdev_get_by_name(client->netdev_name))) < 0) { log_e("create and connect server error."); return -1; } sprintf(str, "e_%s", client->netdev_name); client->event = rt_event_create(str, RT_IPC_FLAG_FIFO); rt_memset(str, 0, 10); sprintf(str, "send_%s", client->netdev_name); tid1 = rt_thread_create(str, thread_send_entry, (void*)(client), /* 线程入口是thread_entry, 入口参数是1 */ THREAD_STACK_SIZE, THREAD_PRIORITY + index, THREAD_TIMESLICE); if (tid1 != RT_NULL) { log_d("Create receive thread for chat receive.\n"); rt_thread_startup(tid1); } else { return -1; } if (str != RT_NULL) { rt_free(str); } return 0; } #ifdef FINSH_USING_MSH #include
MSH_CMD_EXPORT(net_start, a tcp client test); #endif ``` # 结果 ## 腾讯云服务器: ```c nc -l 9008 > test.log ``` ![7315451e825c4caf8e1f677e721578d1.png](https://oss-club.rt-thread.org/uploads/20210716/dce52ef324363b90a69f2b98c58cdbe3.png) ## 本地服务器 ![c7dbe5b892a04096a4d31f6bb653430d.png](https://oss-club.rt-thread.org/uploads/20210716/2f58c6e18c08b15a9cfc0ffffd842e9c.png.webp) ## MSH ![7638581fa2e54278bb271cb56fd595cb.png](https://oss-club.rt-thread.org/uploads/20210716/8bc09d40276503ac8e149a63a813af36.png) ![21148993e5fe4525ae14734fb420ae90.png](https://oss-club.rt-thread.org/uploads/20210716/6a818a9176f0676ab4d176091e9aa98c.png)
8
条评论
默认排序
按发布时间排序
登录
注册新账号
关于作者
yukelab
这家伙很懒,什么也没写!
文章
4
回答
47
被采纳
1
关注TA
发私信
相关文章
1
netdev.h头文件不能被其他c文件包含,否则报错
2
mqtt pipe 里面使用到了dfs, socket 是怎么关联起来dfs的?
3
netdev中link_down和internet_down怎么解决?
4
ETHIF_LINK_PHYUP和ETHIF_LINK_AUTOUP有什么用
5
netdev 网卡 挂载W5500
6
netdev网卡回调函数在internetup时不会触发
7
多网卡情况下如果做到哪个网卡优先通信
8
ifconfig ,netdev等 功能bug,死机
9
netdev设备状态标志位异常,无法上线?
10
HC32F460 AT设备 发送数据就崩溃
推荐文章
1
RT-Thread应用项目汇总
2
玩转RT-Thread系列教程
3
国产MCU移植系列教程汇总,欢迎查看!
4
机器人操作系统 (ROS2) 和 RT-Thread 通信
5
五分钟玩转RT-Thread新社区
6
【技术三千问】之《玩转ART-Pi》,看这篇就够了!干货汇总
7
关于STM32H7开发板上使用SDIO接口驱动SD卡挂载文件系统的问题总结
8
STM32的“GPU”——DMA2D实例详解
9
RT-Thread隐藏的宝藏之completion
10
【ART-PI】RT-Thread 开启RTC 与 Alarm组件
热门标签
RT-Thread Studio
串口
Env
LWIP
SPI
AT
Bootloader
Hardfault
CAN总线
FinSH
ART-Pi
USB
DMA
文件系统
RT-Thread
SCons
RT-Thread Nano
线程
MQTT
STM32
RTC
FAL
rt-smart
ESP8266
I2C_IIC
UART
WIZnet_W5500
ota在线升级
freemodbus
PWM
flash
cubemx
packages_软件包
BSP
潘多拉开发板_Pandora
定时器
ADC
flashDB
GD32
socket
中断
编译报错
Debug
SFUD
rt_mq_消息队列_msg_queue
msh
keil_MDK
ulog
C++_cpp
MicroPython
本月问答贡献
a1012112796
10
个答案
1
次被采纳
踩姑娘的小蘑菇
4
个答案
1
次被采纳
红枫
4
个答案
1
次被采纳
张世争
4
个答案
1
次被采纳
Ryan_CW
4
个答案
1
次被采纳
本月文章贡献
catcatbing
3
篇文章
5
次点赞
YZRD
2
篇文章
5
次点赞
qq1078249029
2
篇文章
2
次点赞
xnosky
2
篇文章
1
次点赞
Woshizhapuren
1
篇文章
5
次点赞
回到
顶部
发布
问题
投诉
建议
回到
底部