2013-07-03 46 views
2

我在Linux/Debian的RAW插槽工作,我有一個問題,當我使用write()代替的sendto():Linux的RAW插槽

struct sockaddr_ll socket_address; 
/* Index of the network device */ 
socket_address.sll_ifindex = if_idx.ifr_ifindex; 
/* Address length*/ 
socket_address.sll_halen = ETH_ALEN; 
/* Destination MAC */ 
socket_address.sll_addr[0] = 0x00; 
socket_address.sll_addr[1] = 0x11; 
socket_address.sll_addr[2] = 0x22; 
socket_address.sll_addr[3] = 0x33; 
socket_address.sll_addr[4] = 0x44; 
socket_address.sll_addr[5] = 0x55; 

/* Send packet */ 
int b_written = 0; 

if ((b_written = write(sockfd, sendbuf, tx_len, 
            (struct sockaddr*)&socket_address, 
            sizeof(struct sockaddr_ll))) < 0) 
/* 
if ((b_written = sendto(sockfd, sendbuf, tx_len, 0, 
            (struct sockaddr*)&socket_address, 
        sizeof(struct sockaddr_ll))) < 0) 
*/ 
{ 
    perror("Could not write socket..."); 
    fprintf(stderr, "ERRNO = %d\n", errno); 
    exit(-1); 
} 
printf("Packet sent!, Bytes written = %d\n", b_written); 

如果我用 「寫」,而不是SENDTO,我得到以下錯誤:「沒有這樣的設備或地址」(errno = 6,它被定義爲EXNIO)。

使用「sendto」我沒有問題,數據包顯示在「tcpdump -nettti eth0」(ether dst host 00:11:22:33:44:55)'「中。

根據man(sendto),sendto相當於一個沒有指定任何標誌的寫入。由於我用於「sendto」的標誌字段是'0',我猜這兩個系統調用是等價的。

我做錯了什麼?這兩個電話是否等同是否正確?

+0

'write()'不能有5個參數。 – nouney

+0

至於該手冊頁的內容,似乎sendto()和sendmsg()之間的唯一區別是如何將參數傳遞給這些函數。爲什麼使用「sendmsg()」而不是「sendto()」更適合鏈接層級的RAW套接字? – Ricardo

+0

這是原始碼。你的意思是「寫」或「發送」。我想,諾尼說的是對的。如果它是'發送',那麼你不能使用它進行無連接服務,例如:SOCK_RAW – Aravind

回答

3

sendto()調用只有在套接字處於連接狀態時才能使用(以便知道預期收件人)。 以下是寫功能的原型,它有3個參數不是5,如send()函數。

write(int fd, const void *buf, size_t count);

+0

即使有3個參數,我也得到相同的錯誤號#6(EXNIO:「沒有這樣的設備或地址」)。寫入的調用如下所示:write(sockfd,sendbuf,tx_len)。 – Ricardo

+0

我想到的一個新問題是:如果按照「write」的manpage,這個函數有3個參數,爲什麼我可以編譯並執行我的代碼,將5個參數傳遞給「write」?它是否支持多個參數並忽略那些不需要的參數? GCC是否應該(至少)提醒我這個問題? – Ricardo

+1

@ Ricardo不,它不支持多個參數。你的編譯器選項是什麼?你是用** - Wall **來編譯的嗎? – nouney

0

此消息是由I/O到特殊文件的子設備產生的,該子設備不存在或超出設備限制。因此,請檢查,您是否有權限或訪問權限來寫入要執行寫入操作的位置。還可以更改寫入參數,因爲它只能有三個參數。

從手冊頁

int write(fd, buf, nbyte) 

我希望這個解決問題。

+1

如果它是一個權限錯誤,他爲什麼會得到寫入錯誤但不發送? – xaxxon

+0

現在,我正在執行該應用程序爲,因爲我還需要打開套接字的權限;所以我想這不是一個權限問題。 – Ricardo

+0

@Ricardo ...我說因爲你越來越errno = 6,這意味着設備不存在。如果你有物理上的設備(如我所設想的那樣),那麼只有一個問題。所以檢查設備文件。權限必須讀取666(crw-rw-rw-)。 – someone

3

你必須bind()see manual)地址到你的插座,然後使用write()正確(這意味着,只有參數)。

/* Send packet */ 
int b_written = 0; 

if (bind(sockfd, (struct sockaddr*)&socket_address, sizeof(struct sockaddr_ll)) == -1) 
{ 
    perror("bind"); 
    exit(-1); 
} 
if ((b_written = write(sockfd, sendbuf, tx_len)) < 0) 
{ 
    perror("Could not write socket..."); 
    fprintf(stderr, "ERRNO = %d\n", errno); 
    exit(-1); 
} 
printf("Packet sent!, Bytes written = %d\n", b_written); 
+0

是的,這解決了這個問題。謝謝@nouney!請在下面的答案中找到完整的解決方案,因爲填寫sockaddr_ll結構的某些字段很重要。 – Ricardo