参考 《Unix 网络编程》
github 地址
- unp.h
#include <stdio.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <string.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/wait.h>#define MAXLINE 4096
#define SERV_PORT 9877
#define LISTENQ 1024void str_echo(int sockfd);
void err_sys(const char *, ...);// client interface
void str_cli(FILE *fp, int sockfd);
- echo_service.c
#include "unp.h"void sig_chld(int signo) {pid_t pid;int stat;// 通过stat指针返回子进程终止状态// 正常终止、信号杀死、作业控制停止// pid = wait(&stat);// 防止同一信号多次提交导致子进程僵死while((pid = waitpid(-1, &stat, WNOHANG)) > 0) {// do nothing}
}int main(int argc, char **argv) {int listenfd, connfd;pid_t childpid;socklen_t clilen;struct sockaddr_in cliaddr, servaddr;listenfd = socket(AF_INET, SOCK_STREAM, 0);bzero(&servaddr, sizeof(servaddr));servaddr.sin_family = AF_INET;servaddr.sin_addr.s_addr = htonl(INADDR_ANY);servaddr.sin_port = htons(SERV_PORT);bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr));listen(listenfd, LISTENQ);signal(SIGCHLD, sig_chld);for(;;) {clilen = sizeof(cliaddr);connfd = accept(listenfd, (struct sockaddr*)&cliaddr, &clilen);if ((childpid = fork()) == 0) {close(listenfd);str_echo(connfd);exit(0);}close(connfd);}
}
- str_echo.c
#include "unp.h"void str_echo(int sockfd) {ssize_t n;char buf[MAXLINE];while( (n = read(sockfd, buf, MAXLINE)) > 0) {write(sockfd, buf, n);}
}/*
void str_echo(int sockfd) {long arg1, arg2;ssize_t n;char line[MAXLINE];for(;;) {if ( (n = read(sockfd, line, MAXLINE)) == 0) {return;}if (sscanf(line, "%ld%ld", &arg1, &arg2) == 2) {snprintf(line, sizeof(line), "%ld\n", arg1, arg2);}else {snprintf(line, sizeof(line), "input error\n");}n = strlen(line);write(sockfd, line, n);}
}
*/
- error.c
#include "unp.h"#include <stdarg.h> /* ANSI C header file */
#include <syslog.h> /* for syslog() */int daemon_proc; /* set nonzero by daemon_init() */static void err_doit(int, int, const char *, va_list);void
err_sys(const char *fmt, ...)
{va_list ap;va_start(ap, fmt);err_doit(1, LOG_ERR, fmt, ap);va_end(ap);exit(1);
}static void
err_doit(int errnoflag, int level, const char *fmt, va_list ap)
{int errno_save, n;char buf[MAXLINE + 1];errno_save = errno; /* value caller might want printed */
#ifdef HAVE_VSNPRINTFvsnprintf(buf, MAXLINE, fmt, ap); /* safe */
#elsevsprintf(buf, fmt, ap); /* not safe */
#endifn = strlen(buf);if (errnoflag)snprintf(buf + n, MAXLINE - n, ": %s", strerror(errno_save));strcat(buf, "\n");if (daemon_proc) {syslog(level, buf);} else {fflush(stdout); /* in case stdout and stderr are the same */fputs(buf, stderr);fflush(stderr);}return;
}
- echo_client.c
#include "unp.h"
#include <stdio.h>
#include <unistd.h>
#include <arpa/inet.h>int main(int argc, char **argv) {int sockfd[5];struct sockaddr_in servaddr;int i=0;for (i=0; i<5; i++) {sockfd[i] = socket(AF_INET, SOCK_STREAM, 0);bzero(&servaddr, sizeof(servaddr));servaddr.sin_family = AF_INET;servaddr.sin_port = htons(SERV_PORT);inet_pton(AF_INET, "127.0.0.1", &servaddr.sin_addr);connect(sockfd[i], (struct sockaddr*)&servaddr, sizeof(servaddr));}str_cli(stdin, sockfd[0]);exit(0);
}
- str_cli.c
#include "unp.h"// maxline 4096void str_cli(FILE *fp, int sockfd) {char sendline[MAXLINE], receline[MAXLINE];int n;while(fgets(sendline, MAXLINE, fp) != EOF) {write(sockfd, sendline, n);bzero(sendline, strlen(sendline));if (read(sockfd, receline, MAXLINE) == 0) {printf("str cli: server terminated prematurely");}fputs(receline, stdout);}
}
- CMakeList.txt
project(echo_srv)
set(CMAKE_CXX_STANDARD 11)
add_executable(echo_srv echo_service.c str_echo.c error.c)# client
add_executable(echo_cli echo_client.c str_cli.c)