参考 《Unix 网络编程》
- 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 1024
void 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_VSNPRINTF
vsnprintf(buf, MAXLINE, fmt, ap); /* safe */
#else
vsprintf(buf, fmt, ap); /* not safe */
#endif
n = 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 4096
void 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)