basic_echo_server

来源:互联网 发布:vs画图软件 编辑:程序博客网 时间:2024/05/01 22:56

basic echo server

client.c

#include <sys/socket.h>#include <string.h>#include <stdlib.h>#include <errno.h>#include <sys/types.h>#include <stdio.h>#include <arpa/inet.h>//htons#include <signal.h>#define MAX_SIZE 100 void send_echo_fun(int fd) {    char buf_snd[MAX_SIZE];    char buf_rcv[MAX_SIZE];     int len;     while(1)    {        char *s = fgets(buf_snd,MAX_SIZE,stdin);//fget \n\0        if( s == NULL)            break;        int n = strlen(buf_snd)-1;        int len;        if(n>0)        {            len = write(fd,buf_snd,strlen(buf_snd)-1);            len = read(fd,buf_rcv,MAX_SIZE);             buf_rcv[len]='\0';            printf("rcv %s\n",buf_rcv);            if(len == 0)            {                printf("recv FIN from server\n");                   return ;            }        }    }}int main(){    int client_fd ;    client_fd = socket(AF_INET,SOCK_STREAM,0);    if(client_fd < 0)        perror("socket error");    struct sockaddr_in server_sock;    server_sock.sin_family = AF_INET;    server_sock.sin_port = htons(12345);    int err = inet_pton(AF_INET,"127.0.0.1",&server_sock.sin_addr);    if(err != 1)        perror("inet_pton error");    err = connect(client_fd,(struct sockaddr *)&server_sock,sizeof(server_sock));    if(err == 0)        printf("connect ok\n");    send_echo_fun(client_fd);    close(client_fd);    return 0;}

server.c

#include <stdio.h>#include <unistd.h>//fork#include <sys/types.h>#include <sys/socket.h>#include <errno.h>//peeor#include <stdlib.h>//exit()#include <arpa/inet.h>//inet_pton#include <sys/wait.h>//waitpid#define MAX_SIZE 100/*当fork时,必须捕获SIGCHLD信号 * 捕获信号,必须处理被中断的系统调用 * SIGCHLD信号处理函数必须正确编写,不能留下僵尸进程 */void client_handle(int fd){    char buf[MAX_SIZE];    int len;    while(1)    {        len = read(fd,buf,MAX_SIZE);//read会把\n放在末尾        buf[len]='\0';        printf("recv %s\n",buf);        if(len > 0)            write(fd,buf,len);        else if (len < 0 && errno == EINTR)            continue;        else if (len == 0) //对于tcp len == 0即读到FIN        {            printf("recv FIN from client\n");            return ;        }        else perror("read error");    }}void child_handle(int sigo){    int status;    while(1)    {        pid_t pid = waitpid(-1,&status,WNOHANG);//-1表示等待第一个终止的进程,WNOHANG代表在没有已终止子进程时不阻塞        if(pid > 0)            printf("child %d terminal\n",pid);        else return;    }}int main(){    int listen_fd = socket(AF_INET,SOCK_STREAM,0);    if(listen_fd < 0)        perror("listen error");    struct sockaddr_in listen_sock;    bzero(&listen_sock,sizeof(listen_sock));    listen_sock.sin_family = AF_INET;    listen_sock.sin_port = htons(12345);    int err = inet_pton(AF_INET,"127.0.0.1",(char *)&listen_sock.sin_addr);    if(err < 0)        perror("inet_pton error");    err = bind(listen_fd,(struct sockaddr *)&listen_sock,sizeof(listen_sock));      if(err < 0)        perror("bind error");    err = listen(listen_fd,5);//note 5    if(err < 0)        perror("listen error");    signal(SIGCHLD,child_handle);    while(1)    {        struct sockaddr_in client_addr;        int client_addr_len;        int client_fd = accept(listen_fd,(struct sockaddr *)&client_addr,&client_addr_len);        if(errno == EINTR)//accept 可能被SIGCHLD信号中断            continue;        pid_t pid = fork();        if(pid > 0)        {            close(client_fd);//note the difference between close() and shutdown()        }        else        {            close(listen_fd);            client_handle(client_fd);            exit(1);        }    }    return 0;}

建立一个信号处理函数并在其中调用wait并不足以防止出现僵死进程。本问题在于,若信号都在处理函数之前产生,那么信号处理函数只
执行一次,因为unix的信号一般是不排队的。
正确的解决办法是调用waitpid,在一个循环中调用waitpid,以获取所有已终止子进程的状态

0 0
原创粉丝点击