学习本书之前,为了了解C语言,先通读了《C程序设计语言》。但对C语言的理解、熟悉可能还是不足,所以在学习本书的过程中,遇到看不懂的C代码,还要去查询、思考。
本书一开始,我就遇到了问题,运行不了程序。不知道在 MACOS 上面应该怎么编译并使其运行。所以学习编译并运行C代码。
OK,现在我们知道如何编译并运行文件了。
第一章
练习
1.3
socket error: Address family not supported by protocol family
1.4
在 while 函数体首行中添加
++bigger_than_zero_times;
1.5
for (int i=0; i<sizeof(buff); ++i) { Write(connfd, &buff[i], strlen(&buff[i])); }
输出是这样
$ ./daytimetcpcli 127.0.0.1 Tue May 30 21:12:38 2017 ue May 30 21:12:38 2017 e May 30 21:12:38 2017 May 30 21:12:38 2017 May 30 21:12:38 2017 ay 30 21:12:38 2017 y 30 21:12:38 2017 30 21:12:38 2017 30 21:12:38 2017 0 21:12:38 2017 21:12:38 2017 21:12:38 2017 1:12:38 2017 :12:38 2017 12:38 2017 2:38 2017 :38 2017 38 2017 8 2017 2017 2017 017 17 7
还有乱码
有错误。我是想输出一个字符,而实际输出的是 i 之后的所有字符。原因是 strlen(&buff[i]) 这里写了输出的长度。这里改为 1 就正常了。
sizeof 要改成 strlen
所以答案是
for (int i=0; i<strlen(buff); ++i) { Write(connfd, &buff[i], 1); }
第二章
2.1 进入 https://www.iana.org/ 后没有找到 IPV0, IPV1的信息
参考答案:
在站内搜索 Version Numbers
Decimal | Keyword | Version | Reference |
---|---|---|---|
0-1 | Reserved | [Jon_Postel][RFC4928] | |
2-3 | Unassigned | [Jon_Postel] | |
4 | IP | Internet Protocol | [RFC791][Jon_Postel] |
5 | ST | ST Datagram Mode | [RFC1819][Jim_Forgie] |
6 | IPv6 | Internet Protocol version 6 | [RFC-ietf-6man-rfc2460bis-13] |
7 | TP/IX | TP/IX: The Next Internet | [RFC6814] |
8 | PIP | The P Internet Protocol | [RFC1621] |
9 | TUBA | TUBA | [RFC1347] |
10-14 | Unassigned | [Jon_Postel] | |
15 | Reserved | [Jon_Postel] |
2.2 直接google搜索咯。
IPv5 used IPv4's 32-bit addressing, which eventually became a problem. The format of IPv4 addresses is one you have probably encountered before, in the ###.###.###.### format. Unfortunately, IPv4 is limited in the number of addresses available, and by 2011 the last remaining blocks of IPv4 addresses were allocated. IPv5 would have suffered from the same limitation.
However, IPv6 was developed in the 1990s to solve the addressing limitation, and commercial deployment of this new internet protocol began in 2006.
So, IPv5 was abandoned before ever becoming a standard, and the world moved on to IPv6.
参考答案:通过 RFC-INDEX 查找或者 google "ipv5 rfc"
在 RFC-INDEX 中没有找到 IPV5,应该是关键字不对
2.3
发送最小的包的大小,这样所有的线路都能够支持。
MTU:最大传输单元
MSS:最大分节大小,用于向对端TCP通告对端在每个分节中能够发送的最大TCP数据量。MSS经常设置成MTU减去IP和TCP首部的固定长度
最小重组缓冲区大小:IPv4和IPv6的任何实现都必须保证支持的最小数据报大小。对于IPv4是576字节,对于IPv6是1500字节。
所以 536 = 576 - 20(IPv4首部) - 20(TCP首部)
2.4
与书上的图一样吧。但是 26 个字节的作用是什么?说明数据传输的次数?
参考答案:这里执行关闭的是服务器而不是客户
2.5
以太网的MTU是1500字节。TCP 首部 + IP 首部 = 20 + 20 = 40字节;所以不能超过1500-40=1460字节
2.6
OSPF 的协议号 -》 OSPF protocol number
进入 https://www.iana.org/, 搜索 Protocol Numbers,进入 https://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml,页面内搜索OSPF,得到
89 | OSPFIGP | OSPFIGP | [RFC1583][RFC2328][RFC5340][John_Moy] |
所以协议号是 89
2.7
累计确认点
选择性确认点
第三章
习题
3.1
由于C中函数不能改变按值传递的参数的值。而这里又需要更改参数的值,所以必须传递指针。
3.2
void 类型指针的作用
因为结果就是 char 类型,所以使用 char 类型的指针
参考答案:
void指针间接引用前需要声明类型/类型转换。
3.3
如果函数出错将返回一个负值,并将errno设置为EAFNOSUPPORT,如果参数af指定的地址族和src格式不对,函数将返回0。
意思是:更严格的函数报错了,就调用更宽松的函数。
第四章
服务器已连接套接字
已完成队列中储存的不是已连接的套接字吗?
Fork 与 并发服务器
我认为Fork 之后连接应该还是 1 个吧?只是 connfd 的引用计数加一。
但是书上画了两个连接。
习题
是大端则为主机字节序。
如何判断大端
void IsBigEndian() { short int a = 0x1122;//十六进制,一个数值占4位 char b = *(char *)&a; //通过将short(2字节)强制类型转换成char单字节,b指向a的起始字节(低字节) if( b == 0x11)//低字节存的是数据的高字节数据 { //是大端模式 } else { //是小端模式 } }
参考答案:
使用 getsockname 以及 sock_ntop 的方法。
子进程在父进程前执行完。那么子进程 close 之后,已连接套接字的引用计数减一,即 2 - 1 = 1 个。然后父进程调用 close,引用计数减一后变为 0。那么就关闭套接字,出发 TCP 的 FIN 以进行资源回收。
4.4 由于没有调用 listen,所以套接字还是主动套接字,所以不能接收到请求。客户端连接到那个端口后会发现没有应用程序在监听那个端口,会受到服务器的 RST 响应。
参考答案:
4.5 没有 bind,那么内核会随机绑定一对 IP 地址、临时端口给那个套接字。调用 listen 后,服务端正常监听,可以正常工作。但是需要查询才能获得服务端的IP 地址、端口号。