5

我正在使用 Pthreads(我更讨厌)用 C 语言(我很讨厌)编写一个 Web 服务器,但我被困在了这一点上。服务器的模型是boss-worker,因此boss线程在程序开始时实例化所有工作线程。有一个全局队列存储传入连接的套接字。老板线程是在接受连接时将所有项目(套接字)添加到队列中的线程。然后,所有工作线程等待将一个项目添加到全局队列中,以便它们开始处理。

只要我连接到它的次数少于服务器拥有的工作线程数,服务器就可以正常工作。因此,我认为要么是我的互斥体有问题(可能信号丢失了?),要么线程在运行一次后被禁用(这可以解释为什么如果有 8 个线程,它只能解析第一个8 个 http 请求)。

这是我的全局队列变量。

int queue[QUEUE_SIZE];

这是主线。它使用入队、出队、空等方法创建一个队列结构(在别处定义)。当服务器接受连接时,它将传入连接所在的套接字入队。一开始调度的工作线程不断检查这个队列,看是否添加了任何作业,如果有作业,则它们将套接字出列,连接到该端口,并读取/解析/写入传入的 http 请求.

int main(int argc, char* argv[])
{
int hSocket, hServerSocket;  /* handle to socket */
struct hostent* pHostInfo;   /* holds info about a machine */
struct sockaddr_in Address; /* Internet socket address stuct */
int nAddressSize = sizeof(struct sockaddr_in);
int nHostPort;
int numThreads;
int i;

init(&head,&tail);

//**********************************************
//ALL OF THIS JUST SETS UP SERVER (ADDR STRUCT,PORT,HOST INFO, ETC)
if(argc < 3) {
    printf("\nserver-usage port-num num-thread\n");
    return 0;
}
else {
    nHostPort=atoi(argv[1]);
    numThreads=atoi(argv[2]);
}

printf("\nStarting server");

printf("\nMaking socket");
/* make a socket */
hServerSocket=socket(AF_INET,SOCK_STREAM,0);

if(hServerSocket == SOCKET_ERROR)
{
    printf("\nCould not make a socket\n");
    return 0;
}

/* fill address struct */
Address.sin_addr.s_addr = INADDR_ANY;
Address.sin_port = htons(nHostPort);
Address.sin_family = AF_INET;

printf("\nBinding to port %d\n",nHostPort);

/* bind to a port */
if(bind(hServerSocket,(struct sockaddr*)&Address,sizeof(Address)) == SOCKET_ERROR) {
    printf("\nCould not connect to host\n");
    return 0;
}
/*  get port number */
getsockname(hServerSocket, (struct sockaddr *) &Address,(socklen_t *)&nAddressSize);

printf("Opened socket as fd (%d) on port (%d) for stream i/o\n",hServerSocket, ntohs(Address.sin_port));

printf("Server\n\
      sin_family        = %d\n\
      sin_addr.s_addr   = %d\n\
      sin_port          = %d\n"
      , Address.sin_family
      , Address.sin_addr.s_addr
      , ntohs(Address.sin_port)
    );
//Up to this point is boring server set up stuff. I need help below this.
//**********************************************

//instantiate all threads
pthread_t tid[numThreads];

for(i = 0; i < numThreads; i++) {
    pthread_create(&tid[i],NULL,worker,NULL);
}

printf("\nMaking a listen queue of %d elements",QUEUE_SIZE);
/* establish listen queue */
if(listen(hServerSocket,QUEUE_SIZE) == SOCKET_ERROR) {
    printf("\nCould not listen\n");
    return 0;
}

while(1) {

    pthread_mutex_lock(&mtx);
    printf("\nWaiting for a connection");

    while(!empty(head,tail)) {
        pthread_cond_wait (&cond2, &mtx);
    }

    /* get the connected socket */
    hSocket = accept(hServerSocket,(struct sockaddr*)&Address,(socklen_t *)&nAddressSize);

    printf("\nGot a connection");

    enqueue(queue,&tail,hSocket);

    pthread_mutex_unlock(&mtx);
    pthread_cond_signal(&cond);     // wake worker thread
}
}

这是工作线程。这应该始终运行检查新请求(通过查看队列是否为空)。在这个方法结束时,它应该推迟回到老板线程以等待下一次需要它。

void *worker(void *threadarg) {

pthread_mutex_lock(&mtx);

while(empty(head,tail)) {
    pthread_cond_wait(&cond, &mtx);
}
int hSocket = dequeue(queue,&head);

unsigned nSendAmount, nRecvAmount;
char line[BUFFER_SIZE];

nRecvAmount = read(hSocket,line,sizeof line);
printf("\nReceived %s from client\n",line);


//***********************************************
//DO ALL HTTP PARSING (Removed for the sake of space; I can add it back if needed)
//*********************************************** 


nSendAmount = write(hSocket,allText,sizeof(allText));

if(nSendAmount != -1) {
    totalBytesSent = totalBytesSent + nSendAmount;
}
printf("\nSending result: \"%s\" back to client\n",allText);

printf("\nClosing the socket");
/* close socket */
if(close(hSocket) == SOCKET_ERROR) {
    printf("\nCould not close socket\n");
    return 0;
}


pthread_mutex_unlock(&mtx);
pthread_cond_signal(&cond2);
}

任何帮助将不胜感激。如果有人需要,我可以发布更多代码,请告诉我。我不是最擅长操作系统的东西,尤其是在 C 语言中,但我知道互斥锁的基础知识,cond。变量、信号量等。就像我说的,我会尽我所能获得帮助。(另外,我不确定我是否完全正确地发布了代码,因为这是我的第一个问题。让我知道是否应该更改格式以使其更具可读性。)

谢谢!

4

1 回答 1

5

工人革命的时候了。

工作线程似乎缺少一个 while(true) 循环。在 HTTP 交换并关闭套接字之后,它们应该循环返回以在队列中等待更多套接字/请求。

于 2012-09-30T11:30:04.900 回答