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