unp总结

来源:互联网 发布:tw域名注册 编辑:程序博客网 时间:2024/06/15 09:16
第二章
tcp从连接到关闭的状态变化图
TIME_WAIT状态 
1)可靠实现TCP全双工连接的终止;TCP执行主动关闭,并发送最后一个ACK,该连接必须在TIME_WAIT状态停留2MSL,如果另一端超时并重发最后的FIN,这样可以让TCP再次发送最后的ACK以防止这个ACK丢失
2)允许老的重复分节在网络中消逝  
以太网MTU 1500字节,MSS IPv4 1460,IPv6 1440
udp没有发送缓冲区,发送数据大于差不多大于指定的发送缓冲区大小的一半,会返回EMSGSIZE

第四章
connect可能出错的几种情况
1)tcp客户端没有收到SYN分节的响应,返回ETIMEDOUT;BSD是75秒未响应则返回这个错误
2)对客户端的SYN分节响应RST;服务器在指定端口没有进程在等待与之连接
3)客户端发出的SYN分节在某个中间路由上引发unreachable错误,在75秒后仍未响应则返回EHOSTUNREACH

bind可能出现EADDRINUSE错误,只要在bind前设置SO_REUSEADDR就可解决
getsockname  获取本地socket的端口与地址;如通过connect返回的fd,获取内核赋予该链接的本地地址与端口
getpeername  获取对端的端口与地址;如通过accept返回的fd,获取客户端的地址与端口

第五章
检查进程状态和关系 ps -t pts/6 -o pid,ppid,tty,stat,args,wchan
SIGCHILD 子进程终止发生给父进程的信号
对于accept,read,write,open,select之类的函数,中断后可以被重启;connect中断后则不行
如果信号同时触发,则可以通过while((pid=waitpid(-1,&stat,WHONG)) > 0)等待;
accept返回前连接夭折;连接建立后accept之前收到客户端发过来的RST
服务器进程终止;终止时会收到FIN,在终止之后客户端再发送数据,服务端响应RST,在read前则返回ECONNRESET
SIGPIPE信号;当一个进程向某个已收到RST的套接口执行写操作时,内核向该进程发送一个SIGPIPE信号
服务器主机崩溃;对客户端数据没有响应,ETIMEDOUT,如果是某个中间路由不可达,EHOSTUNREACH
服务器主机崩溃后重启;服务器重启后丢失崩溃前的所有连接信息,因此对所收到的数据分节响应RST
服务器主机关机;关机时init进程会发送SIGTERM信号,等待一小段时间,然后给所有仍运行的进程发送SIGKILL信号。客户端可通过select/poll获取服务端终止时发送的FIN


第六章
I/O模型
从一种角度来看uinx I/O模型分5种:阻塞I/O,非阻塞I/O,I/O复用,信号驱动I/O,异步I/O
另一种角度来说:同步阻塞,同步非阻塞,异步阻塞,异步非阻塞
select 对某个套接口就绪的条件:
可读:有数据可读,关闭连接的的读一半,给监听的套接口准备好新的连接,待处理的错误
可写:有可用于写的空间,关闭连接的写一半,待处理的错误
close与shutdown区别;
close把描述字的引用计数减1,仅在该计数变为0的时候关闭套接口;close是终止读和写两个方向
shutdown 关闭读一半,套接口不再有数据可接收,而且现有接收缓冲区数据被丢弃
shutdown 关闭写一半,将当前发送缓冲区的数据将被发送掉,之后连接序列终止。shutdown不管引用计数是否为0。

