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)