TCP 回射程序(處理子進程的SIGCHLD信號)

客戶端的代碼;

/*************************************************************************
	> File Name: tcpcli.c
	> Author: mhsheng
	> Mail:[email protected] 
	> Created Time: Wed 09 Nov 2016 10:55:40 AM CST
 ************************************************************************/

// c standard head file
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <errno.h>

// system i/o head file
#include <unistd.h>

// socket head file
#include <netinet/in.h>

#define MAXLINE		1024
#define LISTENQ		5
#define SERV_PORT	9066	

void
err_quit(const char *str_err)
{
	fprintf(stderr, "%s\n", str_err);
	exit(-1);
}

void
err_sys(const char *str_err)
{
	fprintf(stderr, "%s\n", str_err);
	exit(-1);
}

int
Socket(int faimly, int type, int protocol)
{
	int sockfd;
	if ( (sockfd = socket(faimly, type, protocol)) < 0)
		err_sys("socket error");

	return sockfd;
}

void
Connect(int sockfd, const struct sockaddr *myaddr, socklen_t addrlen)
{
	if (connect(sockfd, myaddr, addrlen) < 0)
		err_sys("connect error");
}

void 
Bind(int sockfd, const struct sockaddr *myaddr, socklen_t addrlen)
{
	if (bind(sockfd, myaddr, addrlen) < 0)
		err_sys("bind error");
}

void 
Listen(int sockfd, int backlog)
{
	if (listen(sockfd, backlog) < 0)
		err_sys("listen error");
}

int
Accept(int sockfd, struct sockaddr *cliaddr, socklen_t *addrlen)
{
	int connfd;
	
	connfd = accept(sockfd, cliaddr, addrlen);
	if (connfd < 0)
		err_sys("accept error");

	return connfd;
}

void
Close(int sockfd)
{
	if (close(sockfd) < 0)
		err_sys("close error");
}

//////////////////////////////////////////////////////////////////////////
// Writen begin 
//

ssize_t
writen(int fd, const void *vptr, size_t n)
{
	size_t		nleft;
	ssize_t		nwritten;
	const char	*ptr;

	ptr		= vptr;
	nleft	= n;
	while (nleft > 0) {
		if ( (nwritten = write(fd, ptr, nleft)) <= 0) {
			if (nwritten < 0 && errno == EINTR)
				nwritten = 0;		/* and call write() again */
			else
				return (-1);
		}
		
		nleft	-= nwritten;
		ptr		+= nwritten;
	}

	return (n);
}

void
Writen(int fd, void *ptr, size_t nbytes)
{
	if (writen(fd, ptr, nbytes) != nbytes)
		err_sys("writen error");
}

// 
// Writen end 
//////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////
// Readline begin
//

static int	read_cnt;
static char	*read_ptr;
static char	read_buf[MAXLINE];

static	ssize_t
my_read(int fd, char *ptr)
{
	if (read_cnt <= 0) {
		for ( ; ; ) {
			if ( (read_cnt = read(fd, read_buf, sizeof(read_buf))) < 0) {
				if (errno == EINTR) 
					continue;
				return -1;
			} else if (read_cnt == 0)
				return 0;

			read_ptr = read_buf;
			break;
		}
	}

	read_cnt--;
	*ptr = *read_ptr++;
	return 1;
}

ssize_t
readline(int fd, void *vptr, size_t maxlen)
{
	ssize_t	n;
	ssize_t	rc;
	char	c;
	char	*ptr;

	ptr = vptr;
	for (n=1; n<maxlen; n++) {
		if ( (rc = my_read(fd, &c)) == 1) {
			*ptr++ = c;
			if (c == '\n')
				break;
		} else if (rc == 0) {
			*ptr = 0;		/* EOF, n - 1 bytes were read */
			return n-1;
		} else {
			return -1;
		}
	}

	*ptr = 0;
	return n;
}

ssize_t
Readline(int fd, void *ptr, size_t maxlen)
{
	ssize_t	n;

	if ( (n = readline(fd, ptr, maxlen)) < 0)
		err_sys("readline error");
	return n;
}

//
// Readline end
//////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////
// wrapstdio begin
// 

// Fgets begin
char *
Fgets(char *ptr, int n, FILE *stream)
{
	char *rptr;

	if ( (rptr = fgets(ptr, n, stream)) == NULL && ferror(stream))
		err_sys("fgets error");

	return rptr;
}
// Fgets end

// Fputs begin
void
Fputs(const char *ptr, FILE *stream)
{
	if (fputs(ptr, stream) == EOF)
		err_sys("fputs error");
}
// Fputs end

// 
// wrapstdio end
//////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////
// str_echo begin
//

void
str_echo(int sockfd)
{
	char	buf[MAXLINE];
	ssize_t	n;

	for ( ; ; ) {
		// 從套接字讀取數據
		while ( (n = read(sockfd, buf, MAXLINE)) > 0)
			// 將讀取的數據發送給客戶端
			Writen(sockfd, buf, n);

		if (n < 0 && errno == EINTR)
			continue;
		else if (n < 0)
			err_sys("str_echo: read error");
		else
			break;
	}
}

