★UNP一书主要注重于 应用层 和 传输层之间的部分。
★包裹函数:大写字母开头,即封装了出错判断和处理,节省了一些代码量
★unp.h安装步骤:
1.从网络上下载unpv13e.tar文件,这里用的是自己已经修改过的,可以在CentOS上运行,不需要再为一些编译错误去修改。
2.安装脚本,用于服务器如果挂了的话重装unp.h时方便点
tar -zxvf unpv13e.tar.gz
rm -y unpv13e.tar.gz
cd unpv13e
./configure
cd lib
make
cd ../libfree
make
cd ..
cp libunp.a /usr/lib
cp lib/unp.h /usr/include
cp config.h /usr/include
3.生成目标程序时,记得是
gcc daytimetcpcli.c -o cli -lunp
★时间获取例程(带注释)
客户端程序
#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("usge: a.out<IPaddress>");
}
//socket函数创建一个网际字节流套接字
//AF_INET指网际
//SOCK_STREAM指字节流
//sockfd是套接字的描述符
if ( (sockfd = socket(AF_INET,SOCK_STREAM, 0)) < 0){
err_sys("socket error");
}
//bzero清空socket的地址结构
//bzero是unp.h里定义的函数,用来替代memset
bzero(&servaddr, sizeof(servaddr));
//地址族置为AF_INET
servaddr.sin_family = AF_INET;
//设置端口号为13,是时间服务器的端口
//htons指 主机 到 网络短整数
servaddr.sin_port = htons(13);
//inet_pton 把 argv[1]所传递的IP地址,转为sin_addr的数据结构
if (inet_pton(AF_INET, argv[1], &servaddr.sin_addr) <= 0){
err_quit("inet_pton error for %s", argv[1]);
}
//SA就是struct sockaddr
//将本地的sockfd套接字,与servaddr中对应的服务器进行连接
if (connect(sockfd, (SA *)&servaddr, sizeof(servaddr)) < 0){
err_sys("connect error");
}
//读取返回的内容,并将结尾置为‘\0’
//注意TCP本身不提供字节流末尾的结束标志,即0标志。
//所以要自己置0
while ( (n = read(sockfd, recvline, MAXLINE)) > 0){
recvline[n] = 0;
fputs(recvline, stdout);
}
if (n < 0){
err_sys("read error");
}
exit(0);
}
服务器例程:
#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;
//建立一个监听套接字,并与13端口绑定Bind
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);
Bind(listenfd, (SA *) &servaddr, sizeof(servaddr));
//建立监听描述符
Listen(listenfd, LISTENQ);
while(1){
//进入睡眠,等待客户连接的到达并被内核接受
//建立连接时,进行三次握手
//accept返回已连接起来的描述符,该描述符用来与对应客户通信
connfd = Accept(listenfd, (SA *) NULL, NULL);
printf("Get a request!");
//获取自1970年以来的秒数
ticks = time(NULL);
//之所以用snprintf,而不是sprintf
//主要是因为该函数有缓冲区的检查,而sprintf没有
snprintf(buff, sizeof(buff), "%.24s\r\n",ctime(&ticks));
//发送
Write(connfd, buff, strlen(buff));
//终止连接,等待下一次的连接
Close(connfd);
}
}
★常用的一些网络命令
查看服务器的网络接口信息(有哪些接口): netstat -i
展示路由表:netstat -r
查看对应接口的详细信息:ifconfig 接口名字
查看本地网络中其他主机的IP: ping -b 广播地址 (因为防火墙限制可能会无法广播成功)