2013-02-16 146 views
2

这是用于教学目的的基本TCP服务器实现。是否有任何错误或改进措施。任何建议,欢迎!简单TCP服务器

我只有一个疑问:

signal(SIGCHLD, SIG_IGN); 

是该呼叫用于防止zoombie,子进程?

#include <netinet/in.h> 
#include <sys/socket.h> 
#include <netdb.h> 

#include <sys/signal.h> 

#include <unistd.h> 
#include <stdlib.h> 
#include <stdio.h> 
#include <string.h> 

#define BACKLOG 5 
#define MAXSIZE 1024 //max-bytes for read-buffer 

void main(){ 

int sock_ds, ret, length; 
int acc_ds; //Accept socket descriptor 

struct sockaddr_in addr; //this addres 
struct sockaddr rem_addr; //remote address (generic) 

char buff[MAXSIZE]; 

sock_ds = socket(AF_INET, SOCK_STREAM, 0); // => TCP 

bzero((char *)&addr, sizeof(addr)); //reset struct 
addr.sin_family = AF_INET; 
addr.sin_port = htons(25000); 
addr.sin_addr.s_addr = INADDR_ANY; 
ret = bind(sock_ds, &addr, sizeof(addr)); 
if(ret == -1){ 
    perror("Binding error"); 
    exit(1); 
} 

ret = listen(sock_ds, BACKLOG); // backlog queue 
    if(ret == -1){ 
    perror("Listen error"); 
    exit(1); 
} 

length = sizeof(rem_addr); 
signal(SIGCHLD, SIG_IGN); //zombie children management 

/*Busy-waiting (server) and concurrency */ 
while(1){ 

    /*Repeat until success*/ 
    while(acc_ds = accept(sock_ds, &rem_addr, &length) == -1){ 

     if(fork() == 0){ //child-process 

      close(sock_ds); //unused from child 
      do{ 
       read(acc_ds, buff, MAXSIZE); 
       printf("Message from remote host:&s\n", buff); 

      }while(strcmp(buff, "quit") == 0); 
      /*Transimission completed: server response */ 
      write(acc_ds, "Reading Done", 10); 
      close(acc_ds); //socket closed 
      exit(0); //exiting from child 
     } 
     else{ 
      close(acc_ds); //unused from parent 
     } 
    } 
} 

}

+0

是的,这个想法是正确的,但你应该使用'sigaction'来代替。它实现相同的目的,但是处理信号的现代方式。 http://linux.die.net/man/2/sigaction – shanet 2013-02-16 22:55:28

回答

2

是的,这正是忽略SIGCHLD是。来自TLPI:

There is a further possibility for dealing with dead child processes. Explicitly setting the disposition of SIGCHLD to SIG_IGN causes any child process that subsequently terminates to be immediately removed from the system instead of being converted into a zombie.

它是跨Unix实现的标准。

3
  1. 返回类型main不是int。它应该是。返回EXIT_SUCCESSEXIT_FAILURE
  2. socket()调用结果未被选中。应该是,或者bind将会失败,但perror()会告诉“无效参数”而不是实际的错误。
  3. 未检查返回值read()打印时可能触发未定义的行为。
  4. 指定格式没有&s,应该是%s
  5. %s需要以空字符结尾的字符串。这不能由代码保证(见第3点)。 strcmp()也可能是垃圾。

至于SIGCHLD @cnicutar已经好心地回答说,已经没有什么要补充的。

希望它有帮助。祝你好运!

+2

嘿,很好的工作捕捉所有这些。 – cnicutar 2013-02-16 23:04:59

0

我需要了解它是如何工作的。所以,我搜索了“简单的tcp-server”,找到了这个小程序,并且修复了代码以使gcc -Wall和注释更加快乐。这里是我放在一起的:

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <errno.h> 
#include <unistd.h> 

#include <signal.h> 

#include <netinet/in.h> 
#include <sys/socket.h> 
#include <netdb.h> 

#include <sys/wait.h> 
#include <sys/types.h> 
#include <sys/ptrace.h> 


#define BACKLOG 5 
#define MAXSIZE 1024 //max-bytes for read-buffer 

#define PORT 25000 

/****************************************************************/ 
int main() { 

    int sock_ds, ret; unsigned int length; 
    int acc_ds; //Accept socket descriptor 

    struct sockaddr_in addr; //this address 
    struct sockaddr rem_addr; //remote address (generic) 

    char buff[MAXSIZE+1]; 

    if (!(sock_ds = socket(AF_INET, SOCK_STREAM, 0))) perror("socket call failed"); // => TCP 

    bzero((char *)&addr, sizeof(addr)); //reset struct 
    addr.sin_family = AF_INET; 
    addr.sin_port = htons(PORT); 
    addr.sin_addr.s_addr = INADDR_ANY; 
    ret = bind(sock_ds, (struct sockaddr *)&addr, sizeof(addr)); 
    if (ret == -1) { 
    perror("Binding error"); 
    exit(EXIT_FAILURE); 
    } 

    ret = listen(sock_ds, BACKLOG); // backlog queue 
    if (ret == (-1)) { 
    perror("Listen error"); 
    exit(EXIT_FAILURE); 
    } 

    length = sizeof (rem_addr); 
    // sigaction(SIGCHLD, SA_NOCLDWAIT); //zombie children management 

    /*Busy-waiting (server) and concurrency */ 
    while (1) { 
    fprintf(stderr, "[Waiting for client %d]\n", getpid()); 

    /*Repeat until success*/ 
    while ((acc_ds = accept(sock_ds, &rem_addr, &length)) == -1) { 
     fprintf(stderr, "[Accepted from client %d]\n", getpid()); 

     if (fork() == 0) { //child-process 
     close(sock_ds); //unused from child 
     fprintf(stderr, "[Reading from client %d]\n", getpid()); 
     while (read(acc_ds, buff, MAXSIZE)) { 
      buff[MAXSIZE]='\0'; 
      printf("Message from remote host:%s\n", buff); 
      fflush(stdout); 
      if (strncmp (buff, "quit", 5) == 0) break; 
     } 

     /*Transmission completed: server response */ 

     if (write(acc_ds, "Reading Done", 10)) fprintf(stderr, "failed write\n"); 
     close(acc_ds); //socket closed 
     exit(EXIT_SUCCESS); //exiting from child 
     } 
     else{ 
     close(acc_ds); //unused from parent 
     } 
    } 
    } 
    return EXIT_SUCCESS; 
} 

两个问题。第一是GNU Linux的海湾合作委员会拒绝接受

sigaction(SIGCHLD, SA_NOCLDWAIT); //zombie children management 

tcp-server2.c: In function ‘main’: tcp-server2.c:53:3: warning: passing argument 2 of ‘sigaction’ makes pointer from integer without a cast [enabled by default] In file included from tcp-server2.c:7:0: /usr/include/signal.h:267:12: note: expected ‘const struct sigaction * restrict’ but argument is of type ‘int’ tcp-server2.c:53:3: error: too few arguments to function ‘sigaction’ In file included from tcp-server2.c:7:0: /usr/include/signal.h:267:12: note: declared here

第二是,当我telnet到端口25000,并输入了一些东西,从来都没有如收到回应。所以服务器似乎没有工作。它永远不会被客户接受。

现在,我可以从其他地方选择一个编程示例,但我认为我应该在此处报告,因此我们在此处发布了一个最简单的tcp服务器。