2013-08-30 72 views
2

我正在建立我自己的网络服务器。现在,我的简约代码是:软终止一个简单的网络服务器

#include <stdio.h> 
#include <stdlib.h> 
#include <netinet/in.h> 

#define SERVER_PORT 80 

int main() { 

    int nReqSocketId, nReqSize = 1024, nMainSocketId = socket(AF_INET, SOCK_STREAM, 0); 
    char *sRequest = malloc(nReqSize); 
    socklen_t nAddrLen; 
    struct sockaddr_in oAddress; 

    oAddress.sin_family = AF_INET; 
    oAddress.sin_addr.s_addr = INADDR_ANY; 
    oAddress.sin_port = htons(SERVER_PORT); 

    if (nMainSocketId == 0) { 
     fprintf(stderr, "Error during the creation of the socket\n"); 
     return 1; 
    } 

    if (bind(nMainSocketId, (struct sockaddr *) &oAddress, sizeof(oAddress))) { 
     fprintf(stderr, "The port %d is busy\n", SERVER_PORT); 
     close(nMainSocketId); 
     return 1; 
    } 

    printf("HTTP server listening on port %d\n", SERVER_PORT); 

    while (1) { 

     if (listen(nMainSocketId, 10) < 0) { 
      perror("server: listen"); 
      close(nMainSocketId); 
      exit(1); 
     } 

     nReqSocketId = accept(nMainSocketId, (struct sockaddr *) &oAddress, &nAddrLen); 

     if (nReqSocketId < 0) { 
      perror("server: accept"); 
      close(nMainSocketId); 
      exit(1); 
     } 

     recv(nReqSocketId, sRequest, nReqSize, 0); 

     if (nReqSocketId > 0){ 
      printf("The Client is connected...\n\n%s\n", sRequest); 
     } 

     write(nReqSocketId, "HTTP/1.1 200 OK\n", 16); 
     write(nReqSocketId, "Content-length: 50\n", 19); 
     write(nReqSocketId, "Content-Type: text/html\n\n", 25); 
     write(nReqSocketId, "<html><body><h1>Hello world!!!</h1></body></html>\n", 50); 
     close(nReqSocketId); 

    } 

    printf("Goodbye!\n"); 

    close(nMainSocketId); 

    return 0; 

} 

我可以创建一个“软关闭机制”,让Web服务器打印“再见!”短语位于无限循环之后?当我键入“Q”字母,例如...

+0

想要从服务器的终端窗口或客户端请求软终止它吗? (或者两者兼而有之?)前者高度特定于操作系统,因为您无法在* n * x和Windows上以相同方式等待终端。后者就像解析HTTP请求一样简单。 – Medinoc

+0

Ctrl + C和SIGINT的处理程序。 – someuser

+0

@Medinoc我想从我的Linux服务器的终端窗口软终止它! – madmurphy

回答

0

@Medinoc,@someuser和@Elchonon的建议后,我纠正了我的代码如下方式:

#include <stdio.h> 
#include <stdlib.h> 
#include <netinet/in.h> 
#include <signal.h> 

#define SERVER_PORT 80 

int nStatus, nMainSocketId; 

void onInt() { 
    printf("You have pressed CTRL-C.\n"); 
    nStatus = 0; 
    shutdown(nMainSocketId, 2); 
} 

void onQuit() { 
    printf("You have pressed CTRL-\\.\n"); 
    nStatus = 0; 
    shutdown(nMainSocketId, 2); 
} 

