TCP回射程序

服务器端的代码如下:

/*************************************************************************
	> File Name: tcpserv.c
	> Author: mhsheng
	> Mail:981065720@qq.com 
	> Created Time: Wed 09 Nov 2016 09:59:55 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 
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 
//

//

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

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

	// 申请一个套接字描述符号
	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);

	for ( ; ; ) {
		// 得到一个连接套接字
		connfd = Accept(listenfd, NULL, NULL);

		// 启动一个新的进程
		if ( (pid = fork()) == 0) // fork函数有这个特性
		{
			Close(listenfd);  // 需要在子进程中关闭 监听套接字

			str_echo(connfd);

			Close(connfd);
			exit(0);
		}

		Close(connfd);
	}

	exit(0);
}

客户端的程序如下:

/*************************************************************************
	> File Name: tcpcli.c
	> Author: mhsheng
	> Mail:981065720@qq.com 
	> 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);
}	


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)



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值