第七章
TCP已连接套接口从监听套接口继承下来的选项:
SO_DEBUG,SO_DONTROUTE,SO_KEEPALIVED,SO_LINGER,SO_OOBINLINE
SO_RCVBUF,SO_SNDBUF,SO_SNDLOWAT,SO_RCVLOWAT,TCP_MAXSEG,TCP_NODELAY
SO_ERROR,一旦套接口出现的错误返回给用户进程,它的so_error(套接口上发送错误的值)被复位
SO_KEEPALIVE,如果两个小时内在该套接口的任一方向上没有数据交换,TCP就自动给对端发送一个保持存活探测的分节。对端存活,响应ACK;对端服务崩溃以重启,响应RST;对端没有响应,则11分15秒内没有得到响应则放弃,该套接口的错误为ETIMEDOUT
SO_LINGER,
l_onoff为0,即close立刻返回。
l_onoff不为0,l_linger为0,则close时,丢弃发送缓冲区数据,发送RST给对端,这样就没有走正常的关闭流程。这么一来,避免了TCP的TIME_WAIT;不过需要知道的是,不要试图避免这个状态
l_onoff不为0,l_linger不为0,对于阻塞套接字,那么当套接口关闭时内核将拖延一段时间,等到数据确认或延迟时间到,之后close才返回。对于非阻塞套接字,不会等待close完成
对TCP来说,套接口接受缓冲区可用空间大小限制了TCP通告窗口的大小,TCP套接口缓冲区不会溢出,因为不允许对端发送超过本端所通告窗口大小的数据
对于UDP来说,没有流量控制,较快的发送端可以淹没较慢的接收端,导致接收端的UDP数据报被丢弃
对于TCP发送缓冲区,TCP会为发送的每个分节保留一个拷贝,直到收到服务的ACK,因此如果ACK响应慢,那么,可发送的数据,不一定会等于TCP缓冲区大小
SO_REUSEADDR 
1)允许启动一个监听服务器并绑定到某个端口,即使以前建立的将该端口用作它们的本地端口的连接仍然存在
2)允许同一个端口上启动同一服务器的多个实例,只要每个实例绑定ip地址不一样。即多网卡都单独绑到某个端口
TCP_NODELAY
Nagle算法,目的在于防止一个连接在任何时刻有多个小的分组待确认
Nagle算法通常与ACK延迟算法联合使用;使得TCP在接到数据后不立即发送ACK,而是等待一小段时间,如果这段时间内有数据发送回对端,被延滞的ACK就可以由这些数据捎带,从而省掉一个TCP分节
如果存在客户端向服务器发送第一个小数据后紧跟第二个小数据。
这时可以通过writev或者一次copy到单个缓冲区然后对该缓冲区调用一次写,对于设置TCP_NODELAY调用两次write是不可取的。

第八章
UDP输出操作成功返回仅仅表示在该接口输出队列具有存放IP数据报的空间
客户端的临时端口在第一次sendto时一次性选择,不能改变;而IP地址可以随发送的每个UDP数据报而变动。
除非套接口已连接,否者异步错误时不会返回到UDP套接口
当应用进程在一个未连接的UDP套接口上调用sendto时,berkeley的内核会暂时连接该套接口,发送数据,然后断开该连接
netstat -s -p udp 统计丢包信息

第11章
DNS中的资源记录类型:
A 记录主机名映射成一个32位的IPv4地址
AAAA 记录把一个主机名映射成128的IPv6地址
PTR记录把IP地址映射成主机名,对于IPv4,4字节反转顺序
CNAME代表规范名
gethostbyname 根据查询hostname,有些实现允许hostname参数是点分十进制;返回struct hostent
getservbyname/getservbyport 根据给定名字/端口号查询相应服务;返回struct servent
getaddrinfo/freeaddrinfo 能处理名字到地址以及服务到端口的这两种转换;返回struct addrinfo
可以传入hint对getaddrinfo进行暗示希望获取什么样的响应数据

第12章
对于支持IPv4,IPv6的双栈主机,数据报进入时,如果该机是IPv4服务器,那么只能IPv4数据报能传入
对于支持IPv4,IPv6的双栈主机,数据报进入时,如果该机是IPv6服务器,那么IPv4,IPv6数据报都能传入,
在网络层(IP层)到传输层(TCP/UDP),IPv4会通过IPv4映射的IPv6地址,进行将IPv4头部中的源IPv4地址转换
成一个等价的IPv4映射的IPv6地址。
如果一个IPv6的TCP客户指定了一个IPv4映射的IPv6地址以调用connect,或一个IPv6的UDP客户指定了一个IPv4映射的IPv6地址以调用sendto,那么内核将检测到这个映射地址改为发送IPv4的数据报而不是IPv6数据报;即如果指定了IPv4到IPv6的映射,那么出去的时候将是IPv4数据报

第14章
recv/send 第三个参数flags:
MSG_DONTROUTE 对于直连的本地网络上可以关闭查询
MSG_DONTWAIT 对于阻塞的套接口,可以把单个的I/O操作临时指定为非阻塞
MSG_OOB 发送或接收带外收
MSG_PEEK 适用于recv/recvfrom,允许窥看已可读的数据,不过系统不丢弃窥看走的数据
MSG_WAITALL 告诉内核不要在尚未读入请求数目的字节之前让一个读操作返回
readv/writev允许单个系统调用读入或写出来自一个或多个缓冲区(struct iovec 数组)
recvmsg/sendmsg,可以替换read/readv/recv/recvfrom,类似的也可以替换成sendmsg;
主要关注struct msghdr即可

