查看: 3165|回复: 0

[技术交流] 嵌入式Linux下双网口Socket编程

[复制链接]

3

主题

3

帖子

22

积分

超级版主

Rank: 8Rank: 8

积分
22
发表于 2018-11-15 19:58:39 | 显示全部楼层 |阅读模式
嵌入式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。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

快速回复 返回顶部 返回列表