我有一台带有4个以太网接口的机器(ensf1s1,ensf1s2,ensf1s3,ensf1f4)并使用GNAT.Sockets我需要能够通过每个接口发送/接收数据。
我正在使用的代码是
Create_Socket(SendFrom1, Family_Inet, Socket_Datagram);
Create_Socket(SendFrom2, Family_Inet, Socket_Datagram);
...
Bind_Socket(SendFrom1, SendFrom1Address);
Bind_Socket(SendFrom2, SendFrom2Address);
...
Channel1 := Stream(SendFrom1, SendToAddress1);
Channel2 := Stream(SendFrom2, SendToAddress2);
...
将IP地址配置为192.168.1。(101/102/103/104)我通过单个接口发送所有消息,并在数据包中使用正确指定的源IP和目标IP。
我在另一个问题中读到,在同一个子网上有多个网卡会导致某些操作系统出现问题,所以我改为192.168.1.101,192.168.2.102等,子网掩码为255.255.0.0。使用与地址相同的代码更正后,这只发送了用于以前发送所有消息的接口的数据,但在另一个上没有发送任何消息。
我是否遗漏了Socket配置中的内容,以确保Socket与指定了SendFromAddress的适配器捆绑在一起?如果相关,操作系统是RHEL 7。
答案 0 :(得分:0)
您的问题与套接字的工作方式有关。
如果将套接字绑定到特定地址,则只会收到该目标地址的数据包。 要从四个接口中的任何一个接收数据包,您可以绑定到INADDR_ANY地址。您将按如下方式执行此操作:
Address : GNAT.Sockets.Sock_Addr_Type;
SendFromAll : GNAT.Sockets.Socket_Type;
...
Address.Port := 0; -- Or whatever fixed port you like
Address.Addr := GNAT.Sockets.Any_Inet_Addr;
GNAT.Sockets.Bind_Socket (SendFromAll, Address);
使用此实现, SendFromAll 套接字将从任何接口接收数据。使用 Receive_Socket ,您可以获取发件人地址。然后,当您使用 SendFromAll 套接字将数据发送回客户端时,系统将根据目标地址和网络路由表选择接口。在Linux上,它将取决于路由策略(ip规则)和路由表(ip route)。
Client : GNAT.Sockets.Sock_Addr_Type;
Buffer : Ada.Streams.Stream_Element_Array (0 .. 8192);
Last : Ada.Streams.Stream_Element_Offset;
....
GNAT.Sockets.Receive_Socket (SendFromAll, Buffer, Last, Client);
GNAT.Sockets.Send_Socket (SendFromAll, Buffer (Buffer'First .. Last), Last, Client);
现在,如果您确实需要将套接字绑定到接口,则必须获取该接口的IP地址。如果您有多个接口,则必须获取自己的IP地址。使用 GNAT.Sockets 进行此操作并不容易。您可以使用 Get_Host_By_Name 功能,但必须为每个接口设置不同的名称(否则您将为每个套接字获得相同的IP)。
GNAT.Sockets 无法实现的另一种方法是使用SO_BINDTODEVICE套接字选项。您将套接字绑定到接口名称(您不需要获取IP)。
您可能会遇到的问题是,您为每个 Bind_Socket 电话使用相同的IP地址。