内容简介:这几个属性是从监听套接字继承的,要想设置已连接套接字的这些属性,需要在监听套接字上设置。如果设置了这个选项,当2小时内套接字的任一方向都没有数据交换时,TCP会自动发送一个探活数据包(keep-alive probe),接下来会有几种可能:这个选项表示如何关闭面向连接的协议,默认是调用
- SO_DEBUG
- SO_NOROUTE
- SO_KEEPALIVE
- SO_LINGER
- SO_OOBINLINE
- SO_RCVBUF
- SO_RCVLOWWAT
- SO_SNDBUF
- SO_SNDLOWAT
- TCP_MAXSEG
- TCP_NODELAY
这几个属性是从监听套接字继承的,要想设置已连接套接字的这些属性,需要在监听套接字上设置。
SO_KEEPALIVE
如果设置了这个选项,当2小时内套接字的任一方向都没有数据交换时,TCP会自动发送一个探活数据包(keep-alive probe),接下来会有几种可能:
- 对端正常响应,这时不会通知应用程序。接下来2小时内如果仍没有数据,发送另一个探活数据包。
- 对端响应RST,表示对端已经崩溃并重新启动,这时将SO_ERROR设置为ECONNRESET,关闭套接字。
- 对端没有任何响应,这时会继续发送探活数据包试图获得响应(不同系统的重试次数和间隔不同),如果仍没有任何响应则放弃。这时会将SO_ERROR设置为ETIMEOUT,关闭套接字。
- 套接字收到一个ICMP错误(比如host unreachable),这时会将SO_ERROR设置为对应的错误,然后关闭套接字。
SO_LINGER
这个选项表示如何关闭面向连接的协议,默认是调用 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
允许一个监听套接字绑定到其众所周知端口,即使以前建立的将该端口作为本地端口的连接仍存在。比如监听的进程中途关闭了但其建立的子进程和连接仍存在,这时监听进程重启时尝试重新绑定端口时需要指定了SO_REUSEADDR
才行,否则会绑定失败。 - 允许在同一个端口上启动同一服务器的多个实例,只要每个实例绑定不同的本地地址即可
TCP_MAXSEG
获取或设置TCP最大分节大小(MSS),表示TCP能够发送的最大数据量,通常由对端的SYN分节指定,除非我们选择一个更小的值。如果在连接建立之前查询,返回的是默认值。
TCP_NODELAY
开启该选项将禁用Nagle算法,默认情况其是启用的。nagle算法可以减少大量小的数据包在网络中传输的情况。
TCP_CORK
linux2.4之后的版本才支持选项,开启该选项将启用cork算法,默认是禁用的。cork选项可以禁止小的数据包在网络中传输。
fcntl(file control)
fcntl顾名思义,可以对描述符进行各种控制操作,主要通过cmd和arg两个参数来控制。
int fcntl(int fd, int cmd, .../* args */) 复制代码
可选的cmd有:
F_SETFL F_GETFL F_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
时,必须先获取当前的标志,然后与新的标志或之后再设置标志,否则会清除描述符的其他标志。
UDP套接字
sendto和recvfrom
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已经只绑定到一个对端时,这些异步错误才返回给进程。
connect
除非udp套接字事先成功调用了 connect
,否则 sendto
和 recvfrom
发生的异常不会返回给应用程序。
对一个UDP套接字调用 connect
函数并不会像TCP套接字那样进行三次握手,而是先检查传入的地址是否合法(是否可达等)然后保存ip和port到传入的套接字地址结构体中,接着直接返回。
一旦一个UDP套接字已连接,会发生三个变化:
-
sendto
时 不能 再指定最后两个参数(目标地址和地址长度),必须设置为空指针;或者改用write
或者send
-
recvfrom
时 不能 再指定最后两个参数(目标地址和地址长度),必须设置为空指针;或者改用read
/recv
/recvmsg
- 由已连接UDP套接字引发的异步错误会返回给进程。
多次调用connect
和TCP套接字不同,UDP套接字可以多次调用 connect
函数,通过这样做可以达到两个目的:
AF_UNSPEC
connect与性能
对于未连接的UDP套接字,每次调用 sendto
函数时都会隐式地进行套接字连接和断开连接;所以如果确定UDP套接字要发送的对端只有一个时,可以通过显式连接来提高效率。
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。