簡體   English   中英

select()和具有C上動態緩沖區的非阻塞recv

[英]select() and non-blocking recv with dynamic buffer on C

我試圖弄清楚為什么recv在下面的代碼中被阻止,如果我通過telnet並發送“ GET / HTTP / 1.1”,則recv會一直在等待數據,並且也會阻止另一個telnet連接。 但是,如果我只是使用固定緩沖區而不是do{} while ,那么它可以正常工作並且不會阻塞,即,

char buffer[1024];
nbytes = recv(i, buffer, sizeof buffer, 0);

到目前為止,我了解到, select()處於就緒狀態。 我需要將recv設置為O_NONBLOCK嗎?

char *buffer = NULL;
unsigned long LEN = 200;
unsigned long bytes_received = 0;
unsigned long cur_size = 0;
int status = 0;

FD_SET(listener, &master);
fdmax = listener;

for(;;){
    read_fds = master; // copy it
    if(select(fdmax+1, &read_fds, NULL, NULL, NULL) == -1){
        exit(4);
    }   

    for(i = 0; i <= fdmax; i++){
        if(FD_ISSET(i, &read_fds)){
            if(i == listener){
                // handle new connections
                addrlen = sizeof remoteaddr;
                newfd = accept(listener, (struct sockaddr *)&remoteaddr, &addrlen);

                if(newfd == -1){
                    perror("accept");
                }else{
                    FD_SET(newfd, &master);
                    if(newfd > fdmax) { 
                        fdmax = newfd;
                    }
                }
            }else{
                do{
                    if(bytes_received >= cur_size){
                        char * tmp;
                        cur_size += LEN;
                        tmp = realloc(buffer, cur_size);
                        buffer = tmp;
                    }
                    status = recv(i, buffer + bytes_received, LEN, 0); 
                    if(status == 0){ 
                        printf("Done\n");
                    }
                    else if(status > 0){ 
                        bytes_received += status;
                    }
                    else{
                        fprintf(stderr, "socket error\n");
                    }
                } while (status > 0); 
                if(send(i, buffer, strlen(buffer), 0) == -1){
                    perror("send");
                }   
            }   
        }   
    }
}

首先,如果您不想阻塞,則必須將套接字設置為非阻塞。 無論您做什么,都無法確保如果套接字操作正在阻塞,則永遠不會阻塞。 這是一個常見的錯誤,已導致嚴重的錯誤,並帶有重大的安全隱患。 如果必須阻止,則必須將套接字設置為非阻止。

到目前為止,我了解到,select()處於就緒狀態。

您的意思處於准備就緒狀態。 select函數是一個狀態報告功能,與其他狀態報告功能一樣,它會在調用它和返回它之間的某個時間點報告狀態。 無法保證在以后的某個時刻仍保持該狀態。

永遠不要認為您可以排除狀態可能改變的所有其他可能方式。 歷史充滿了那些認為並被焚毀的人。

但是阻止的具體原因是您在調用recv沒有先調用select (因為您有一個do循環再次調用recv )。

無論如何,您必須正確處理來自recvWOULDBLOCK指示。 那是必不可少的。

另外,您可能希望每個select recv僅調用一次recv 如果您解決了其他問題,那就沒關系了。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM