2013-01-08 77 views
1

我目前正試圖實現一個在Linux上運行的小型FastCGI多線程應用程序。我使用fastcgi.com的圖書館。現在我不確定我是否真正瞭解Web服務器與我的應用程序之間FCGI通信的工作原理。對FCGI概念感到困惑

首先,我在我的應用程序中創建一個新的套接字。我返回文件描述符。

int socketIn = 0; 
struct sockaddr_un local; 
int length = 0; 
int value = 1; 

memset(&local, 0, sizeof(local)); 

local.sun_family = AF_UNIX; 

strcpy(local.sun_path, socketPath); 

length = strlen(local.sun_path) + sizeof(local.sun_family); 

/* delete old unix socket */ 
if(-1 == unlink(socketPath)) 
{ 
    switch (errno) 
    { 
     case ENOENT: 
     { 
     }break; 

     default: 
     { 
      printf("\n[Error]\tCould not remove old socket."); 
      return -1; 
     } 
    } 
} 

/* create new socket */ 
if (-1 == (socketIn = socket(AF_UNIX, SOCK_STREAM, 0))) 
{ 
    printf("\n[Error]\tCould not create socket."); 
    return -2; 
} 

/* bind socket */ 
if (-1 == bind(socketIn, (struct sockaddr *)&local, length)) 
{ 
    printf("\n[Error]\tCould not bind socket."); 
    return -4; 
} 

return socketIn; 

之後,我初始化了FCGI庫:FCGX_Init();

現在我開始創建我的主題:

#define THREAD_COUNT 2 

static int counts[THREAD_COUNT]; 

struct thread_data{ 
    int thread_id; 
    int fcgiSocket; 
}; 

struct thread_data thread_data_array[THREAD_COUNT]; 

int main(int argc, char** argv) 
{ 
    int i; 
    pthread_t id[THREAD_COUNT]; 
    for (i = 1; i < THREAD_COUNT; i++) 
    { 
     thread_data_array[i].thread_id = i; 
     thread_data_array[i].fcgiSocket = fcgi.fcgiSocket; 
     pthread_create(&id[i], NULL, doit, &thread_data_array[i]); 
    } 

    thread_data_array[0].thread_id = 0; 
    thread_data_array[0].fcgiSocket = fcgi.fcgiSocket; 

    doit((void *)&thread_data_array[0]); 

    return 0; 
} 

最後我的線程代碼:

static void *doit(void *a) 
{ 
    struct thread_data *my_data; 
    my_data = (struct thread_data *) a; 
    int rc, i; 
    pid_t pid = getpid(); 
    FCGX_Request request; 
    char *server_name; 

    FCGX_InitRequest(&request, my_data->fcgiSocket, 0); 

    for (;;) 
    { 
     static pthread_mutex_t accept_mutex = PTHREAD_MUTEX_INITIALIZER; 
     static pthread_mutex_t counts_mutex = PTHREAD_MUTEX_INITIALIZER; 

     /* Some platforms require accept() serialization, some don't.. */ 
     pthread_mutex_lock(&accept_mutex); 
     rc = FCGX_Accept_r(&request); 
     pthread_mutex_unlock(&accept_mutex); 

     if (rc < 0) 
      break; 

     server_name = FCGX_GetParam("SERVER_NAME", request.envp); 

     FCGX_FPrintF(request.out, 
      "Content-type: text/html\r\n" 
      "\r\n" 
      "<title>FastCGI Hello! (multi-threaded C, fcgiapp library)</title>" 
      "<h1>FastCGI Hello! (multi-threaded C, fcgiapp library)</h1>" 
      "Thread %d, Process %ld<p>" 
      "Request counts for %d threads running on host <i>%s</i><p><code>", 
      my_data->thread_id, pid, THREAD_COUNT, server_name ? server_name : "?"); 

     pthread_mutex_lock(&counts_mutex); 
     ++counts[my_data->thread_id]; 
     for (i = 0; i < THREAD_COUNT; i++) 
      FCGX_FPrintF(request.out, "%5d " , counts[i]); 
     pthread_mutex_unlock(&counts_mutex); 

     FCGX_Finish_r(&request); 
    } 

    return NULL; 
} 

現在的我我擔心我使用的插座。這3個線程將全部寫入相同的套接字。是否有其他更好的方法來解決多線程FCGI應用程序的問題?

回答

1

我正在回覆一箇舊帖子,但也許別人可以從中受益。

「現在我擔心我使用的套接字,3個線程將全部寫入 到相同的套接字。

沒什麼好擔心的!

根據Fast CGI規範,每個請求都有關聯的ID,並且當線程將響應寫回到套接字時,它會將請求的ID與其服務相關聯。所以即使線程以不同的順序寫入,Web服務器也知道哪個請求是哪個響應。該規範是在這裏 -

http://www.fastcgi.com/drupal/node/6?q=node/22

而寫入到一個插座保證是原子,只要消息的大小小於PIPE_BUF。而libfcgi將寫入大小限制爲PIPE_BUF。您可以在以下文件中檢查這一點 -

http://www.fastcgi.com/mod_fastcgi/mod_fastcgi.h

#define FCGI_MAX_MSG_LEN PIPE_BUF 

希望這個解釋清除疑惑!

0

您可以創建一個處理所有套接字通信的新線程,並讓其他線程將其消息放入從套接字線程讀取的共享隊列中。