2011-03-31 62 views
0

我想弄清楚什么是阻止我的程序。我正在运行一个使用POSIX线程的服务器。我必须为我的计算机编程实验室。主函数监听新的连接。一旦它接受了连接,它就会通过将FD传递给该线程来创建一个新线程。我能够使用多个telnet /客户端连接成功连接到服务器。我可以成功地将数据发送到服务器一次,但如果我尝试再次发送服务器将不会执行任何操作。主要功能使用Unix和C/C++的块套接字帮助

int active_thread = 0; 
    //The Running loop 
while(running) 
{ 
    if(active_thread > NUMBTHREADS) 
    { 
     printf("Unable to accept client connection! Threads are all used up"); 
     running = false; 
    } 
    else 
    { 
     if(FD_ISSET(sockfd, &readfds)) 
     { 
      if((bindfd[active_thread] = accept(sockfd, (struct sockaddr *) &client_addr, &client_sock_size)) == -1) 
      { 
       fprintf(stderr, "Unable to accept client \n"); 
       perror("What"); 
       break; 
      } 

      activethreads[active_thread] = pthread_create(&threads[active_thread], NULL, server_handler, (void*) &bindfd[active_thread]); 
      //close(bindfd[active_thread]); 
      //pthread_join(threads[active_thread], NULL); 
      active_thread++; 
      //running = false; 
      }  
     } 
    } 
    close(sockfd); 
    return 0; 
} 

POSIX线程代码

void *server_handler(void *sockfd) 
{ 
    int bindfd = *((int *) sockfd); 
    char buffer[MESSAGELENGTH]; 
    bool running = true; 
    printf("Thread was created successfully\n"); 
    char intro[] = "Successfully Connected to server!\n"; 
    struct pollfd pfd; 
    pfd.fd = bindfd; 
    pfd.events = POLLIN; 

    if ((send(bindfd, intro, strlen(intro), 0)) < 0) 
    { 
     perror("Unable to send"); 
    } 

    while(running){ 
    char msg[] = "\nYou have the following options!\n1) Insert an integer: insert <integer>\n2) Remove An Integer: remove <integer>\n3) Get number of integers in list: get_count\n4) Get first integer: get_first\n5) Get last integer: get_last\n6) Quit program: quit\n "; 
    if ((send(bindfd, msg, strlen(msg), 0)) < 0) 
    { 
     perror("Unable to send"); 
    } 
    memset(&buffer, 0, MESSAGELENGTH); 
    if (recv(bindfd, buffer, MESSAGELENGTH, 0) > 0) 
    { 
     //SOme other code 
    } 
} 

的部分

部分,我认为它在阻止无论是接受或recv。我听说过select()和其他各种方法,但我很难实现它们。谢谢!

+0

你真的需要使用select(或轮询,而是选择更容易IMO),以确保您的套接字fd的准备读或写。对不起,我没有时间atm提供一个真正的答案,但谷歌周围的例子与选择,我相信你会最好的。 – 2011-03-31 01:01:33

+0

在几个打印语句中添加应该知道它阻塞的位置。如果您在拨打'recv'时阻止,则可能等待您发送数据。作为一个方面说明,看起来你在'server_handler'中的'while'循环中有大括号的不匹配 – Jeff 2011-03-31 01:17:11

回答

1

默认情况下,网络套接字被阻塞。您需要在套接字上设置O_NONBLOCK标志。

if(fcntl(fd, F_GETFL, &flags) < 0 || 
    fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0) 
     perror("Failed to set socket as non-blocking"); 

现在,而不是当存在没有返回输入(或缓冲器空间来存储输出),则错误EAGAIN(或EWOUDLBLOCK)阻挡。最后,当你没有别的事要做时,你需要使用select()或poll(),但是在I/O上等待。这些调用只会在有输入,输出空间或可能超时时间的情况下唤醒进程。

int maxFd; 
fdset fds; 

FD_ZERO(&fds); 
FD_SET(listenFd, &fds); 
FD_SET(sockFd1, &fds); 
FD_SET(sockFd2, &fds); 
maxFd = listenFd+1; 
maxFd = sockFd1 > maxFd ? sockFd1+1 : maxFd; 
maxFd = sockFd2 > maxFd ? sockFd2+1 : maxFd; 
if(select(maxFd, &fds, &fds, &fds, NULL) < 0) { 
     perror("Failed on select()"); 
     exit(1); 
} 
if(FD_ISSET(listenFd, &fds)) 
    ... 

这个例子是不完整的或neccessarily 100%正确的,但应该是一个良好的开端。另外,我倾向于在处理SOCK_DGRAM套接字时使用send *()和recv *()并在SOCK_STREAM套接字上使用read(),write()。

2

您的问题的根本原因似乎是您无条件在while (running)循环的底部执行close(sockfd); return 0;,这意味着该循环只执行一次。

此外,除非您还使用select(),否则不应使用FD_ISSET()。你的主循环看起来应该更像:

int active_thread = 0; 

while (active_thread < NUMBTHREADS) 
{ 
    if((bindfd[active_thread] = accept(sockfd, (struct sockaddr *) &client_addr, &client_sock_size)) == -1) 
    { 
     fprintf(stderr, "Unable to accept client \n"); 
     perror("What"); 
     break; 
    } 

    activethreads[active_thread] = pthread_create(&threads[active_thread], NULL, server_handler, (void*) &bindfd[active_thread]); 
    active_thread++; 
} 

if (active_thread >= NUMBTHREADS) 
{ 
    printf("Unable to accept client connection! Threads are all used up.\n"); 
} 
running = false; 
close(sockfd); 
return 0;