TCP
bind函数
bind函数的作用是把本地地址和端口写入套接字结构里。
如果tcp服务器不bind一个地址,在listen的时候会随机分配,但这种操作不合适
如果不指定端口,没法在bind函数取得所选端口(const sockaddr *),如果想知道,getsockname
listen函数
listen函数做两件事:
- socket创建的套接字默认为主动套接字(即将要connect),listen函数将其转换为监听套接字,指示内核允许接受连接请求
- 本函数的第二个参数指示内核为其连接队列赋予的最大排队数
backlog参数大小的含义:
内核会为监听套接字维护两个队列:全连接队列(established)和半连接队列(syn_rcvd),这两个队列大小的和不得超过backlog的大小
收到第一个SYN报文,在半连接队列中创建条目。在收到来自客户端的ACK报文后,服务器在全连接队列中创建条目。
当进程调用accept时,会将全连接队列的队头返回给进程。如果调用时队列为空,进程将会进入睡眠,直到TCP中放入了一项才唤醒它。
accept函数
accept函数的第一个参数为监听套接字,返回值为已连接套接字。
如果对客户的地址不感兴趣,可以把第2个参数和第3个参数都置为NULL
fork和exec
fork是创建新进程的唯一方式,exec并不创建新进程,而是创建新程序.
进程打开的描述符通常在exec之后保持打开。
文件和套接字是引用计数的,因此如果引用数大于1,通过描述符关闭文件或者描述符并不真的关闭,而只是将引用数减1.
多进程服务器
迭代式服务器的问题在于如果处理请求的时间很长,那么用户等待时间会很长。
close函数
close的动作是将套接字标记为关闭,并且立即返回。close后既不能使用read也不能使用write。但是TCP会试图将所有没传完的数据传完。
父进程一定要立即close已连接,不然会导致可用描述符用完,并且因为父进程仍然持有套接字,任何子进程也也没法终止TCP连接。
getsockname和getpeername.
这两个函数用于获取本机ip端口,对端ip端口
getpeername的应用场景:
虽然accept确实会返回对端的地址结构,但是fork后的进程调用exec会丢失这个结构,这个时候就只能通过套接字描述符去获得
对端地址。