TCP多进程并发服务器与多进程客户端实验

2022年版
tcp_echo_cli.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <signal.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/wait.h>

#define MAX_CMD_STR 100
#define bprintf(fp, format, ...) \
    if(fp == NULL){printf(format, ##__VA_ARGS__);}  \
    else{printf(format, ##__VA_ARGS__); \
            fprintf(fp, format, ##__VA_ARGS__);fflush(fp);}

int sig_type = 0;
FILE * fp_res = NULL;//文件指针

void sig_pipe(int signo) {
    sig_type = signo;
    return;
}
int  sig_chld_id = 0;
void sig_chld(int signo){
    int pid_chld;
    while((pid_chld = waitpid(-1, NULL, WNOHANG) > 0)){
        printf("[srv](%d) server child(%d) terminated.\n", getpid(), pid_chld);
    };
    return;
}
void sig_int(int signo){
    exit(0);
    return;
}

int echo_rqt(int sockfd, int pin, FILE *fp_res){
    FILE *file_td;
    char  file_name_td[50];
    const int pin_h = pin;
    const int pin_n = htonl(pin);
    char dat[MAX_CMD_STR];
    int len_h = 0;
    int len_n = 0;
    int len_rev_h = 0;
    int len_rev_n = 0;
    char  buf[MAX_CMD_STR + 9];
    sprintf(file_name_td, "td%d.txt", pin);
    file_td = fopen(file_name_td, "r");
    if(file_td == 0){
        fprintf(fp_res, "[cli](%d) Test data read error!\n", pin_h);
        printf("[cli](%d) Test data read error!\n", pin_h);
        exit(0);
    }
    
    char* temp;
    while((temp = fgets(buf, MAX_CMD_STR, file_td))){
        len_h = strlen(buf);
        len_n = htonl(len_h);
        if(strncmp(buf, "exit", 4) == 0){
            fclose(file_td);
            return 0;
        }
        int i = 0;                
        while(buf[i] != '\n'){     
            i++;
        }
        if(buf[i] == '\n'){
            buf[i] = '\0';
        }
        if(send(sockfd, &pin_n, 4, 0) == -1){
            printf("editor: send data error pin, errno:%d!\n", errno);
        }
        if(send(sockfd, &len_n, 4, 0) == -1){
            printf("editor: send data error len!\n");
        }
        if(send(sockfd, buf, len_h, 0) == -1){
            printf("editor: send data error buf!\n");
        }
        memset(buf, 0, MAX_CMD_STR);
        int tmp_pin_rev = 0;
        recv(sockfd, &tmp_pin_rev, 4, 0);
        if(recv(sockfd, &len_rev_n, 4, 0) == -1){
            printf("editor: some error happened! in 108 num: %d\n", pin);
            return 0;
        };
        len_rev_h = ntohl(len_rev_n);
        int count = 0;
        int tmp_len_rev = 0;
        
        count = 0;
        while(count < len_rev_h){
            if((tmp_len_rev = recv(sockfd, buf + count, len_rev_h - count, 0)) == -1){
                printf("editor: some error happened!\n");
                return 0;
            }
            if(tmp_len_rev == 0){
                printf("editor: not data\n");
                break;
            }
            count += tmp_len_rev;
        }
        fprintf(fp_res, "[echo_rep](%d) %s\n", getpid(), buf);
    }
    fclose(fp_res);
    return 0;
}
int main(int argc, char* argv[])
{
    
    if(argc != 4){
        printf("Usage:%s <IP> <PORT> <CONCURRENT AMOUNT>\n", argv[0]);
        return 0;
    }

    struct sigaction sigact_pipe,sigact_pipe_old;
    sigact_pipe.sa_handler = sig_pipe;//sig_pipe(),信号处理函数
    sigemptyset(&sigact_pipe.sa_mask);
    sigact_pipe.sa_flags = 0;
    sigact_pipe.sa_flags |= SA_RESTART;//设置受影响的慢系统调用重启
    sigaction(SIGPIPE, &sigact_pipe, &sigact_pipe_old);
    
    struct sigaction sigact_chld, sigact_chld_old;
    sigact_chld.sa_handler = sig_chld;
    sigemptyset(&sigact_pipe.sa_mask);
    sigact_pipe.sa_flags |= SA_RESTART;
    sigaction(SIGCHLD, &sigact_chld, &sigact_chld_old);


    struct sockaddr_in  srv_addr;
    struct sockaddr_in  cli_addr;
    socklen_t  cli_addr_len;
    memset(&srv_addr, 0, sizeof(srv_addr));
    srv_addr.sin_family = AF_INET;
    inet_pton(AF_INET, argv[1], &srv_addr.sin_addr);
    srv_addr.sin_port = htons(atoi(argv[2]));
    int  connfd;
    char  av3[10];
    strncpy(av3, argv[3], 5);
    int conc_amnt = atoi(av3);
    
    int i = 0;
    while (i < conc_amnt - 1) {
        if (!fork()) {
            char  file_name_cli[50];
            sprintf(file_name_cli, "stu_cli_res_%d.txt", i+1);
            
            FILE * fp_res;
            fp_res = fopen(file_name_cli, "ab"); 
            if(!fp_res){
                printf("[cli](%d) child exits, failed to open file \"stu_cli_res_%d.txt\"!\n", getpid(), i+1);
                exit(-1);
            }

            printf("[cli](%d) stu_cli_res_%d.txt is created!\n", getpid(), i+1);
            fprintf(fp_res, "[cli](%d) child process %d is created!\n", getpid(), i+1);

            int clientfd;
            if((clientfd = socket(PF_INET, SOCK_STREAM, 0)) == -1){
                printf("editor: create socket error in child process %d, exit...\n", getpid());
                exit(0);
            }
            while(1){
                int  con_res;
                
                con_res = connect(clientfd, (struct sockaddr *)(&srv_addr), sizeof(srv_addr));
                if(con_res == 0){
                    fprintf(fp_res, "[cli](%d) server[%s:%s] is connected!\n", getpid(), argv[1], argv[2]);
                    char  ip_str[50];
                    if(echo_rqt(clientfd, i+1, fp_res) == 0){
                        close(clientfd);
                        break;
                    }
                    else{
                        printf("editor: some error happened in echo_rqt, in child_process :%d\n",getpid());
                        fclose(fp_res);
                        exit(0);
                    }
                }
                else{
                    if(sig_chld_id){
                        printf("editor: int happened\n");
                    }
                    fclose(fp_res);
                    exit(0);
                }
            }
            fprintf(fp_res, "[cli](%d) connfd is closed!\n", getpid());
            fprintf(fp_res, "[cli](%d) child process is going to exit!\n", getpid());
            fprintf(fp_res, "[cli](%d) stu_cli_res_%d.txt is closed!\n", getpid(), i+1);
            printf("[cli](%d) connfd is closed!\n", getpid());
            printf("[cli](%d) child process is going to exit!\n", getpid());
            printf("[cli](%d) stu_cli_res_%d.txt is closed!\n", getpid(), i+1);
            
            fclose(fp_res);       
            exit(1);
        }
        i++;
    }

        char  file_name_cli[50];
        sprintf(file_name_cli, "stu_cli_res_%d.txt", 0);
        FILE * fp_res;
        fp_res = fopen(file_name_cli, "ab"); 
        if(!fp_res){
            printf("[cli](%d) child exits, failed to open file \"stu_cli_res_%d.txt\"!\n", getpid(), 0);
            exit(-1);
        }

        
        printf("[cli](%d) stu_cli_res_%d.txt is created!\n", getpid(), 0);
        fprintf(fp_res, "[cli](%d) parent process  is created!\n", getpid());

        int clientfd;
        if((clientfd = socket(PF_INET, SOCK_STREAM, 0)) == -1){
            printf("editor: create socket error in child process %d, exit...\n", getpid());
            exit(0);
        }
        while(1){
            int  con_res;

            con_res = connect(clientfd, (struct sockaddr *)&srv_addr, sizeof(srv_addr));
            if(con_res == 0){
                fprintf(fp_res, "[cli](%d) server[%s:%s] is connected!\n", getpid(), argv[1], argv[2]);
                char  ip_str[50];
                if(echo_rqt(clientfd, 0, fp_res) == 0){
                    close(clientfd);
                    break;
                }
                else{
                    printf("editor: some error happened in echo_rqt, in child_process :%d\n",getpid());

                }
            }
            else{
                if(sig_chld_id){
                    printf("editor: int happened\n");
                }
                fclose(fp_res);
                exit(0);
            }
        }
        fprintf(fp_res, "[cli](%d) connfd is closed!\n", getpid());
        fprintf(fp_res, "[cli](%d) child process is going to exit!\n", getpid());
        fprintf(fp_res, "[cli](%d) stu_cli_res_%d.txt is closed!\n", getpid(), 0);
        printf("[cli](%d) connfd is closed!\n", getpid());
        printf("[cli](%d) child process is going to exit!\n", getpid());
        printf("[cli](%d) stu_cli_res_%d.txt is closed!\n", getpid(), 0);
        
        fclose(fp_res);
        exit(0);
    
}


tcp_echo_srv.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <signal.h>
#include <errno.h>
#include <sys/wait.h>

#define MAX_CMD_STR 100
#define BACKLOG 1024
#define bprintf(fp, format, ...) \
    if(fp == NULL){printf(format, ##__VA_ARGS__);}  \
    else{printf(format, ##__VA_ARGS__); \
            fprintf(fp, format, ##__VA_ARGS__);fflush(fp);} 

int sig_type = 0;

void sig_int(int signo) {   
    sig_type = signo;
    printf("[srv](%d) SIGINT is coming!\n", getpid());
    return;
}
void sig_pipe(int signo) {  
    sig_type = signo;
    printf("[srv](%d) SIGPIPE is coming!\n", getpid());
}
void sig_chld(int signo){
    int stat;
    sig_type = signo;
    pid_t pid_chld;
    printf("[srv](%d) SIGCHLD is coming!\n", getpid());
    while((pid_chld = waitpid(-1, NULL, WNOHANG))> 0){
        printf("[srv](%d) server child(%d) terminated.\n", getpid(), pid_chld);
    };
}

int sig_handlers(void){
    
    struct sigaction sigact_pipe, sigact_pipe_old;
    sigact_pipe.sa_handler = sig_pipe;//sig_pipe(),信号处理函数
    sigact_pipe.sa_flags = 0;
    sigact_pipe.sa_flags |= SA_RESTART;//设置受影响的慢系统调用重启
    sigemptyset(&sigact_pipe.sa_mask);
    sigaction(SIGPIPE, &sigact_pipe, &sigact_pipe_old);
    
    struct sigaction sigact_chld, sigact_chld_old;
    sigact_chld.sa_handler = sig_chld;
    sigact_chld.sa_flags |= SA_RESTART;
    sigemptyset(&(sigact_chld.sa_mask));
    sigaction(SIGCHLD, &sigact_chld, &sigact_chld_old);

    struct sigaction sigact_int, sigact_int_old;
    sigact_int.sa_handler = sig_int;
    sigact_int.sa_flags = 0;
    sigemptyset(&(sigact_int.sa_mask));
    sigaction(SIGINT, &sigact_int, &sigact_int_old);
    return 0;
}

int echo_rep(int sockfd, FILE *fp_res)
{
    int len_h, len_n;
    int pin_h, pin_n;
    int count;
    char buf[MAX_CMD_STR];
    int flag = 0;
    while(1){
        flag = read(sockfd, &pin_n, 4);
        if(flag < 0){
            if(errno == EINTR){
                if(sig_type == SIGINT){
                    return -1;
                }
                continue;
            }
            continue;
        }
        else if(flag == 0){
            return pin_h;
        }
        if(!read(sockfd, &len_n, 4)){
            printf("editor: no data\n");
        }
        pin_h = ntohl(pin_n);
        len_h = ntohl(len_n);
        count = 0;
        int temp = 0;
        while(count < len_h){
            temp = read(sockfd, buf + count, len_h - count);
            if(!temp){
                printf("id: %d, editor: no data!!\n", getpid());
                return -1;
            }
            count += temp;
        }
        fprintf(fp_res, "[echo_rqt](%d) %s\n",getpid(), buf);
        if(send(sockfd, &pin_n, 4, 0) == -1){
            printf("editor: send data error pin, errno:%d!\n", errno);
        }
        if(send(sockfd, &len_n, 4, 0) == -1){
            printf("editor: send data error len!\n");
        }
        if(send(sockfd, buf, len_h, 0) == -1){
            printf("editor: send data error buf!\n");
        }

    }

}

int main(int argc, char* argv[])
{
    
    if(argc != 3)
    {
        printf("Usage:%s <IP> <PORT>\n", argv[0]);
        return -1;
    }
    FILE * fp_res;
    fp_res = fopen("stu_srv_res_p.txt", "wb");
    fflush(fp_res);
    if(!fp_res){
        printf("[srv](%d) failed to open file \"stu_srv_res_p.txt\"!\n", getpid());
        return 0;
    }
    else{
        printf("[srv](%d) stu_srv_res_p.txt is opened!\n", getpid());
    }
    
    sig_handlers();

    struct sockaddr_in  srv_addr, cli_addr;
    int listenfd, connfd, cli_addr_len;
    bzero(&srv_addr, sizeof(srv_addr));
    srv_addr.sin_family = AF_INET;
    inet_pton(AF_INET, argv[1], &(srv_addr.sin_addr));
    srv_addr.sin_port = htons(atoi(argv[2]));

    fprintf(fp_res, "[srv](%d) server[%s:%s] is initializing!\n",getpid(), argv[1], argv[2]);

    if((listenfd = socket(PF_INET, SOCK_STREAM, 0)) == -1){
        printf("editor: create socket error in child process %d, exit...\n", getpid());
        exit(0);
    }
    int opt = SO_REUSEADDR;
	setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));	//将地址和端口设为可立即重用

    if (bind(listenfd, (struct sockaddr *)&srv_addr, sizeof(srv_addr)) == -1)
    {
        printf("editor: bind socket error, \n");
        exit(0);
    } 
    if(listen(listenfd, BACKLOG)){
        printf("editor: listen error!\n");
    }
    int cli_addr_size;
    char cli_addr_str[32];
    short int cli_port;
    cli_addr_len = sizeof(struct sockaddr_in);
    while(1){
        if((connfd = accept(listenfd, (struct sockaddr*)(&cli_addr), &cli_addr_len)) == -1){
            if(errno == EINTR){
                if(sig_type = SIGINT){
                    break;
                }
            }
            else{
                close(connfd);//与restart作用相同
                continue;
            }
        }
        inet_ntop(AF_INET, &(cli_addr.sin_addr.s_addr), cli_addr_str, sizeof(cli_addr));
        cli_port = ntohs(cli_addr.sin_port);
        fprintf(fp_res, "[srv](%d) client[%s:%hu] is accepted!\n",getpid(), cli_addr_str, cli_port);
        
        fflush(fp_res);
        int pid = 0;
        pid = fork();
        if(pid == -1){
            printf("unexpected error!\n");
            return -1;
        }
        else if(pid == 0){
            fclose(fp_res);
            close(listenfd);
            char filename_res[50];
            char filename_res_new[60];
            sprintf(filename_res, "stu_srv_res_%d.txt", getpid());
            fp_res = fopen(filename_res, "wb");
            printf("[srv](%d) stu_srv_res_%d.txt is opened!\n", getpid(), getpid());
            fprintf(fp_res, "[cli](%d) child process is created!\n", getpid());
            int tt_val;
            tt_val = 0;
            if((tt_val = echo_rep(connfd, fp_res)) == -1){
                printf("some error may happened in echo_rep\n");
            }
            else{
                sprintf(filename_res_new, "stu_srv_res_%d.txt", tt_val);
                if(!rename(filename_res, filename_res_new)){
                    fprintf(fp_res, "[srv](%d) res file rename done!\n", getpid());
                }
                else{
                    printf("res file name error!\n");
                }
            }
            close(connfd);
            fprintf(fp_res, "[srv](%d) connfd is closed!\n", getpid());
            fprintf(fp_res, "[srv](%d) child process is going to exit!\n", getpid());
            fclose(fp_res);
            printf("[srv](%d) stu_cli_res_%d.txt is closed!\n", getpid(), getpid());
            exit(0);
        }
        close(connfd);
    }
    fprintf(fp_res, "[srv](%d) listenfd is closed!\n", getpid());
    fprintf(fp_res, "[srv](%d) parent process is going to exit!\n", getpid());
    fclose(fp_res);
    close(listenfd);
    printf("[srv](%d) stu_srv_res_p.txt is closed!\n", getpid());
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值