2

这是用于教学目的的基本 TCP-Server 实现。是否有任何错误或改进。欢迎任何建议!

我只有一个疑问:

signal(SIGCHLD, SIG_IGN);

该调用是否用于防止缩放子进程?

 #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
        }
    }
}

}

4

3 回答 3

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

至于SIGCHLD,@cnicutar 已经很好地回答了这个问题,没有什么可添加的。

希望能帮助到你。祝你好运!

于 2013-02-16T23:01:00.533 回答
2

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

还有一种处理死子进程的可能性。将 SIGCHLD 的配置显式设置为 SIG_IGN 会导致任何随后终止的子进程立即从系统中删除,而不是转换为僵尸进程。

它是 Unix 实现的标准。

于 2013-02-16T22:52:27.047 回答
0

我也需要了解它是如何工作的。所以,我用谷歌搜索了“simple 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 gcc拒绝接受

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

tcp-server2.c:在函数'main'中:tcp-server2.c:53:3:警告:传递'sigaction'的参数2使指针从整数而不进行强制转换[默认启用]在tcp-server2包含的文件中.c:7:0: /usr/include/signal.h:267:12: 注意:预期的 'const struct sigaction * restrict ' 但参数的类型是 'int' tcp-server2.c:53:3: 错误: tcp-server2.c:7:0:/usr/include/signal.h:267:12:/usr/include/signal.h:267:12 中包含的文件中函数“sigaction”的参数太少:注意:在此处声明

第二个是当我远程登录到端口 25000 并键入一些内容时,没有任何内容被回显为收到。所以服务器似乎不起作用。它永远不会被客户接受。

现在,我可以从其他地方找到一个编程示例,但我认为我应该在这里报告这个,所以我们在这里得到了一个最简单的 tcp 服务器。

于 2013-10-12T03:34:51.047 回答