嵌入式Linux下双网口Socket编程 硬件连接: 首先这里有两个网卡,一个是有线网卡eth0,另外一个是无线网卡ra0,然后确保有线和无线都已经连接到两个路由器上 [root@YuGe-AM1808/test/rt5370]#ifconfig eth0 Link encap:Ethernet HWaddr 00:18:31:E6:3C:15 inet addr:192.168.2.57 Bcast:192.168.2.255 Mask:255.255.255.0 UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:0 errors:0 dropped:0overruns:0 frame:0 TX packets:0 errors:0 dropped:0overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:0 (0.0 B) TX bytes:0 (0.0 B) Interrupt:40 ra0 Link encap:Ethernet HWaddr 00:0C:43:53:70:00 inet addr:192.168.1.57 Bcast:192.168.1.255 Mask:255.255.255.0 UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:0 errors:0 dropped:0overruns:0 frame:0 TX packets:0 errors:0 dropped:0 overruns:0carrier:0 collisions:0 txqueuelen:1000 RX bytes:139191 (135.9 KiB) TX bytes:2038 (1.9 KiB) 并且配置成各自网段的IP地址 从上面可以看出来双网卡的配置: 开发板eth0连接到路由器A(网段是192.168.2.xxx),自身IP为192.168.2.57 开发板ra0连接到路由器B(网段是192.168.1.xxx),自身IP为192.168.1.57 然后需要2台PC: PC-A连接到路由器A(网段是192.168.2.xxx),自身IP为192.168.2.140 PC-B连接到路由器B(网段是192.168.1.xxx),自身IP为192.168.1.140 此时确保各个系统之间网络是连通的: 路由器和PC之间能够通过ping命令测试能够连通 路由器和开发板能够通过ping -I eth0 192.168.2.1或者ping -I ra0192.168.1.1 连通 具体网络拓扑图如下: Socket编程 默认的Socket是不指定网卡发送接收数据的,因此如果系统中存在双网卡的时候,Socket会根据路由表选择需要从哪个网卡通讯,但是这种方式不是很好弄,因此我们选择另外一种方式,在Socket程序中指定网卡通讯,如下面程序所示,下面的程序是一个tcp client,指定从eth0这个网卡通讯: #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> #include<sys/socket.h> #include <errno.h> #include <sys/types.h> #include<netinet/in.h> #include <string.h> #include<errno.h> #include<netpacket/packet.h> #include<net/if.h> #include<net/if_arp.h> #include<netinet/in.h> #include<netinet/ip.h> #include<linux/if_ether.h> #include<arpa/inet.h> #include<sys/ioctl.h> // tcp 客户端连接ok标志 inttcp_client_connect_ok_flag = 0; int send_data_time_cnt = 0; #define M_DELAY_TIME_MS 300 int main(int argc, char**argv) { int sockfd, recvbytes,res,flags,error,n; socklen_t len; fd_set rset,wset; struct timeval tval; tval.tv_sec = 0; tval.tv_usec = 0; struct sockaddr_in serv_addr; // 发送字符串 char* sendData = "1234567890"; // 接收buffer char buf[1024] = "\0"; printf("eth0-client:Version 1.003\n"); // 创建socket描述符 sockfd = socket(AF_INET, SOCK_STREAM, 0); if( sockfd == -1) { perror("eth0-client:socket create failed"); return 1; } else { printf("eth0-client:creat sockfd =%d\n",sockfd); } struct ifreq interface; strncpy(interface.ifr_ifrn.ifrn_name, "eth0",IFNAMSIZ); if (setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE, (char *)&interface, sizeof(interface))< 0) { perror("eth0-client:SO_BINDTODEVICEfailed"); /*Deal with error... */ return -1; } serv_addr.sin_family=AF_INET; // 服务器tcp端口和IP地址设定 serv_addr.sin_port=htons(5000); serv_addr.sin_addr.s_addr =inet_addr("192.168.2.140"); bzero(&(serv_addr.sin_zero),8); printf("eth0-client:connect to ip=192.168.2.140port=5000\n"); // 设置为非阻塞,首先获取flag,设定noblock,然后设定flag flags = fcntl(sockfd,F_GETFL,0); fcntl(sockfd,F_SETFL,flags|O_NONBLOCK); if ( (res = connect(sockfd, (struct sockaddr *)&serv_addr,sizeof(struct sockaddr)) )< 0) { // 如果返回则表示错误,直接返回 if(errno != EINPROGRESS) { printf("eth0-client:connect error\n"); return 1; } } //如果server与client在同一主机上,有些环境socket设为非阻塞会返回 0 if(0 == res) { tcp_client_connect_ok_flag = 1; //goto done; } while(1) { usleep( M_DELAY_TIME_MS *1000); if(tcp_client_connect_ok_flag == 0) { FD_ZERO(&rset); FD_SET(sockfd,&rset); wset = rset; if( ( res = select(sockfd+1, NULL, &wset,NULL,&tval) ) <= 0) { printf("eth0-client:connect timeout\n"); } else { len = sizeof(error); getsockopt(sockfd, SOL_SOCKET, SO_ERROR,&error, &len); if (error) { fprintf(stderr, "eth0-client:Errorin connection() %d - %s\n", error, strerror(error)); //return 1; } else { tcp_client_connect_ok_flag = 1; printf("eth0-client:connectok\n"); } } } else if(tcp_client_connect_ok_flag == 1) { send_data_time_cnt += M_DELAY_TIME_MS ; if(send_data_time_cnt >= 1000) { send_data_time_cnt = 0; if ( (n = send(sockfd, sendData,strlen(sendData),0) ) ==-1 ) { perror("eth0-client:senderror!"); } } FD_ZERO(&rset); FD_SET(sockfd,&rset); wset = rset; if( ( n = select(sockfd+1,&rset,NULL,NULL,&tval)) <= 0 )//rset没有使用过,不用重新置为sockfd { } else if(n > 0) { if ((recvbytes=recv(sockfd, buf, 1024, 0))==-1) { perror("eth0-client:recverror!"); close(sockfd); return 1; } buf[recvbytes] = 0x00; printf("eth0-client:receive num%d\n",recvbytes); printf("%s\n",buf); } } }// while(1) close(sockfd); } 关键代码在于 struct ifreq interface; strncpy(interface.ifr_ifrn.ifrn_name, "eth0",IFNAMSIZ); if (setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE, (char *)&interface, sizeof(interface))< 0) { perror("eth0-client:SO_BINDTODEVICEfailed"); /*Deal with error... */ return -1; } 这里的意思是这个Socket指定到网卡eth0。 网络测试: Eth0上tcp client方式
在PC-B上创建一个tcp服务器,监听5000端口,使用LSD的网络调试工具。 然后在串口终端执行 [root@YuGe-AM1808/]#./tcp-client-noblock-eth0 eth0-client:Version 1.003 eth0-client:creat sockfd = 3 eth0-client:connect toip=192.168.2.140 port=5000 eth0-client:connect ok
从上面可以看出已经连接上 上图是PC-B上显示收到连接 连接建立之后,PC-B会不断收到数据,另外通过网络调试工具发送数据到eth0 串口终端显示已经收到数据了 eth0-client:receive num 10 1234567890 这里通讯OK了。 ra0上tcp server方式 首先在串口终端上执行如下命令,监听端口6000 [root@YuGe-AM1808 /]#./tcp-server-noblock-ra0& [root@YuGe-AM1808/]#ra0-server:creat socket ok ra0-server:SO_BINDTODEVICEok ra0-server:setsocslistenJ kopt ok ra0-server:bind port=6000 ok ra0-server:listen ok ra0-server:listen time out ra0-server:listen time out 这里看到已经在监听了。
然后在PC-A上创建一个tcp client,连接到192.168.1.57,端口为6000
然后单击连接按钮,连接成功后显示如下 file:///F:/PERSON~1/Temp/msohtmlclip1/01/clip_image002.jpg 此时串口终端显示如下信息 ra0-server:listen time out ra0-server:accept connectionok ra0-server:Yout got aconnection from 192.168.1.140. 这里表示已经连接成功了,此时查看PC-A的tcp client,可以看到不断的会收到数据,然后也可以手动发送数据给ra0。 file:///F:/PERSON~1/Temp/msohtmlclip1/01/clip_image004.jpg file:///F:/PERSON~1/Temp/msohtmlclip1/01/clip_image006.jpg ra0-server:receive num 10 1234567890 到这里就表示网络通讯成功了。 注意:基于篇幅问题,没有写四个测试程序的现象,实际我这边测试是按照eth0的client、server,ra0的client、server四种程序做的,同时测试没有出现丢包现象。 假设FT3232的驱动在目录Test\测试所需软件\FDDI芯片USB驱动\FTDI下。 static void __initam335x_evm_i2c_init(void) { /* Initially assume Low Cost EVM Config */ am335x_evm_id = LOW_COST_EVM; //evm_init_cpld(); //omap_register_i2c_bus(1, 100, am335x_i2c_boardinfo, // ARRAY_SIZE(am335x_i2c_boardinfo)); omap_register_i2c_bus(3, 100, am335x_i2c_boardinfo, ARRAY_SIZE(am335x_i2c_boardinfo)); } 有些图片显示不全的,请查看附件pdf。
|