我正在使用 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。变量、信号量等。就像我说的,我会尽我所能获得帮助。(另外,我不确定我是否完全正确地发布了代码,因为这是我的第一个问题。让我知道是否应该更改格式以使其更具可读性。)
谢谢!