《深刻理解计算机系统》第11章网络编程linux
11.4.7主机和服务的转换程序员
include "csapp.h"编程
int main(int argc, char **argv)
{
struct addrinfo p,listp,hints;
char buf[MAXLINE];
int rc,flags;windows
if (argc != 2) { fprintf(stderr, "usage: %s <domain name or dotted-decimal>\n", argv[0]); exit(0); } memset(&hints,0,sizeof(struct addrinfo)); hints.ai_family=AF_INET; hints.ai_socktype = SOCK_STREAM; if((rc = getaddrinfo(argv[1],NULL,&hints,&listp)) != 0) { fprintf(stderr,"getaddrinfo error : %s\n",gai_strerroe(rc)); exit(1); } exit(0);
}
c语言给main函数传参。
有两种传参格式:数组
int main(int argc, char** argv)服务器
int main(int argc, char* argv[])网络
argc 是指命令行输入参数的个数,argv是一个字符数组(或者二重指针)用来存放多个字符串,每一个字符串就是一个参数。app
注意在命令行下运行命令,./a.out parameter1 parameter2,argc的值是 3,argv[0]是"./a.out",argv[1]是"parameter1",argv[2]是"parameter2"。dom
参数缺乏提示
stderr是linux里的标准输出(设备)文件,对应终端屏幕。socket
fprintf是用于文件操做。
原型:int fprintf(FILE stream,char format,[argument]);
功能:fprintf()函数根据指定的format(格式)发送信息(参数)到由stream(流)指定的文件.所以fprintf()可使得信息输出到指定的文件。
即这里将会在屏幕上提示“usage: argv[0]
同时退出程序,exit(0)是正常退出,代码一切正常的时候的退出。
C语言中的fscanf和fprint函数
stderr和stdout详细解说
学两个单词:usage <n.>惯用法,domain name域名,dotted-decimal点分十进制
memset
void memset(void s,int c,size_t n) 将已开辟内存空间 s 的首 n 个字节的值设为值 c,即给内存赋值。
memset用法详解
addrinfo结构体原型
这里使用memset是将struct addrinfo hints整个结构清0,再选择性设置一些字段。
将ai_family设置为AF_INET能够将套接字地址结构体列表所有限制为IPV4。
ai_socktype设置为SOCK_STREAM将列表限制为只有一个addrinfo结构。 若是不限制默认会返回三个addrinfo结构,即将TCP、UDP、原始数据报三种套接字都返回了,在使用时,遍历这个列表尝试每一个类型的套接字地址,直到成功链接。
调用getaddrinfo函数,host参数由用户输入,能够是域名也能够是点分十进制的数字地址。service参数为空,即不将服务名传化成地址。同时将设置了ai_family和ai_socktype字段的hints传入,用于对返回的套接字地址列表进行控制。
若是调用失败,经过错误代码打印错误消息字符串。并退出程序。
exit(1)是异常退出,在不该该出现的分枝,要求终止程序的时候就用exit(1)
设置getnameinfo的flags为NI_NUMERICHOST,不会返回域名而是数字地址字符串
遍历列表中的每个addrinfo结构体,对每一个结构体调用getnameinfo。不须要返回服务字段
freeaddrinfo释放列表。
总结:在用C语言使用windows socket时,主机和服务的转化须要程序员借助其余函数(好比pton,ntop)手动完成,而getaddrinfo和getnameinfo提供了更高级别、独立于任何特殊地址格式的抽象。这也体现了计算机领域颇有名的一句话:任何问题均可以经过加一层抽象层来解决。
11.4.8套接字接口的辅助函数
open_clientfd创建与服务器的链接,该服务器运行在主机hostname上,并在端口port上监听链接请求。
open_listenfd打开和返回一个监听描述符,准备好在端口port上接收链接请求。
值得注意的是,经过这两个辅助函数全部代码都与任何版本的IP无关。
echo客户端和服务器的示例
include "csapp.h"
int main(int argc, char **argv)
{
int clientfd;
char host, port, buf[MAXLINE];
rio_t rio;
if (argc != 3) { fprintf(stderr, "usage: %s <host> <port>\n", argv[0]); exit(0); } host = argv[1]; port = argv[2]; clientfd = Open_clientfd(host, port); Rio_readinitb(&rio, clientfd); while (Fgets(buf, MAXLINE, stdin) != NULL) { Rio_writen(clientfd, buf, strlen(buf)); Rio_readlineb(&rio, buf, MAXLINE); Fputs(buf, stdout); } Close(clientfd); exit(0);
}