简体   繁体   English

简单的TCP服务器

[英]Simple TCP-Server

This is a basic TCP-Server implementation for teaching purposes. 这是用于教学目的的基本TCP-Server实现。 Are there any error or improvements to do. 是否有任何错误或改进措施。 Any suggest is welcome! 任何建议都欢迎!

I only have a doubt: 我只有一个疑问:

signal(SIGCHLD, SIG_IGN);

Is that call used to prevent zoombie-child processes? 该呼叫是否用于防止zoombie-child过程?

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

} }

  1. Return type of main is not int . main返回类型不是int It should be. 它应该是。 Either return EXIT_SUCCESS or EXIT_FAILURE . 返回EXIT_SUCCESSEXIT_FAILURE
  2. Result of socket() call is not checked. 没有检查socket()调用的结果。 It should be, or bind will fail but perror() will tell "Invalid argument" instead of the actual error. 应该是这样,否则bind将会失败,但perror()会告诉“无效参数”,而不是实际错误。
  3. A return value of read() is not checked possibly triggering undefined behavior when printing. 未检查read()返回值,有可能在打印时触发未定义的行为。
  4. There is no &s format specified, it should be %s . 未指定&s格式,应为%s
  5. %s expects a null-terminated string. %s需要一个以空值结尾的字符串。 This is not guaranteed by the code (see point #3). 代码不能保证这一点(请参阅第3点)。 strcmp() may crap out as well. strcmp()也可能出现故障。

As for the SIGCHLD , @cnicutar has kindly answered that already, nothing to add there. 至于SIGCHLD ,@ cnicutar已经很好地回答了,没有什么可补充的。

Hope it helps. 希望能帮助到你。 Good Luck! 祝好运!

Yes, that's exactly what ignoring SIGCHLD is for. 是的,这正是忽略SIGCHLD的目的。 From TLPI: 从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 . 将SIGCHLD的处置方式显式设置为SIG_IGN会导致随后终止的所有子进程立即从系统中删除, 而不是转换为僵尸

It is standard across Unix implementations. 它是Unix实现中的标准配置。

I need to learn how this works, too. 我也需要学习这是如何工作的。 So, I googled "simple tcp-server", found this little program, and fixed up the code to be happier with gcc -Wall and the comments. 因此,我搜索了“简单的tcp-server”,找到了这个小程序,并使用gcc -Wall和注释将代码固定为更快乐。 here is what I put together: 这是我整理的:

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

two problems. 两个问题。 the first is that gnu linux gcc refuses to accept 首先是gnu linux gcc拒绝接受

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 tcp-server2.c:在函数'main'中:tcp-server2.c:53:3:警告:传递'sigaction'的参数2使指针从整数开始而没有强制转换[默认启用]在tcp-server2包含的文件中.C:7:0:/usr/include/signal.h:267:12:注:应为'const的结构的sigaction * 限制 ',但参数的类型的'INT' TCP-server2.c:53:3:错误: tcp-server2.c:7:0:/usr/include/signal.h:267:12包含的文件中的参数'sigaction'的参数太少:注意:在这里声明

the second is that when I telnet to port 25000 and type a few things, nothing ever is echoed as received. 第二个是,当我远程登录到端口25000并键入一些内容时,接收到的内容不会回显。 so the server does not seem to work. 因此服务器似乎无法正常工作。 it never gets to accepted from client. 它永远不会被客户接受。

now, I could pick up a programming example from somewhere else, but I thought I should just report this here, so we get a simplest tcp server posted correct here. 现在,我可以从其他地方获取一个编程示例,但是我认为我应该只在此处报告此内容,因此我们在这里得到了一个最简单的tcp服务器。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM