《UNP》第一章读后感

123 阅读1分钟

日期获取客户端 daytimetcpcli.c

#include	"unp.h"

int
main(int argc, char **argv)
{
	int					sockfd, n;
	char				recvline[MAXLINE + 1];
	struct sockaddr_in	servaddr;

	if (argc != 2)
		err_quit("usage: a.out <IPaddress>");

	// 分配一个TCP套接字描述符 之后的读写都通过它来标识 大小为小整数
	if ( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
		err_sys("socket error");

	bzero(&servaddr, sizeof(servaddr));
	servaddr.sin_family = AF_INET;
	// servaddr.sin_addr 和 servaddr.sin_port 都是特殊的格式
	// 把端口号通过 host转化为网络短整数
	servaddr.sin_port   = htons(13);	/* daytime server */
	// 把输入的第二个参数 ip地址 由字符串转换成合适的数字格式
	if (inet_pton(AF_INET, argv[1], &servaddr.sin_addr) <= 0)
		err_quit("inet_pton error for %s", argv[1]);

	// connect连接目标服务器建立一个tcp连接
	if (connect(sockfd, (SA *) &servaddr, sizeof(servaddr)) < 0)
		err_sys("connect error");

  // tcp是一个没有记录结束边界的字符流 需要自行判断数据传输是否结束了
	while ( (n = read(sockfd, recvline, MAXLINE)) > 0) {
		recvline[n] = 0;	/* null terminate */
		if (fputs(recvline, stdout) == EOF)
			err_sys("fputs error");
	}
	if (n < 0)
		err_sys("read error");

	exit(0);
}

日期获取客户端ipv6版本 daytimetcpcliv6.c

#include	"unp.h"

int
main(int argc, char **argv)
{
	int					sockfd, n;
	// diff
	struct sockaddr_in6	servaddr;
	char				recvline[MAXLINE + 1];

	if (argc != 2)
		err_quit("usage: a.out <IPaddress>");

	// diff	
	if ( (sockfd = socket(AF_INET6, SOCK_STREAM, 0)) < 0)
		err_sys("socket error");

	bzero(&servaddr, sizeof(servaddr));
	// diff
	servaddr.sin6_family = AF_INET6;
	// diff
	servaddr.sin6_port   = htons(13);	/* daytime server */
	// diff
	if (inet_pton(AF_INET6, argv[1], &servaddr.sin6_addr) <= 0)
		err_quit("inet_pton error for %s", argv[1]);

	if (connect(sockfd, (SA *) &servaddr, sizeof(servaddr)) < 0)
		err_sys("connect error");

	while ( (n = read(sockfd, recvline, MAXLINE)) > 0) {
		recvline[n] = 0;	/* null terminate */
		if (fputs(recvline, stdout) == EOF)
			err_sys("fputs error");
	}
	if (n < 0)
		err_sys("read error");

	exit(0);
}

服务器获取服务器程序 daytimetcpsrv.c

#include	"unp.h"
#include	<time.h>

int
main(int argc, char **argv)
{
	int					listenfd, connfd;
	struct sockaddr_in	servaddr;
	char				buff[MAXLINE];
	time_t				ticks;

	listenfd = Socket(AF_INET, SOCK_STREAM, 0);

	bzero(&servaddr, sizeof(servaddr));
	servaddr.sin_family      = AF_INET;
	// 多个ip地址都可以接受tcp请求连接
	servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
	servaddr.sin_port        = htons(13);	/* daytime server */

	// bind绑定设置的地址参数到这个socket描述符上面
	Bind(listenfd, (SA *) &servaddr, sizeof(servaddr));

    // 调用listen将其变成监听描述符 且有最大服务数量
	Listen(listenfd, LISTENQ);

	for ( ; ; ) {
		// 接受一个新到来的tcp连接请求 并返回一个已经建立好tcp连接的socket描述符
		connfd = Accept(listenfd, (SA *) NULL, NULL);
		
        // 如果下面的处理过程如果很耗时间 这时候有新的请求到来 将会导致下一轮的的Accept方法等待过长时间,这是迭代服务器的缺点
        ticks = time(NULL);
        snprintf(buff, sizeof(buff), "%.24s\r\n", ctime(&ticks));
        Write(connfd, buff, strlen(buff));
				
    // 写入数据后结束这次连接
		Close(connfd);
	}
}

小结:

最简单的客户端程序和服务器程序,从它们可以看出来BS模型的简介抽象模式,是学习的好材料。

多个tcp请求同时到达服务器的时候,需要等待上一个请求的处理完成,也就是迭代服务器模式。