//
// str_echo end
//////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////
// str_cli begin
//

void
str_cli(FILE *fp, int sockfd)
{
	char	sendline[MAXLINE];
	char	recvline[MAXLINE];

	while (Fgets(sendline, MAXLINE, fp) != NULL) {
		Writen(sockfd, sendline, strlen(sendline));

		if (Readline(sockfd, recvline, MAXLINE) == 0)
			err_quit("str_cli: server terminated prematurely");

		Fputs(recvline, stdout);
	}
}

//
// str_cli end
//////////////////////////////////////////////////////////////////////////


int
main(int argc, char **argv)
{
	int					sockfd;
	struct sockaddr_in	servaddr;

	if (argc != 2)
		err_quit("usage: tcpcli <IPaddress>");

	// 申請一個套接字
	sockfd = Socket(AF_INET, SOCK_STREAM, 0);

	// 設置一個服務器套接字
	memset(&servaddr, 0, sizeof(servaddr));
	servaddr.sin_family	= AF_INET;
	servaddr.sin_port	= htons(SERV_PORT);
	inet_pton(AF_INET, argv[1], &servaddr.sin_addr);

	Connect(sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr));

	str_cli(stdin, sockfd);

	exit(0);
}	




服務器端的代碼:

/*************************************************************************
	> File Name: tcpserv.c
	> Author: mhsheng
	> Mail:[email protected] 
	> Created Time: Mon 14 Nov 2016 10:35:23 AM CST
 ************************************************************************/

// c standard head file
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <errno.h>
#include <signal.h>

// system i/o head file
#include <unistd.h>

// socket head file
#include <netinet/in.h>

#define MAXLINE		1024
#define LISTENQ		5
#define SERV_PORT	9066	

void
err_quit(const char *str_err)
{
	fprintf(stderr, "%s\n", str_err);
	exit(-1);
}

void
err_sys(const char *str_err)
{
	fprintf(stderr, "%s\n", str_err);
	exit(-1);
}

int
Socket(int faimly, int type, int protocol)
{
	int sockfd;
	if ( (sockfd = socket(faimly, type, protocol)) < 0)
		err_sys("socket error");

	return sockfd;
}

void
Connect(int sockfd, const struct sockaddr *myaddr, socklen_t addrlen)
{
	if (connect(sockfd, myaddr, addrlen) < 0)
		err_sys("connect error");
}

void 
Bind(int sockfd, const struct sockaddr *myaddr, socklen_t addrlen)
{
	if (bind(sockfd, myaddr, addrlen) < 0)
		err_sys("bind error");
}

void 
Listen(int sockfd, int backlog)
{
	if (listen(sockfd, backlog) < 0)
		err_sys("listen error");
}

int
Accept(int sockfd, struct sockaddr *cliaddr, socklen_t *addrlen)
{
	int connfd;
	
	for ( ; ; ) {
		if ( (connfd = accept(sockfd, cliaddr, addrlen)) < 0) {
			if (errno == EINTR)			// 信號中斷引起的錯誤
				continue;
			else
				err_sys("accept error");
		}
		break;
	}

	return connfd;
}

void
Close(int sockfd)
{
	if (close(sockfd) < 0)
		err_sys("close error");
}

//////////////////////////////////////////////////////////////////////////
// Writen begin 
//

ssize_t
writen(int fd, const void *vptr, size_t n)
{
	size_t		nleft;
	ssize_t		nwritten;
	const char	*ptr;

	ptr		= vptr;
	nleft	= n;
	while (nleft > 0) {
		if ( (nwritten = write(fd, ptr, nleft)) <= 0) {
			if (nwritten < 0 && errno == EINTR)
				nwritten = 0;		/* and call write() again */
			else
				return (-1);
		}
		
		nleft	-= nwritten;
		ptr		+= nwritten;
	}

	return (n);
}

void
Writen(int fd, void *ptr, size_t nbytes)
{
	if (writen(fd, ptr, nbytes) != nbytes)
		err_sys("writen error");
}

// 
// Writen end 
//////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////
// Readline begin
//

static int	read_cnt;
static char	*read_ptr;
static char	read_buf[MAXLINE];

static	ssize_t
my_read(int fd, char *ptr)
{
	if (read_cnt <= 0) {
		for ( ; ; ) {
			if ( (read_cnt = read(fd, read_buf, sizeof(read_buf))) < 0) {
				if (errno == EINTR) 
					continue;
				return -1;
			} else if (read_cnt == 0)
				return 0;

			read_ptr = read_buf;
			break;
		}
	}

	read_cnt--;
	*ptr = *read_ptr++;
	return 1;
}