int main() { 

    int nReqSocketId, nReqSize = 1024; 
    nMainSocketId = socket(AF_INET, SOCK_STREAM, 0); 
    char *sRequest = malloc(nReqSize); 
    socklen_t nAddrLen; 
    struct sockaddr_in oAddress; 

    signal(SIGINT, onInt); 
    signal(SIGQUIT, onQuit); 
    oAddress.sin_family = AF_INET; 
    oAddress.sin_addr.s_addr = INADDR_ANY; 
    oAddress.sin_port = htons(SERVER_PORT); 
    nStatus = 1; 

    printf("\n W E L C O M E!\n\nPress CTRL-C or CTRL-\\ to quit.\n"); 

    if (nMainSocketId == 0) { 
     fprintf(stderr, "Error during the creation of the socket\n"); 
     return 1; 
    } 

    if (bind(nMainSocketId, (struct sockaddr *) &oAddress, sizeof(oAddress))) { 
     fprintf(stderr, "The port %d is busy\n", SERVER_PORT); 
     close(nMainSocketId); 
     return 1; 
    } 

    printf("HTTP server listening on port %d\n", SERVER_PORT); 

    while (nStatus) { 

     if (listen(nMainSocketId, 10) < 0) { 
      perror("server: listen"); 
      close(nMainSocketId); 
      return 1; 
     } 

     nReqSocketId = accept(nMainSocketId, (struct sockaddr *) &oAddress, &nAddrLen); 

     if (nReqSocketId < 0) { 
      perror("server: accept"); 
      close(nMainSocketId); 
      return 1; 
     } 

     recv(nReqSocketId, sRequest, nReqSize, 0); 

     if (nReqSocketId > 0){ 
      printf("The Client is connected...\n\n%s\n", sRequest); 
     } 

     write(nReqSocketId, "HTTP/1.1 200 OK\n", 16); 
     write(nReqSocketId, "Content-length: 50\n", 19); 
     write(nReqSocketId, "Content-Type: text/html\n\n", 25); 
     write(nReqSocketId, "<html><body><h1>Hello world!!!</h1></body></html>\n", 50); 
     close(nReqSocketId); 

    } 

    printf("Goodbye!\n"); 

    close(nMainSocketId); 

    return 0; 

} 

