因为第二章之后基本都是纯Socket API的内容, 第三章到第十一章的笔记整理合并到一起。
第三章
3.4 :字节排序函数,涉及到大小端,处理网络字节序和主机字节序的转换
如何判别是大端(Big-Endian)还是小端(Little-Endian):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26union TestBigOrLittle
{
short var_short;
char array_char[2];
};
int main()
{
TestBigOrLittle unTestUnion;
unTestUnion.var_short = 0x1234;
if (sizeof(short) == 2)
{
if (unTestUnion.array_char[0] == 0x12)
printf("BigEndian\n");
else if(unTestUnion.array_char[0] == 0x34)
printf("LittleEndian\n");
else
printf("unkonw endian\n");
}
else
{
printf("sizeof(short) : %d \n", sizeof(short));
}
return 0;
}网际协议使用大端字节序来传送这些多字节整数, 也就是说网络字节序就是大端字节序.
由图中我们可以知道, htons和ntohs是用于端口的字节序转换的, 而htonl和ntohl是用于32位IP地址的, 下图就是一个例子:
3.6 : 地址转换函数,它们在ASCII字符串(这是人们偏爱使用的格式)与网络字节序的二进制值(这是存放在套接字地址结构中的值)之间转换网际地址
第四章基本TCP套接字编程
listen函数
int listen(int sockfd, int backlog);
当来自客户的SYN到达时,TCP在未完成连接队列中创建个新项,然后响应以三路握手
的第—个分节服务器的SYN响应,其中捎带对客户SYN的ACK(2.6节)。这一项.直保留在
未完成连接队列中,直到三路握手的第二个分节(客户对服务器SYN的ACK)到达或者该项超
时为止。(源白Berkeley的实现为这些末完成连接的项设置的超时值为75s。)如果3路握手正常
完成,该项就从未完成连接队列移到已完成连接队列的队尾。当进程调用accept时(该函数在
下一节讲解),己完成连接队列巾的队头项将返回给给进程,或者如果该队列为空,那么进程将被
投入睡眠,直到TCP在该队列中放入一项才唤醒它。4.6节: accept函数
accept函数用于从已完成连接队列对头返回下一个已完成连接
int accept(int sockfd, struct sockaddr *cliaddr, socklent_t *addrlen);
4.7节: fork函数
fork函数的内存语义:- 共享代码段, 子指向父 : 父子进程共享同一代码段, 子进程的页表项指向父进程相同的物理内存页(即数据段/堆段/栈段的各页)
- 写时复制(copy-on-write) : 内核会捕获所有父进程或子进程针对这些页面(即数据段/堆段/栈段的各页)的修改企图, 并为将要修改的页面创建拷贝, 将新的页面拷贝分配给遭内核捕获的进程, 从此父/子进程可以分别修改各自的页拷贝, 不再相互影响.
- 4.9节:
close函数, 涉及到描述符引用计数,所以多进程并发服务器才可以共享已连接套接字,因为父进程调用close函数知识把该套接字标记成已关闭并导致该套接字描述符减1。只要引用计数的值仍大于0,就不会引发tcp的四分组连接终止序列
第五章
- 5.9节:
处理SIGCHLD信号, 涉及到僵死进程(子进程终止时给父进程发送了一个SIGCHLD信号,若父进程未加处理,则子进程进入僵死状态),所以要建立该信号处理函数,并在函数中调用waitpid来处理 - 5.10节 :
使用wait或者waitpid来处理已终止的子进程,通常是使用waitpid并指定WNOHANG选项,来告知waitpid在有尚未终止的子进程在运行时不要阻塞。
第六章
同步I/O操作:导致请求进程阻塞,知道I/O操作完成
异步I/O操作:不导致请求进程阻塞
- 6.6节 :
shutdown函数,shutdown可以不用管引用计数就激发tcp的正常连接终止序列。当关闭连接的写这一半,对于tcp连接, 这称为半关闭(half-close)