1. 程式人生 > >lighttpd1.4.18程式碼分析(八)--狀態機(2)CON_STATE_READ狀態

lighttpd1.4.18程式碼分析(八)--狀態機(2)CON_STATE_READ狀態

// -1:出錯 -2:對方關閉連線 0:成功staticint connection_handle_read(server *srv, connection *con) {
    
int len;
    buffer 
*b;
    
int toread;

    
if (con->conf.is_ssl) {
        
return connection_handle_read_ssl(srv, con);
    }

#if defined(__WIN32)
    b 
= chunkqueue_get_append_buffer(con->read_queue);
    buffer_prepare_copy(b, 
4*1024);
    len 
= recv(con->fd, b->ptr, b->size -10);
#else// 獲取有多少資料可讀if (ioctl(con->fd, FIONREAD, &toread)) {
        log_error_write(srv, __FILE__, __LINE__, 
"sd",
                
"unexpected end-of-file:",
                con
->fd);
        
return-1;
    }
    
// 根據資料量準備緩衝區    b = chunkqueue_get_append_buffer(con
->read_queue);
    buffer_prepare_copy(b, toread 
+1);
    
// 讀資料    len = read(con->fd, b->ptr, b->size -1);
#endifif (len <0) {
        con
->is_readable =0;

        
// Non-blocking  I/O has been selected using O_NONBLOCK and no data
        
// was immediately available for reading.if (errno == EAGAIN) 
            
return0;
        
if (errno == EINTR) {
            
/* we have been interrupted before we could read */
            con
->is_readable =1;
            
return0;
        }

        
if (errno != ECONNRESET) {
            
/* expected for keep-alive */
            log_error_write(srv, __FILE__, __LINE__, 
"ssd""connection closed - read failed: ", strerror(errno), errno);
        }

        connection_set_state(srv, con, CON_STATE_ERROR);

        
return-1;
    } 
elseif (len ==0) {
        
// 當讀入資料 = 0時 表示對端關閉了連線        con->is_readable =0;
        
/* the other end close the connection -> KEEP-ALIVE *//* pipelining */return-2;
    } 
elseif ((size_t)len < b->size -1) {
        
/* we got less then expected, wait for the next fd-event */

        con
->is_readable =0;
    }

    
// 記錄讀入的資料量 未使用的資料第一個位元組為0    b->used = len;
    b
->ptr[b->used++='\0';

    con
->bytes_read += len;
#if 0
    dump_packet(b
->ptr, len);
#endifreturn0;
}
簡單的說, 該函式首先呼叫ioctl獲取fd對應的緩衝區中有多少可讀的資料, 然後呼叫chunkqueue_get_append_buffer和buffer_prepare_copy函式準備好所需的緩衝區, 準備好緩衝區之後, 呼叫read函式讀取緩衝區中的資料.對read函式的呼叫結果進行區分, 小於0表示出錯, 返回-1;等於0表示關閉了連線, 返回-2;假如讀取的資料長度比預期的小, 那麼就等待下一次繼續讀資料, 最後將已經讀入的資料緩衝區最後一個位元組置'\0',返回0.