我正在使用Pthreads编写一个Web服务器(我用它来吸吮)(我更糟糕的是),而且我已经陷入了困境。服务器的模型是boss-worker,因此boss线程在程序开始时实例化所有工作线程。存在一个全局队列,用于存储传入连接的套接字。 boss线程是在接受连接时将所有项(套接字)添加到队列的线程。然后,所有工作线程等待将项目添加到全局队列,以便它们接受处理。
只要连接服务器的次数少于服务器拥有的工作线程数,服务器就可以正常工作。因此,我认为我的互斥体出现问题(可能信号丢失了?)或线程在运行一次后被禁用(这可以解释为什么如果有8个线程,它只能解析第一个8个http请求)。
这是我的全局队列变量。
int queue[QUEUE_SIZE];
这是主线程。它创建一个队列结构(在其他地方定义),方法是enqueue,dequeue,empty等。当服务器接受连接时,它会将传入连接所在的套接字排入队列。在开始时调度的工作线程不断检查此队列以查看是否已添加任何作业,如果有作业,则它们将套接字出列,连接到该端口,并读取/解析/写入传入的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。变量,信号量等。就像我说的,我会得到所有的帮助。 (另外,我不确定我是否完全正确地发布了代码,因为这是我的第一个问题。让我知道是否应该更改格式以使其更具可读性。)
谢谢!
答案 0 :(得分:3)
工人革命的时间。
工作线程似乎缺少一段时间(真实)循环。在HTTP交换并关闭套接字之后,它们应该循环返回以在队列上等待更多套接字/请求。