1. 程式人生 > >socket通過多網絡卡收發資料

socket通過多網絡卡收發資料

1.   通過bind機制,   socket必須要呼叫bind才能傳送tcp包。 bind呼叫時需要一個ip地址。一般一臺機器的多網口都要配置不同的ip地址(路由器除外,路由器是一個網橋裝置,只是負責轉發包,所以其它的埠一般沒有ip地址)。

2.   通過ioctl來設定開啟的socket.     (ioctl (fd, SIOCGIFINDEX, &ifr)==0;

TCP程式設計時不管是客戶端還是伺服器端,都要呼叫bind後才能連線/收發資料。

UDP在客戶端時可以不呼叫bind而直接使用recvfrom/sendto來收發資料。 

在客戶端一般是本地地址選擇INETADDR_ANY, 表示所有網路介面。

程式碼如下:

#include <stdio.h>;
#include <string.h>;
#include <sys/socket.h>;
#include <netpacket/packet.h>;
#include <net/ethernet.h>;
#include <sys/ioctl.h>;
#include <net/if.h>;
#include <assert.h>;


int
main ()
{
        struct sockaddr_ll sll;
        int fd;
        struct ifreq ifr;
        char *dev;

        fd = socket (PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));

        dev = "eth0";
        strncpy ((char *)ifr.ifr_name, dev, sizeof(ifr.ifr_name));
        assert (ioctl (fd, SIOCGIFINDEX, &ifr)==0);

        memset (&sll, 0, sizeof(sll));
        sll.sll_family = AF_PACKET;
        sll.sll_protocol = htons (ETH_P_ALL);
        sll.sll_ifindex = ifr.ifr_ifindex;

        assert (bind (fd, (struct sockaddr *)&sll, sizeof(sll))==0);

}

##############################################################

Windows網路程式設計總結(一)
作者:   Kendiv
出處:   CSDN.NET  

  關於bind:

  INADDR_ANY   的具體含義是,繫結到0.0.0.0。此時,對所有的地址都將是有效的,如果系統考慮冗餘,採用多個網絡卡的話,那麼使用此種bind,將在所有網絡卡上進行繫結。在這種情況下,你可以收到傳送到所有有效地址上資料包。

  例如:

  SOCKADDR_IN   Local;

  Local.sin_addr.s_addr   =   htonl(INADDR_ANY);

  
  另外一種方式如下:

  SOCKADDR_IN   Local;

  hostent*   thisHost   =   gethostbyname( " ");

  char*   ip   =   inet_ntoa(*(struct   in_addr   *)*thisHost-> h_addr_list);

  Local.sin_addr.s_addr   =   inet_addr(ip);

  在這種方式下,將在系統中當前第一個可用地址上進行繫結。在多網絡卡的環境下,可能會出問題。

  
  最常見的方式:

  const   char   LocalIP[]   =   "192.168.0.100 ";

  SOCKADDR_IN   Local;

  Local.sin_addr.s_addr   =   inet_addr(LocalIP);

  bind(socket,   (LPSOCKADDR)&Local,   sizeof(SOCKADDR_IN)


  bind的安全問題:

  如果你在bind時,使用了INADDR_ANY那麼,你將可以在所有有效的地址上進行監聽,但是Socket有一個特性:可在同一埠上繫結多個Socket。

  讓我們看看下面的情況:假設你的系統只有一個IP:192.168.0.100,你希望bind到4096埠。對於下面的兩種bind,當資料包到達時,誰會接收到呢?

  Local.sin_addr.s_addr   =   htonl(INADDR_ANY);

  Local.sin_addr.s_addr   =   inet_addr(“192.168.0.100”);


  WinSocke庫是這樣處理的:誰繫結的最明確,誰獲取資料包。顯然,第二種bind將獲取到達的資料包。如果避免這種情況呢?使用SO_EXECLUSINEADDRUSE選項。需要注意的是,此選項在Windows   NT   4   Service   Pack   4以後(包括SP4)才可以使用。

  示例程式碼:

  #ifndef   SO_EXECLUSINEADDRUSE

  #define   SO_EXECLUSINEADDRUSE   ((int)(~SO_REUSEADDR))

  #endif
  

  SOCKADDR_IN   Local;

  BOOL   val   =   TRUE;

  
  Local.   sin_family   =   AF_INET;

  Local.   sin_port   =   htons(4096);

  Local.sin_addr.s_addr   =   htonl(INADDR_ANY);

  
  setsocketopt(socket,

  SOL_SOCKET,

  SO_EXECLUSINEADDRUSE,

  (char*)&val,

  sizeof(val));

  
  bind(socket,   (LPSOCKADDR)&Local,   sizeof(SOCKADDR_IN)