UNIX网络编程学习记录2-第一章
标题遵循原书标题
1.2、获取时间的客户端程序
#include "unp.h" /*原书自己写的头文件,该头文件包含了网络编程需要的大部分系统头文件,还定义了一些常量如MAXLINE */
int main(int argc, char** argv){ /* argc表示入参个数,argv接收入参*/
/* 变量定义 */
int sockfd, n;
char recvline(MAXLINE + 1);
struct sockaddr_in servaddr;
if (argc != 2) {
err_quit("uage: a.out <IPaddress>");
}
/*
socket函数创建一个AF_INET(IPv4)的字节流套接字
该函数返回一个整形数值,该返回值被赋给了sockfd变量
*/
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
err_sys("socket error");
}
/* 清空结构体servaddr */
bzero(&servaddr, sizeof(servaddr));
/*
设置该套接字的地址族是IPv4
端口号:13是时间服务器众所周知的端口
套接字结构体中的ip和端口必须是特定格式,所以13要用库函数hton转换
*/
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(13);
/*
库函数onet_pton用来把点分十进制的ipv4地址转换为二进制
第一个参数是地址族
第二个参数是点分十进制ip地址
第三个参数是存储转换结果的地址
*/
if (inet_pton(AF_INET, argv[1], &servaddr.sin_addr) <= 0) {
err_quit("inet_pton error for %S", argv[1]);
}
/*
库函数connet用于与服务器段建立连接,
第一个参数是客户端套接字
第二个参数是指定服务器地址的结构体指针
第三个参数是地址结构体的长度
*/
if (connect(sockfd, (SA *)&servaddr, sizeof(servaddr)) < 0) {
err_sys("connect error");
}
/*
read函数循环读取服务器返回的结果
用标准IO函数fputs输出结果
*/
while ((n = read(sockfd, recvline, MAXLINE)) > 0) {
recvline[n] = 0;
if (fputs(recvline, stdout) == EOF) {
err_sys("fputs error");
}
}
if (n < 0) {
err_sys("read error");
}
/*
结束程序
*/
exit(0);
}
1.4、包裹函数
简单说,包裹函数就包含了库函数的异常和错误处理逻辑,一般地,包裹函数的命名是库函数首字母大写。
以socket函数为例:
sockfd = socket(AF_INET, SOCK_STREAM, 0);
他的包裹函数:
int Socket(int family, int type, int protocol) {
int n;
if ((n = socket(family, type, protocol)) < 0) {
sys_error("socket error");
}
return n;
}
1.5、获取时间的服务端程序
#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 = hton(13);
Bind(listenfd, (SA*)&servaddr, sizeof(servaddr));
Listen(listenfd, LISTENQ);
for(; ;) {
connfd = Accept(listenfd, (SA*)NULL, NULL);
ticks = time(NULL);
snprint(buff, sizeof(buff), "%.24s\r\n", ctime(&ticks));
Write(connfd, buff, strlen(buff));
Close(connfd);
}
}
注:服务器端代码不过多注释,建议编码时用snprint代替sprintf,因为前者可以检查缓存区是否溢出。此外还有用fgets、strncat、ctrncpy 代替gets、strcat、strcpy