1.socket 函数
首先被调用的函数,用于选择通信协议。
socket调用成功后,得到的套接字为主动套接字CLOSED状态。
PF 和 AF 的关系
PF的是协议族,AF是地址族,理论上一个PF包括多个AF,但实际上一个PF只实现了一个AF,所以两者在编程上是同等的。
2.connect
connect 发起主动握手,
connect 调用时,TCP 发送 SYN
TCP接收到 ACK时,connect 返回。
connect 前,可以不bind,内核会在connect 时随机分配原套接字。
connect 开始时,TCP从 CLOSED --> SYN_SEND,成功时, SYN_SEND --> ESTABLISH
每次 connect 失败后,都必须 close 套接字,并重新调用 socket。
3.bind
设置源套接字地址,套接字状态不改变
可以指定也可以不指定,不指定内核会分配,
设置为0则为不指定,
指定任意IP时,下面两种都一样,因为 INADDR_ANY == 0,大小端都一样
serv.sin_addr.s_addr = INADDR_ANY;
serv.sin_addr.s_addr = htonl(INADDR_ANY);
bind 返回的常见错误是, EADDRINUSE (地址已使用)。
4.listen
两个作用:
(1)套接字状态从主动状态--> 被动状态 CLOSED --> LISTEN
l (2)isten 初始化排队的最大连接个数。
内核为套接字分配了两个队列:
未完成连接队列,即正在进行三次握手的,这些套接字处于 SYN_RECV 状态。
已完成连接队列,即已经完成三次握手的,这些套接字处于 ESTABLISHED 状态。
backlog >= 两队列总和
5.accept
用于已连接队列头返回已连接。
如果已连接队列为空,则进程随眠。
accept 若成功,则返回内核重新分配的套接字。
6.典型的多进程并发服务器
for(;;) {
connfd = accept(listenfd, NULL, NULL);
if (fork() == 0) {
close(listenfd);
work();
close(connfd);
}
close(connfd);
}
父子进程都要 close 未用的套接字,以减少引用计数。
当 套接字关闭时,才会发出 FIN。
另外也避免了 文件描述符用尽。
7.close
减少套接字引用计数,当引用计数为0,则关闭套接字(TCP会发送FIN,对端TCP接受到FIN后,向应用层发送EOF)。
close后应用程序无法通过套接字继续读写操作。
但TCP会将剩余的数据进行收发。
8.getsockname 和 getpeername
通过 文件描述符,获得 套接字对信息。
用于子进程 exec 后,需要获得 父进程时的套接字对信息,因为套接字信息在内核区,不会被exec后覆盖,所以子进程只要获得 文件描述符即可(可通过命令行参数获得)
手机扫一扫
移动阅读更方便
你可能感兴趣的文章