ssize_t
readline(int fd, void *vptr, size_t maxlen)
{
	ssize_t	n;
	ssize_t	rc;
	char	c;
	char	*ptr;

	ptr = vptr;
	for (n=1; n<maxlen; n++) {
		if ( (rc = my_read(fd, &c)) == 1) {
			*ptr++ = c;
			if (c == '\n')
				break;
		} else if (rc == 0) {
			*ptr = 0;		/* EOF, n - 1 bytes were read */
			return n-1;
		} else {
			return -1;
		}
	}

	*ptr = 0;
	return n;
}

ssize_t
Readline(int fd, void *ptr, size_t maxlen)
{
	ssize_t	n;

	if ( (n = readline(fd, ptr, maxlen)) < 0)
		err_sys("readline error");
	return n;
}

//
// Readline end
//////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////
// wrapstdio begin
// 

// Fgets begin
char *
Fgets(char *ptr, int n, FILE *stream)
{
	char *rptr;

	if ( (rptr = fgets(ptr, n, stream)) == NULL && ferror(stream))
		err_sys("fgets error");

	return rptr;
}
// Fgets end

// Fputs begin
void
Fputs(const char *ptr, FILE *stream)
{
	if (fputs(ptr, stream) == EOF)
		err_sys("fputs error");
}
// Fputs end

// 
// wrapstdio end
//////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////
// str_echo begin
//

void
str_echo(int sockfd)
{
	char	buf[MAXLINE];
	ssize_t	n;

	for ( ; ; ) {
		// 從套接字讀取數據
		while ( (n = read(sockfd, buf, MAXLINE)) > 0)
			// 將讀取的數據發送給客戶端
			Writen(sockfd, buf, n);

		if (n < 0 && errno == EINTR)
			continue;
		else if (n < 0)
			err_sys("str_echo: read error");
		else
			break;
	}
}

//
// str_echo end
//////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////
// str_cli begin
//

void
str_cli(FILE *fp, int sockfd)
{
	char	sendline[MAXLINE];
	char	recvline[MAXLINE];

	while (Fgets(sendline, MAXLINE, fp) != NULL) {
		Writen(sockfd, sendline, strlen(sendline));

		if (Readline(sockfd, recvline, MAXLINE) == 0)
			err_quit("str_cli: server terminated prematurely");

		Fputs(recvline, stdout);
	}
}

//
// str_cli end
//////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////
// signal begin
//
typedef void Sigfunc(int); 

Sigfunc *
signal(int signo, Sigfunc *func)
{
	struct sigaction	act;
	struct sigaction	oact;

	act.sa_handler = func;
	sigemptyset(&act.sa_mask);
	act.sa_flags = 0;
	
	if (signo == SIGALRM) {
#ifdef SA_INTERRUPT
		act.sa_flags |= SA_INTERRUPT;
#endif
	} else {
#ifdef SA_RESTART
		act.sa_flags |= SA_RESTART;
#endif
	}


	if (sigaction(signo, &act, &oact) < 0)
		return SIG_ERR;

	return oact.sa_handler;
}

Sigfunc *
Signal(int signo, Sigfunc *func)
{
	Sigfunc *sigfunc;

	if ( (sigfunc = signal(signo, func)) == SIG_ERR) 
		err_sys("signal error");

	return sigfunc;
}

//
// signal end
//////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////
// sig_chld begin
//

void
sig_chld(int signo)
{	
	pid_t	pid;
	int		stat;

	while ( (pid = waitpid(-1, &stat, WNOHANG)) < 0)
		;

	return ;
}

//
// sig_chld end
//////////////////////////////////////////////////////////////////////////


int
main(int argc, char **argv)
{
	int					listenfd;
	int					connfd;
	pid_t				pid;
	struct sockaddr_in	servaddr;
	
	void sig_chld(int);

	// 創建一個監聽套接字描述符
	listenfd = Socket(AF_INET, SOCK_STREAM, 0);

	// 設置服務器的監聽套接字
	memset(&servaddr, 0, sizeof(servaddr));
	servaddr.sin_family			= AF_INET;
	servaddr.sin_port			= htons(SERV_PORT);
	servaddr.sin_addr.s_addr	= htonl(INADDR_ANY);
	
	// 綁定套接字到套接字描述符
	Bind(listenfd, (struct sockaddr *) & servaddr, sizeof(servaddr));

	// 啓動監聽套接字
	Listen(listenfd, LISTENQ);	

	// 處理子進程的信號 SIGCHLD 
	Signal(SIGCHLD, sig_chld);

	for ( ; ; ) {
		connfd = Accept(listenfd, (struct sockaddr *)NULL, NULL);

		if ( (pid = fork()) == 0) {
			Close(listenfd);

			str_echo(connfd);

			exit(0);
		}

		Close(connfd);
	}

	exit(0);
}	





Makefile文件:

PROGS	= tcpserv \
		  tcpcli

OBJS	= tcpserv.o \
		  tcpcli.o

All:	${PROGS}

tcpserv:	tcpserv.o
	cc -o tcpserv tcpserv.o

tcpcli:		tcpcli.o
	cc -o tcpcli tcpcli.o

clean:
	rm $(PROGS) $(OBJS)


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章