一、socket函数
作用:为了执行网络I/O,一个进程必须做的第一件事情就是调用socket函数,指定期望的通信协议类型
其中family参数指明协议族,该参数还被称为协议域。(AF_前缀表示地址族)
faily | 说明 |
AF_INET |
IPv4协议 |
AF_INET6 | ipv6协议 |
AF_LOCAL | Unix域协议 |
AF_ROUTE | 路由套接字 |
AF_KEY | 密钥套接字 |
type参数指明套接字类型
type | 说明 |
SOCK_STREAM | 字节流套接字 |
SOCK_DGRAN | 数据报套接字 |
SOCK_SEQPACKET | 有序分组套接字 |
SOCK_RAW | 原始套接字 |
protocol参数值某个协议类型常值,或设为0
protocol | 说明 |
IPPROTO_CP | TCP传输协议 |
IPPROTO_UDP | UDP传输协议 |
IPPROTO_SCTP | SCTP传输协议 |
socket函数中family和type参数组合
AF_INET | AF_INET6 | AF_LOCAL | AF_ROUTE | AF_KEY | |
SOCK_STREAM | TCP|SCTP | TCP|SCTP | 是 | ||
SOCK_DGRAN | UDP | UDP | 是 | ||
SOCK_SEQPACKET | SCTP | SCTP | 是 | ||
SOCK_RAW | IPv4 | IPv6 | 是 | 是 |
二、connect函数
作用:TCP客户用connect函数来建立与TCP服务器的连接。
sockfd是socket函数返回的套接字描述符。第二个、第三个参数分别是一个指向套接字地址结构的指针和该结构的大小。
套接字地址结构必须含有服务器的IP地址和端口号(fd可以理解为文件描述符)
TCP套接字:
调用connect函数将激发TCP的三路握手过程,而且仅在建立成功或出错时才返回。其中出错返回可能的情况如下。
- 若TCP客户没有收到SYN分节的响应,则返回ETIMEDOUT。
- 若对客户的SYN的响应是RST(表示复位),则表明该服务器主机在我们指定的端口上没有进程在等待与之连接(例如服务器进程也许没在运行)
- 若客户发出的SYN在中间的某一路由器上引发一个“destination unreachable“(目的地不可达)ICMP错误,则认为是一种软错误(soft error)。
connect函数导致当前套接字从CLOSED状态(该套接字自从由socket函数创建以来一直所处的状态)转移到SYN_SENT状态
若成功,则在转移到ESTABLISHED状态
若失败,则该套接字不再可用,必须关闭,我们不能对这样的套接字再次调用connect函数。
三、bind函数
作用:把一个本地协议地址赋予一个套接字。
对于网际网协议,协议地址是32位的IPv4地址或128位的IPv6地址与16位的TCP或UDP端口号组合。
sockfd是socket函数返回套接字的描述符。第二个参数是一个指向特定于协议的地址结构的指针,第三个参数时该地址结构的长度。
对于TCP,调用bind函数可以指定一个端口号,或指定一个IP地址,也可以两者都指定,还可以都不指定。
如何根据预期结果,设置sin_addr和sin_port或者sin6_addr和sin6_port的值
(给bind函数指定要捆绑的IP地址和/或端口号产生的结果)
进程指定 | 结果 | |
IP地址 | 端口 | |
通配地址 | 0 | 内核选择IP地址和端口 |
通配地址 | 非0 | 内核选择IP地址,进程指定端口 |
本地IP地址 | 0 | 进程指定IP地址,内核选择端口 |
本地IP地址 | 非0 | 进程指定IP地址和端口 |
四、listen函数
作用:仅由TCP服务器调用
listen做的两件事
1)当socket函数创建一个套接字时,它被假设为一个主动套接字,它是一个被调用connect发起连接客户套接字。listen函数把一个未连接的套接字转换成一个被动套接字,指示内核应该接受指向该套接字的连接要求。
根据TCP状态转换图,调用listen导致套接字从CLOSED状态转换到LISTEN状态。
2)本函数的第二个参数规定了内核应该为相应套接字排队的最大连接个数
listen函数通常在调用socket函数和bind函数之后,并在调用accept函数之前调用。
为了理解backlog参数,我们必须认识到内核为任何一个给定的监听套接字维护两个队列:
1)未完成连接队列(incomplete connection queue),每个这样的SYN分节对于其中一项
2)已完成连接队列(completed connection queue),每个已完成TCP三路握手过程的客户对应其中一项。这些套接字处于ESTABLISHED状态。
五、accept函数
作用:accept函数由TCP服务器调用,用于从已完成连接队列队头返回下一个已完成连接。如果已完成连接队列为空,那么进程被投入睡眠(假定套接字为默认的阻塞方式)
参数cliaddr和addrlen用来返回已连接的对端进程(客户)的协议地址。
addrlen是值-结果参数:调用前,我们将由*addrlen所引用的整数值置为cliaddr所指的套接字地址结构的长度,返回时,该整数值即为由内核存放在该套接字地址结构的确切字节数。
如果accept成功,那么其返回值是由内核自动生成的一个全新的描述符,代表与所返回客户的TCP连接。
本函数最多返回三个值:一个既可能是新套接字描述符也可能是出错知识的整数、用户进程的协议地址(由cliaddr指针所指)以及该地址的大小。
如果我们对返回客户协议地址不感兴趣,可以把cliaddr和addrlen均置为空指针。
六、fork和exec函数
fork函数作用:(包括有些系统可能提供的它的各种变体)是UNIX中派生新进程的唯一方法。
fork函数的一个特点就是返回两次。它在调用进程(称为父进程)中返回一次,返回值是新派生进程(称为子进程)的进程ID号,在子进程又返回一次,返回值为0.返回值本身告知当前进程是子进程还是父进程。
fork函数的两个典型用法:
1)一个进程创建一个自身的副本,这样每个副本都可以在另一个副本执行其他任务的同时处理各自的某个操作。
2)一个进程想要执行另一个程序。既然创建新进程的唯一办法是调用fork,该进程于是首先调用fork创建一个自身的副本,然后其中一个副本(通常为子进程)调用exec把自身替换成新的程序。
exec函数
存放在硬盘上的可执行程序文件能够被UNIX执行的唯一方法:由一个现有进程调用留个exec函数中的某一个。
exec把当前进程映像替换成新的程序文件,而且该新程序通常从main函数开始执行。进程ID不改变。我们称调用exec的进程为调用进程,称新执行的程序为新程序。
这六个exec函数之间的区别:
待执行的程序文件是由文件名还是路由名指定
新程序的参数时意义列出还是有一个指针数组来引用
把调用进程的环境传递给新程序还是个新程序指定新的环境
七、并发服务器
典型的并发服务器程序轮廓
并发服务器是同时调用父进程和子进程。
八、close函数
作用:用来关闭套接字,并终止TCP连接。
close一个TCP套接字的默认行为是把该套接字标记为已关闭,然后立即返回到调用进程。
九、getsockname和getpeername函数
这两个函数或者返回与某个套接字关联的本地协议地址,或者返回与某个套接字关联的外地协议地址
注意,两个函数最后一个参数都是值-结果参数。这两个函数都得装填有localaddr或peeraddr指针所指的套接字地址结构。
获取套接字的地址族
sockfd_to_family函数返回某个套接字的地址族