这几个属性是从监听套接字继承的,要想设置已链接套接字的这些属性,须要在监听套接字上设置。linux
若是设置了这个选项,当2小时内套接字的任一方向都没有数据交换时,TCP会自动发送一个探活数据包(keep-alive probe),接下来会有几种可能:算法
这个选项表示如何关闭面向链接的协议,默认是调用close
时当即返回,但若是发送缓冲区有残留的数据,会尝试将其发送给对端。服务器
设置时经过如下结构体来控制参数:网络
struct linger {
int l_onoff; /* option on/off */
int l_linger; /* linger time, 单位为秒*/
};
复制代码
l_onoff
为0时表示选项关闭,l_linger
的值被忽略,调用close
时会马上返回l_onoff
为非0而l_linger
为0时,调用close
关闭某个链接时TCP会停止该链接,即丢弃发送缓冲区的全部数据并向对端发送一个RST,而不是进行正常的四次挥手。这样可以避免TCP的TIME_WAIT状态,可是也可能出现2MSL内建立出该链接的化身的状况,致使来自刚才被终止的链接上的旧的数据被发送到新的化身上。l_onoff
为非0并且l_linger
也为非0时,关闭套接字时内核将会拖延一段时间。若是此时发送缓冲区中有数据,进程将会进入睡眠,直到:(a) 全部数据都已发送并被对端确认;(b) 拖延时间到。若是套接字被设置为非阻塞型,close
会当即返回,即便拖延时间为非0的状况也是。在使用SO_LINGER选项时,应该检查close
的返回值,若是在数据发送完并被确认前拖延时间到的话,close
会返回EWOULDBLOCK,且发送缓冲区的数据都会被丢弃。SO_REUSEADDR
容许一个监听套接字绑定到其众所周知端口,即便之前创建的将该端口做为本地端口的链接仍存在。好比监听的进程中途关闭了但其创建的子进程和链接仍存在,这时监听进程重启时尝试从新绑定端口时须要指定了SO_REUSEADDR
才行,不然会绑定失败。获取或设置TCP最大分节大小(MSS),表示TCP可以发送的最大数据量,一般由对端的SYN分节指定,除非咱们选择一个更小的值。若是在链接创建以前查询,返回的是默认值。异步
开启该选项将禁用Nagle算法,默认状况其是启用的。nagle算法能够减小大量小的数据包在网络中传输的状况。函数
linux2.4以后的版本才支持选项,开启该选项将启用cork算法,默认是禁用的。cork选项能够禁止小的数据包在网络中传输。性能
fcntl顾名思义,能够对描述符进行各类控制操做,主要经过cmd和arg两个参数来控制。大数据
int fcntl(int fd, int cmd, .../* args */) 复制代码
可选的cmd有:spa
F_SETFL
设置flagF_GETFL
获取flagF_SETOWN
设置套接字属主F_GETOWN
获取套接字属主使用方式:指针
int flags;
//先获取当前flags
if ((flags = fcntl(fd, F_GETFL, 0)) < 0) {
//error
}
//增长O_NONBLOCK选项
flags |= O_NONBLOCK;
//设置flags
if ((flags = fcntl(fd, F_SETFL, flag)) < 0) {
//error
}
//设置flags
if (fcntl(fd, F_SETFL, flags) < 0) {
//error
}
//关闭O_NONBLOCK选项
flags &= ~O_NONBLOCK
//设置flags
if (fcntl(fd, F_SETFL, flags) < 0) {
//error
}
复制代码
在使用fcntl
时,必须先获取当前的标志,而后与新的标志或以后再设置标志,不然会清除描述符的其余标志。
ssize_t sendto(int fd, const void *buff, size_t nbytes,
int flags, const struct sockaddr *to, socklen_t *addrlen);
ssize_t recvfrom(int fd, void *buff, size_t nbytes,
int flags, struct sockaddr *from, socklen_t *addrlen);
复制代码
函数返回发送或者接收的字节数,最后两个参数指定了对端地址。若是recvfrom的后两个参数是空指针,则表示不关心数据发送者的协议地址。
在一个UDP套接字上调用sendto
时,若是对端不可用,对端会返回一个ICMP消息(好比"port unreachable"),但这个错误不会返回给应用程序,sendto
仍可以正常返回。
咱们称这里的这个ICMP错误为异步错误,这个错误由sendto
触发,可是sendto
自己却成功返回;缘由是sendto
的成功仅表示在网络接口输出队列中具有足够的空间存放sendto
造成的IP数据报,而真正的错误在随后实际发出数据包的时候才发生,因此咱们称这个错误是异步的。
对于异步错误,处理的基本规则是:对于一个UDP套接字,由它引起的异步错误不会返回给它,除非它已链接。这里的已链接指的是成功调用了connect
函数。为何这么规定呢?由于一个UDP套接字可能会往多个对端发送和读取数据,而sendto
和recvfrom
只能返回单纯的errno
,不能返回对端的ip和端口号信息。因此咱们决定:只有在UDP已经只绑定到一个对端时,这些异步错误才返回给进程。
除非udp套接字事先成功调用了connect
,不然sendto
和recvfrom
发生的异常不会返回给应用程序。
对一个UDP套接字调用connect
函数并不会像TCP套接字那样进行三次握手,而是先检查传入的地址是否合法(是否可达等)而后保存ip和port到传入的套接字地址结构体中,接着直接返回。
一旦一个UDP套接字已链接,会发生三个变化:
sendto
时不能再指定最后两个参数(目标地址和地址长度),必须设置为空指针;或者改用write
或者send
recvfrom
时不能再指定最后两个参数(目标地址和地址长度),必须设置为空指针;或者改用read
/recv
/recvmsg
和TCP套接字不一样,UDP套接字能够屡次调用connect
函数,经过这样作能够达到两个目的:
AF_UNSPEC
便可)对于未链接的UDP套接字,每次调用sendto
函数时都会隐式地进行套接字链接和断开链接;因此若是肯定UDP套接字要发送的对端只有一个时,能够经过显式链接来提升效率。