程序执行流程:
1.创建TCP套接字
listenfd = Socket(AF_INET, SOCK_STREAM, 0)
2.清空sockaddr_in
servaddr结构体
bzero(&servaddr,
sizeof
(servaddr))
3.填写网际套接字地址结构
我们指定IP地址为INADDR_ANY
,这样要是服务器主机有多个网络接口,服务器进程就可以在任意网络接口上接受客户连接
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(13);
/* daytime server */
4.服务器的众所周知的端口号被绑定到所创建的套接字
Bind(listenfd, (SA *) &servaddr,
sizeof
(servaddr));
5.把套接字转换成一个监听套接字,这样来自客户的外来连接就可以在该套接字上由内核接受
Listen(listenfd, LISTENQ)
LISTENQ指定内核允许在这个监听描述符上排队的最大客户连接数
6.接受客户连接
connfd = Accept(listenfd, (SA *) NULL, NULL)
服务器进程在accept调用中被投入睡眠,等待某个客户连接到达并被内核接受
TCP连接采用三次握手来建立连接
握手完毕时accept返回,其返回值是一个已连接描述符的新描述符
该描述符用于与新近连接的那个客户通信
accept为每个连接到本服务器的客户返回一个新描述符
7.返回当前的时间和日期,它实际上是从1970.1.1:00:00以来的秒数
ticks =
time
(NULL)
8.输出可直观可读的时间格式
这里输出结果后面添加了\r\n
snprintf(buff,
sizeof
(buff),
"%.24s\r\n"
,
ctime
(&ticks))
9.把结果写个客户
Write(connfd, buff,
strlen
(buff))
10.终止连接
Close(connfd)
服务器调用close关闭与客户的连接
该调用引发正常的TCP连接终止序列:
每个方向上发送一个FIN,每个FIN又对各自的对端确认
#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; servaddr.sin_addr.s_addr = htonl(INADDR_ANY); servaddr.sin_port = htons(13); /* daytime server */ Bind(listenfd, (SA *) &servaddr, sizeof(servaddr)); Listen(listenfd, LISTENQ); for ( ; ; ) { connfd = Accept(listenfd, (SA *) NULL, NULL); ticks = time(NULL); snprintf(buff, sizeof(buff), "%.24s\r\n", ctime(&ticks)); Write(connfd, buff, strlen(buff)); Close(connfd); } }