2010-06-16 136 views
8

我需要使用C函數read從AF_UNIX插槽讀取緩衝區,但我不知道緩衝區大小。從插座讀取

我認爲最好的方法是讀取N字節,直到讀取返回0(套接字中不再有寫入者)。它是否正確?有沒有辦法猜測在socket上寫入的緩衝區的大小?

我在想套接字是一個特殊的文件。以二進制模式打開文件並獲取大小會幫助我瞭解緩衝區的正確大小?

我是一個非常新的C,所以請記住這一點。

回答

14

通常的方法是使用ioctl(..)查詢套接字的FIONREAD,該套接字將返回有多少數據可用。

int len = 0; 
ioctl(sock, FIONREAD, &len); 
if (len > 0) { 
    len = read(sock, buffer, len); 
} 
+0

嗨,謝謝。 閱讀中的第四個參數是什麼? – Donovan 2010-06-17 10:52:21

+1

@Alberto,啊,這是一個錯字。應該只有3讀,我先寫了'recv'... – epatel 2010-06-17 16:37:04

0

你是對的,如果你不知道輸入的大小,你可以每次只讀一個字節,並將它附加到一個更大的緩衝區。

0

讀N個字節,直到讀返回0

是的!

一個增加的細節。如果發送者沒有關閉連接,套接字將會被阻塞,而不是返回。當沒有東西可讀時,非阻塞套接字將返回-1(與errno == EAGAIN);那是另一種情況。

以二進制模式打開文件並獲取大小會幫助我知道正確的大小給緩衝區?

沒有。套接字沒有大小。假設你通過同一個連接發送了兩條消息:文件有多長?

1

我認爲最好的辦法是讀取N個字節 直到讀取(在插座沒有 更多作家)返回0。這是 是否正確?

0表示EOF,另一側已關閉連接。如果通信的另一端關閉了連接,那麼它是正確的。

如果連接沒有關閉(通過同一連接,chatty協議進行多次傳輸),那麼情況會更復雜一些,並且行爲通常取決於您是否具有SOCK_STREAM或SOCK_DGRAM套接字。

操作系統已經爲您分配了數據報套接字。如果需要的話,必須在應用程序級別上實現:例如,通過在消息頭結構中定義一個大小字段或使用分隔符(例如' \ n'用於單行文本消息)。在第一種情況下,您首先要讀取標題,提取長度並使用長度讀取消息的其餘部分。在其他情況下,將流讀入部分緩衝區,搜索分隔符並從緩衝區中提取包含分隔符的消息(您可能需要保留部分緩衝區,具體取決於協議)可以使用單個recv()/ read() ))。

有沒有辦法猜測 的緩衝區大小是否寫在 的socket?

對於流套接字,沒有可靠的方法,因爲通信的另一方可能仍在寫數據。想象一下很正常的情況:套接字緩衝區是32K和128K正在寫入。寫入應用程序會在send()/ write()內部阻塞,等待讀取應用程序的操作系統讀取數據,從而釋放下一塊寫入數據的空間。

對於數據報套接字,通常事先知道消息的大小。或者可以嘗試(從來沒有做過)recvmsg(MSG_PEEK),如果MSG_TRUNC在返回的msghdr.msg_flags中,則嘗試增加緩衝區大小。

2

從套接字讀取未知數量的同時避免阻塞的一種方法可能是poll()一個非阻塞套接字的數據。

E.g.

char buffer[1024]; 
int ptr = 0; 
ssize_t rc; 

struct pollfd fd = { 
    .fd = sock, 
    .events = POLLIN 
}; 

poll(&fd, 1, 0); // Doesn't wait for data to arrive. 
while (fd.revents & POLLIN) 
{ 
    rc = read(sock, buffer + ptr, sizeof(buffer) - ptr); 

    if (rc <= 0) 
     break; 

    ptr += rc; 
    poll(&fd, 1, 0); 
} 

printf("Read %d bytes from sock.\n", ptr);