2011-11-12 139 views
4

我正在嘗試製作一個簡單的客戶端 - 服務器聊天程序。在客戶端,我分離出另一個線程來讀取來自服務器的任何傳入數據。問題是,當一個人從主線程註銷時,我想優雅地終止第二個線程。我試圖使用共享變量'running'來終止,問題是,socket read()命令是一個阻塞命令,所以如果我這樣做(運行== 1),服務器必須在讀取返回之前發送一些內容並且可以再次檢查時間條件。我正在尋找一種方法(只有常見的unix套接字)來執行非阻塞式讀取,基本上某種形式的peek()可以工作,因爲我可以不斷檢查循環以查看是否完成。C- Unix套接字 - 無阻塞讀取

閱讀線程循環如下,現在它沒有共享變量的任何互斥量,但我打算補充,以後不用擔心! ;)

void *serverlisten(void *vargp) 
{ 
    while(running == 1) 
    { 
     read(socket, readbuffer, sizeof(readbuffer)); 
     printf("CLIENT RECIEVED: %s\n", readbuffer); 
    } 
    pthread_exit(NULL); 
} 

回答

8

可以使插座無法阻斷的,在另一篇文章中建議加用select等待輸入與超時,像這樣:

fd_set   input; 
FD_ZERO(&input); 
FD_SET(sd, &input); 
struct timeval timeout; 
timeout.tv_sec = sec; 
timeout.tv_usec = msec * 1000; 
int n = select(sd + 1, &input, NULL, NULL, &timeout); 
if (n == -1) { 
    //something wrong 
} else if (n == 0) 
    continue;//timeout 
if (!FD_ISSET(sd, &input)) 
    ;//again something wrong 
//here we can call not blockable read 
+0

sd + 1在這種情況下意味着什麼?我像這樣運行它,並且它能夠工作,但它會像循環20次那樣循環,然後停止,直到創建新輸入,但它像我想要的那樣優雅地終止,唯一的問題是20次。它幾乎就像它在超時或運行期間運行的那樣 – will

+0

您可以在終端中輸入「man select」以獲取選擇功能的詳細說明。因爲在這裏我們只有一個描述符,所以我只寫(sd + 1)。 – fghj

+0

大約20次不瞭解說明。我的代碼在你的第一個問題的上下文應該是這樣的:1)檢查標誌(退出的時間?)2)睡眠直到輸入或超時3)讀取一些東西4)goto(1)。所以它會延遲退出。但是你應該處理另一方關閉連接時的情況,然後選擇返回控制給你,但是「讀取」將讀取0字節,並且你得到了繁忙循環。所以你應該檢查「read」的結果,如果它爲零,則退出循環。 – fghj

6
fcntl(socket, F_SETFL, O_NONBLOCK); 

,或者如果你有其他的標誌:

int x; 
x=fcntl(socket ,F_GETFL, 0); 
fcntl(socket, F_SETFL, x | O_NONBLOCK); 

然後檢查的讀取返回值,看看是否有可用的數據。

注意:一點谷歌搜索會產生很多完整的例子。

您也可以使用阻塞套接字,並在select超時時使用「peek」。在這裏似乎更合適,所以你不必忙於等待。

1

查找功能setsockopt與選項SO_RCVTIMEO

2

最好的事情是可能擺脫多餘的線程,並使用select()poll()來處理一個線程中的所有內容。

如果你想保持線程,你可以做的一件事情是調用shutdown()套接字SHUT_RDWR,這將關閉連接,喚醒所有阻塞的線程,但保持文件描述符有效。加入閱讀器線程後,可以關閉套接字。請注意,這隻適用於套接字,而不適用於其他類型的文件描述符。

0

這可能不是您正在尋找的具體答案,但它可能是您可以找到它的地方。我目前正在讀:

Unix Network Programming, Volume 1: The Sockets Networking API, 3rd Edition

而且有很多的多線程,非阻塞的服務器和客戶端的例子。此外,他們解釋了很多不同方法之間的推理和權衡。

希望可以幫到...

+0

通過廣告的鏈接。偉大的舉動! ;) –

+0

@YagamyLight歡迎您添加您想要的任何非廣告鏈接。我與亞馬遜或Addison-Wesley沒有任何關係。然而,連接到亞馬遜使其可以購買,預覽和評論,並且通常是一個穩定的URL,不會在不久的將來過期。 – Homer6

+0

我並不是指亞馬遜,我的意思是說,鏈接本身通過一個神祕的[rads.stackoverflow.com](http://rads.stackoverflow.com/amzn/click/0131411551)。但是,那就是說,我已經發現你的帖子中沒有這個鏈接,所以這似乎是StackOverflow本身的惡作劇。順便說一句,只是好奇 - 你在帖子中看到這樣一個鏈接(我只是認爲鏈接可以從作者隱藏)? –