内容简介:这几个属性是从监听套接字继承的,要想设置已连接套接字的这些属性,需要在监听套接字上设置。如果设置了这个选项,当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套接字要发送的对端只有一个时,可以通过显式连接来提高效率。
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Beginning Apache Struts
Arnold Doray / Apress / 2006-02-20 / USD 44.99
Beginning Apache Struts will provide you a working knowledge of Apache Struts 1.2. This book is ideal for you Java programmers who have some JSP familiarity, but little or no prior experience with Ser......一起来看看 《Beginning Apache Struts》 这本书的介绍吧!