日期获取客户端 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请求同时到达服务器的时候,需要等待上一个请求的处理完成,也就是迭代服务器模式。