第15章
unix socket套接口结构 struct sockaddr_un,内部sun_path指定要绑定的地址;
注意connect前,server已启(即路径已绑定且打开socket),否则连不上;
另外对于udp的unix socket客户端,需要在sendto/recvfrom之前,绑定一个路径(和server端的路径是不一样的),然后再发送与接收数据
socketpair创建,创建一个全双工的流管道。其实和pipe很像,pipe也可以有全双工,个人认为差别是在于指定可以指定type为SOCK_STREAM和SOCK_DGRAM

第16章
linux下,EAGAIN和EWOULDBLOCK值是一样的。
对于非阻塞套接口,如果输入操作不能被满足(对于TCP套接口即至少有一个字节的数据可读,对于UDP套接口即有一个完整的数据报可读),相应调用将立刻返回一个EWOULDBLOCK错误。
对于一个非阻塞的TCP套接口,如果其发送缓冲区没有可用空间,输出函数调用将立即返回EWOULDBLOCK错误,如果其发送缓冲区有一部分可用,返回值将是内核能够拷贝到缓冲区的字节数,即不是需要发送数据的总长度。对于UDP套接口,因为没有发送缓冲区,内核只是拷贝应用进程的数据并把它沿协议栈向下传递
对于一个非阻塞的套接口调用accept,并且无连接到达,将立即返回EWOULDBLOCK;不过一般不会这么用,会在非阻塞监听的套接口上+IO复用,这样,如果套接口可读,那么一般是不会出现EWOULDBLOCK;
对于accept需要注意一种情况,select之后在accept之前,服务器TCP收到客户端发来的RST,这是这个已完成的连接会被TCP服务器剔除出已完成队列,如果队列中没有其他也完成的连接,那么对于阻塞的套接口将会阻塞在上面,对于非阻塞套接口将返回EWOULDBLOCK,ECONNABORTED等错误(忽略掉即可)
对于一个非阻塞的套接口调用connect,基本上都是立即返回EINPROGRESS;
当连接建立成功,描述字变为可写;
当连接建立遇到错误时,描述字变为可读可写,可用getsockopt取套接口待处理错误(SO_ERROR选项),如果发生错误,取到的值就是对应连接错误的errno值。
需要注意的是,在使用调用select之前,有可能连接已经建立并有来自对端的数据到达,这时,套接字上不发生错误,套接口也是即可读又可写。
又有提到,不能假设套接口的可写(而不可读)条件是select返回套接口操作成功唯一的方法,应该是指,不能将其可写作为可移植性的判断连接是否建立成功的唯一方法
apache apr对于非阻塞套接口的connect判断是否连接上的做法是,在IO复用响应套接口可写,则再次调用connect,并获取套接口返回的错误如果是EINPROGRESS则尝试用SO_ERROR选项获取是否存在错误,如果存在错误,则返回错误;如果不是EINPROGRESS错误,则判断是否是EISCONN错误,如果不是则返回错误,否而即连接成功

第20章
TCP只支持单播
IPv4对于多播的支持是可选的,IPv6是支持多播的。对于广播,两者都支持
广播的用途之一是资源发现,另一个用途是在有多个客户主机与单个服务器主机的局域网环境减少分组流通
广播存在的问题:
子网上未参加相应广播应用的所有主机也不得不沿协议栈一路向上完成地处理收取UDP广播数据报,知道该数据报经历UDP层时被丢弃为止
发送广播,需要指定对端的IP为子网的广播地址,已经设置SO_BROADCAST套接口选项
对于源自Berkely的内核不允许对广播数据报执行分片,如果宿地址是广播地址的一个IP数据报,其大小超过外出接口的MTU,发送它的系统调用将返回EMSGSIZE错误;至于EMSGSZIE,UDP数据报本身不能发送太长,否者仍会返回EMSGSIZE(见之前章节的记录)
关于信号的阻塞与递交,如果关心信号的话,需要清晰的知道,信号会在程序执行过程中由内核随时随地递交;因此处理过程中,如果希望在除了某处之外都不触发的话,可将其阻塞掉,或者用些原语操作


第21章
广播一般局限于局域网内使用,而多播既可以局域网,也可以跨广域网
224.0.0.0-239.255.255.255是IPv4多播地址
发送端在发送数据多播数据前,接收端需要加入到某个多播地址
不同于广播,IP分片操作对于多播数据报是没问题的。