过程SOF-终止,现在!!但是,不幸的是,插座没有! :(...所以我收到以下消息时,我按CTRL-C或CTRL- \以退出:

server: accept: Invalid argument 

任何建议来解决它

+0

你打算在哪个操作系统上运行这个操作系统? – alk

+0

顺便说一句:这个例子没有包括''。 – alk

+0

@alk在GNU/Linux上。 – madmurphy

0

下一个* IXish OS的信号将被唤醒达一定阻塞的系统调用,让他们回来。

他们将指示eror并设置errnoEINTR,这种机制可以用于正常关闭服务器。

请看到你的答案代码稍微调整ED /更正如下:

#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <netinet/in.h> 
#include <signal.h> 
#include <unistd.h> 
#include <errno.h> 

#define SERVER_PORT 8080 /* Using a port>1024 one does not need to run this as root. */ 

void onInt() 
{ 
    /* Do nothing. */ 
} 

void onQuit() 
{ 
    /* Do nothing. */ 
} 

int main() 
{ 
    int nMainSocketId = -1, nReqSocketId = -1; 
    size_t nReqSize = 1024; 
    char * sRequest = malloc(nReqSize); /* TODO: add error checking */ 
    socklen_t nAddrLen; 
    struct sockaddr_in oAddress = {0}; 

    signal(SIGINT, onInt); /* TODO: add error checking */ 
    signal(SIGQUIT, onQuit); /* TODO: add error checking */ 

    printf("\n W E L C O M E!\n\nPress CTRL-C or CTRL-\\ to quit.\n"); 

    oAddress.sin_family = AF_INET; 
    oAddress.sin_addr.s_addr = INADDR_ANY; 
    oAddress.sin_port = htons(SERVER_PORT); 

    nMainSocketId = socket(AF_INET, SOCK_STREAM, 0); 
    if (nMainSocketId < 0) /* 0 is a valid file/socket descriptor! */ 
    { 
    perror("server: socket() failed"); 
    return 1; 
    } 

    if (bind(nMainSocketId, (struct sockaddr *) &oAddress, sizeof(oAddress))) 
    { 
    perror("server: bind() failed"); 
    close(nMainSocketId); 
    return 1; 
    } 

    printf("HTTP server listening on port %d\n", SERVER_PORT); 

    while (1) 
    { 
    int result = 0; 

    if (listen(nMainSocketId, 10) < 0) 
    { 
     perror("server: listen() failed"); 
     close(nMainSocketId); 
     return 1; 
    } 

    result = accept(nMainSocketId, (struct sockaddr *) &oAddress, &nAddrLen); 
    if (result < 0) 
    { 
     if (EINTR == errno) 
     { 
     printf("Shutdown requested. Exiting ...\n"); 
     break; 
     } 

     perror("server: accept failed()"); 
     close(nMainSocketId); 
     return 1; 
    } 

    nReqSocketId = result; 

    result = recv(nReqSocketId, sRequest, nReqSize, 0); /* TODO: Check wether the request size was really read! */ 
    if (result < 0) 
    { 
     perror("server: recv() failed"); 
     close(nMainSocketId); 
     return 1; 
    } 
    else if (result == 0) 
    { 
     printf("The client is disconnected. Waiting for another connection ...\n"); 
     close(nReqSocketId); 
     nReqSocketId = -1; 
     continue; 
    } 

    printf("The client is connected...\n\n%s\n", sRequest); 

    /* TODO: add error checking for ALL write()s */ 
    write(nReqSocketId, "HTTP/1.1 200 OK\n", 16); 
    write(nReqSocketId, "Content-length: 50\n", 19); 
    write(nReqSocketId, "Content-Type: text/html\n\n", 25); 
    write(nReqSocketId, "<html><body><h1>Hello world!!!</h1></body></html>\n", 50); 

    close(nReqSocketId); 
    nReqSocketId = -1; 
    } 

    printf("Goodbye!\n"); 

    close(nMainSocketId); 

    return 0; 
} 

注意,还调用recv()可以阻止等待数据,然后由于SIGINT被所中断。因此,在检查accept()的结果时应使用与recv()相同的逻辑。

0

@alk

谢谢您的回答!你建议我一个软终止我的网络服务器的替代方法...:

#include <stdio.h> 
#include <stdlib.h> 
#include <netinet/in.h> 
#include <signal.h> 

#define SERVER_PORT 80 

int bExiting, nMainSocketId; 

void terminateServer() { 
    if (bExiting) { return; } 
    printf("\n\nTerminating server...\n"); 
    close(nMainSocketId); 
    bExiting = 1; 
} 

int main() { 

    int nRecvResult = -1, nReqSocketId = -1; 
    size_t nReqSize = 1024; 
    char * sRequest = malloc(nReqSize); 
    socklen_t nAddrLen; 
    struct sockaddr_in oAddress = {0}; 

    printf("\n W E L C O M E!\n\nPress CTRL-C or CTRL-\\ to quit.\n"); 

    signal(SIGINT, terminateServer); 
    signal(SIGQUIT, terminateServer); 

    oAddress.sin_family = AF_INET; 
    oAddress.sin_addr.s_addr = INADDR_ANY; 
    oAddress.sin_port = htons(SERVER_PORT); 

    nMainSocketId = socket(AF_INET, SOCK_STREAM, 0); 

    if (nMainSocketId < 0) { 
     perror("server: socket() failed"); 
     return 1; 
    } 

    if (bind(nMainSocketId, (struct sockaddr *) &oAddress, sizeof(oAddress))) { 
     perror("server: bind() failed"); 
     terminateServer(); 
     return 1; 
    } 

    printf("HTTP server listening on port %d\n", SERVER_PORT); 

    while (bExiting == 0) { 

     if (listen(nMainSocketId, 10) < 0) { 
      perror("server: listen() failed"); 
      terminateServer(); 
      return 1; 
     } 

     nReqSocketId = accept(nMainSocketId, (struct sockaddr *) &oAddress, &nAddrLen); 

     if (bExiting) { break; } 

     if (nReqSocketId < 0) { 
      perror("server: accept failed()"); 
      terminateServer(); 
      return 1; 
     } 

     nRecvResult = recv(nReqSocketId, sRequest, nReqSize, 0); 

     if (nRecvResult < 0) { 
      perror("server: recv() failed"); 
      terminateServer(); 
      return 1; 
     } 

     if (nRecvResult == 0) { 
      printf("The client is disconnected. Waiting for another connection...\n"); 
      close(nReqSocketId); 
      continue; 
     } 

     printf("The client is connected...\n\n%s\n", sRequest); 

     /* This is only a simple "Hello world"... */ 
     write(nReqSocketId, "HTTP/1.1 200 OK\n", 16); 
     write(nReqSocketId, "Content-length: 50\n", 19); 
     write(nReqSocketId, "Content-Type: text/html\n\n", 25); 
     write(nReqSocketId, "<html><body><h1>Hello world!!!</h1></body></html>\n", 50); 

     close(nReqSocketId); 

    } 

    free(sRequest); 
    printf("Goodbye!\n"); 

    return 0; 

} 

你怎么看待它?我应该添加什么?

不过,我还有一个问题。我可以使用fprintf()和文件描述符一起作为write()的替代方法吗?如何?

1

为什么不消除所有这些写功能,只使用一个send()?

所有你需要做的是存储在缓冲区中的响应,则发送缓冲区:

// Global 
#define MAX 2048 
char response[MAX]; // No need for char* 

// In Main 
memset(response, 0, MAX); // **EDIT** 
strcpy(response, "HTTP/1.1 200 OK\n"); 
strcat(response, "Content-length: 50\n"); 
strcat(response, "Content-Type: text/html\n\n"); 
strcat(response, "<html><body><h1>Hello world!!!</h1></body></html>\n"); 

// Now simply send the whole response in one go: 
send(nReqSocketId, response, strlen(response), 0); 

此外,你也可以简单地使这是一个非持久连接,像这样:

// Global 
#define MAX 2048 
char response[MAX]; // No need for char* 

// In Main 
memset(response, 0, MAX); // **EDIT** 
strcpy(response, "HTTP/1.1 200 OK\n"); 
strcat(response, "Content-Type: text/html\n\n"); 
strcat(response, "<html><body><h1>Hello world!!!</h1></body></html>\n"); 

// Now simply send the whole response in one go again: 
send(nReqSocketId, response, strlen(response), 0); 

// Shutdown the socket so it cannot write anymore: 
shutdown(nReqSocketId,1); 

// Then totally close it when you are ready: 
close(nReqSocketId); 

后者可能更适合你目前的工作;因为无论如何您都不会在网络服务器中保持多个连接。

一旦关闭了服务器端的连接,客户端(即Web浏览器)知道停止期待内容,并且会正确完成工作。

希望这会有所帮助。

干杯!

PS-

这,当然,在这个线程没有那么多的软终端部分,以你的最后一个问题的回应。

我也不得不建议你memset(响应,0,MAX),这样你每次都有一个很好的干净的石板响应。

0

@PandaSobao

我删除的write()使用与文件描述符一起fprintf中(),我认为这是最好的方法,因为不需要的strlen()...看看下面的代码:

#include <stdio.h> 
#include <netinet/in.h> 
#include <signal.h> 

#define REQUEST_SIZE 1024 
#define SERVER_PORT 80 

int bExiting, nMainSocketId; 

void terminateServer() { 
    if (bExiting) { return; } 
    printf("\n\nTerminating server...\n"); 
    close(nMainSocketId); 
    bExiting = 1; 
} 

int main() { 

    int nRecvResult = -1, nReqSocketId = -1; 
    char sRequest[REQUEST_SIZE]; 
    socklen_t nAddrLen; 
    struct sockaddr_in oAddress; 
    FILE *nRespFD; 

    printf("\n W E L C O M E!\n\nPress CTRL-C or CTRL-\\ to quit.\n"); 

    signal(SIGINT, terminateServer); 
    signal(SIGQUIT, terminateServer); 

    oAddress.sin_family = AF_INET; 
    oAddress.sin_addr.s_addr = INADDR_ANY; 
    oAddress.sin_port = htons(SERVER_PORT); 

    nMainSocketId = socket(AF_INET, SOCK_STREAM, 0); 

    if (nMainSocketId < 0) { 
     perror("server: socket() failed"); 
     return 1; 
    } 

    if (bind(nMainSocketId, (struct sockaddr *) &oAddress, sizeof(oAddress))) { 
     perror("server: bind() failed"); 
     terminateServer(); 
     return 1; 
    } 

    printf("HTTP server listening on port %d\n", SERVER_PORT); 

    while (bExiting == 0) { 

     if (listen(nMainSocketId, 10) < 0) { 
      perror("server: listen() failed"); 
      terminateServer(); 
      return 1; 
     } 

     nReqSocketId = accept(nMainSocketId, (struct sockaddr *) &oAddress, &nAddrLen); 

     if (bExiting) { break; } 

     if (nReqSocketId < 0) { 
      perror("server: accept() failed"); 
      terminateServer(); 
      return 1; 
     } 

     nRecvResult = recv(nReqSocketId, sRequest, REQUEST_SIZE, 0); 

     if (nRecvResult < 0) { 
      perror("server: recv() failed"); 
      terminateServer(); 
      return 1; 
     } 

     if (nRecvResult == 0) { 
      printf("The client is disconnected. Waiting for another connection...\n"); 
      close(nReqSocketId); 
      continue; 
     } 

     printf("The client is connected...\n\n%s\n", sRequest); 

     nRespFD = fdopen(nReqSocketId, "a+"); 

     fprintf(nRespFD, "HTTP/1.1 200 OK\n"); 
     fprintf(nRespFD, "Content-length: 50\n"); 
     fprintf(nRespFD, "Content-Type: text/html\n\n"); 
     fprintf(nRespFD, "<html><body><h1>Hello world!!!</h1></body></html>\n"); 

     fclose(nRespFD); 

     close(nReqSocketId); 

    } 

    printf("Goodbye!\n"); 

    return 0; 

} 

关于shutdown()与close(),你能解释更好的区别吗?

+0

shutdown()可以阻止只发送,只接收等,但不会实际关闭套接字,所以它的描述符仍然有效。 **注意:**当我第一次发布时,我并没有想到中断,我正在考虑'select'。在* n * x上,您可以在'STDIN_FILENO'上使用它,这样您就可以同时在终端和插座上等待。有了这个,你甚至可以为你的服务器做一个全功能的命令行解释器(允许你做各种事情,比如踢用户)而不是仅仅退出! – Medinoc

+0

@Medinoc 谢谢你的解释! 关于STDIN_FILENO,在终端上同时等待,插座是我想要做的!你能发送一个最小的工作示例吗? – madmurphy

0

好的,所以我的回应的第二部分解释了如何使您的Web服务器非持久性。 Persistent-Connections在HTTP 1.1之前被称为Keep-Alive,顺便说一句。由于我发现每次发送完毕后都要关闭响应套接字,因此可能会使Web服务器“非持久性”。

这意味着您不必因shutdown()而发送“Content-Length:X”。您可以关闭套接字三种不同的方式:

"The constants SHUT_RD, SHUT_WR, SHUT_RDWR have the value 0, 1, 2, respectively..." 

这样做停机(SOCKET,1)我们基本上是发送一个FIN ACK给客户端(浏览器),让它知道插座写完。因此,不需要设置“Content-Length:X”标题响应。

现在,这不是一个shutdown()VS close()的东西。它是一个shutdown()和close()的东西。您仍然必须关闭()套接字才能销毁套接字。关机不适合你。

总之,如果你不需要跟踪多个连接,考虑从头中取出“Content-Length:”。只需使用shutdown(SOCKET,1)作为“传输结束”机制,然后再关闭以摧毁套接字。

/--------------------------------------------- -------------------------------------------------- -----------------------------------/

至于创建一个完整的文件*只是为了发送字符串文字,我不确定是否值得。你有没有做到这一点,并得到一些结果?无论如何,如果你正在寻找性能,strcat()[其中包括strlen()和strlen())的其他方法我都知道。我不知道是这样。

PS- strcat()在开始时速度非常快,只有在连接大缓冲区时才开始增加其复杂性。查找SIMD,以及这些类型的功能如何根据您的架构进行优化。

+0

感谢您关于shutdown()的解释。关于fprintf()+ FILE * ...我不知道它是否比send()+ strlen()更快:我只看到fprintf()+ FILE *经常用在一些教学网络服务器的例子中。 – madmurphy

0

等待两个标准输入和插座

这是一个特定的POSIX行为,明确不能在Windows上工作。它依赖于在* n * x平台上的套接字是文件描述符,并且它使用select函数。

这是一个简化的函数,它包装了select以在一个套接字上等待。

/*Waits on a single socket and stdin.*/ 
int waitOnStdinAndSocket(
int sockFd,    /*[in] Socket descriptor*/ 
int *pInputOnStdin,  /*[out] Set to a nonzero value if there is input on stdin*/ 
int *pInputOnSocket, /*[out] Set to a nonzero value if there is input on the socket*/ 
sturct timeval *timeout /*[in/opt] Timeout*/ 
) /*Returns a negative value on failure.*/ 
{ 
    int ret; 
    fd_set fds; 

    *pInputOnStdin = 0; 
    *pInputOnSocket = 0; 

    FD_ZERO(&fds); 
    FD_SET(STDIN_FILENO, &fds); 
    FD_SET(sockFd, &fds); 
    ret = select(sockFd+1, &fds, NULL, NULL, timeout); 
    if(ret >= 0) 
    { 
     *pInputOnStdin = FD_ISSET(STDIN_FILENO, &fds); 
     *pInputOnSocket = FD_ISSET(sockFd, &fds); 
    } 
    return ret; 
} 
0

@Medinoc

非常感谢您!

阅读你的回复后,我尝试了一下'在网上,发现这个GNU页面:http://www.gnu.org/software/libc/manual/html_node/Server-Example.html

所以,经过一番尝试后,我已经能够将所有的东西与我的“hello world”例子结合起来。这里是结果:

#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <netinet/in.h> 
#include <string.h> 

#define SERVER_PORT 80 
#define REQUEST_MAX_SIZE 1024 

char sRequest[REQUEST_MAX_SIZE]; 
int bListening = 1, nMainSocket; 

void terminateServer() { 
    if (bListening == 0) { return; } 
    printf("\n\nTerminating server...\n"); 
    close(nMainSocket); 
    bListening = 0; 
} 

void switchStdin() { 
    if (strcmp(sRequest, "q\n") == 0) { 
     terminateServer(); 
    } else { 
     printf("Unknown request %s\n", sRequest); 
    } 
} 

void helloWorld (const int nRequestId) { 
    printf("The client is connected...\n\n%s\n", sRequest); 
     write(nRequestId, "HTTP/1.1 200 OK\n", 16); 
     write(nRequestId, "Content-length: 50\n", 19); 
     write(nRequestId, "Content-Type: text/html\n\n", 25); 
     write(nRequestId, "<html><body><h1>Hello world!!!</h1></body></html>\n", 50); 
} 

int main (void) { 

    int nOldReqSock, nNewReqSock, nReqLen, nUninitLen = REQUEST_MAX_SIZE; 
    fd_set oActiveFD, oReadFD; 
    socklen_t nAddrLen; 
    struct sockaddr_in oAddress; 

    oAddress.sin_family = AF_INET; 
    oAddress.sin_addr.s_addr = INADDR_ANY; 
    oAddress.sin_port = htons(SERVER_PORT); 

    /* Create the socket and set it up to accept connections. */ 

    nMainSocket = socket(AF_INET, SOCK_STREAM, 0); 

    if (nMainSocket < 0) { 
     perror("socket"); 
     return 1; 
    } 

    if (bind(nMainSocket, (struct sockaddr *) &oAddress, sizeof(oAddress))) { 
     perror("bind"); 
     terminateServer(); 
     return 1; 
    } 

    if (listen(nMainSocket, 10) < 0) { 
     perror("listen"); 
     terminateServer(); 
     return 1; 
    } 

    /* Initialize the set of active sockets plus STDIN. */ 

    FD_ZERO(&oActiveFD); 
    FD_SET(STDIN_FILENO, &oActiveFD); 
    FD_SET(nMainSocket, &oActiveFD); 

    printf("\n W E L C O M E!\n\nType \"q\" to quit.\n"); 

    while (bListening) { 

     /* Block until input arrives on one or more active sockets. */ 

     oReadFD = oActiveFD; 

     if (select(FD_SETSIZE, &oReadFD, NULL, NULL, NULL) < 0) { 
      perror("select"); 
      terminateServer(); 
      return EXIT_FAILURE; 
     } 

     /* Service all the sockets with input pending. */ 

     for (nOldReqSock = 0; bListening && nOldReqSock < FD_SETSIZE; ++nOldReqSock) { 

      if (FD_ISSET(nOldReqSock, &oReadFD)) { 

       if (nOldReqSock == nMainSocket) { 

        /* Connection request on original socket. */ 

        nAddrLen = sizeof(oAddress); /* why??? */ 
        nNewReqSock = accept(nMainSocket, (struct sockaddr *) &oAddress, &nAddrLen); 

        if (nNewReqSock < 0) { 
         perror("accept"); 
         terminateServer(); 
         return EXIT_FAILURE; 
        } 

        FD_SET(nNewReqSock, &oActiveFD); 

       } else { 

        /* Data arriving on an already-connected socket. */ 

        nReqLen = read(nOldReqSock, sRequest, REQUEST_MAX_SIZE); 

        if (nReqLen < 0) { 
         /* Read error. */ 
         perror("read"); 
         terminateServer(); 
         return EXIT_FAILURE; 
        } else if (nReqLen == 0) { 
         /* End-of-file. */ 
         printf("End-of-file\n"); 
         close(nOldReqSock); /* why??? */ 
         FD_CLR(nOldReqSock, &oActiveFD); /* why??? */ 
         continue; 
        } else { 
         /* Data read. */ 
         if (nUninitLen > nReqLen) { memset(sRequest + nReqLen, 0, nUninitLen - nReqLen); } 
         nUninitLen = nReqLen; 
        } 

        if (nOldReqSock == STDIN_FILENO) { 
         /* Standard input received */ 
         switchStdin(nReqLen); 
        } else { 
         /* TCP/IP request received */ 
         helloWorld(nOldReqSock); 
        } 

       } 

      } 

     } 

    } 

    printf("Goodbye\n"); 

    return 0; 

} 

我还补充说,我不明白的线附近的一些/* why??? */意见。我可以请你简单解释它们是什么?