<转>Linux Socket学习(十二)

bsp; int l_onoff;
int l_linger;
};
成员l_onoff为一个布尔值,非零值表示TRUE,而零则表示FALSE。这个选项的三个值描述如下:

1 设置l_onoff为FALSE使得成员l_linger被忽略,而使用默认的close行为。也就是说,close调用会立即返回给调用者,如果可能将会传输任何未发送的数据。
2 设置l_onoff为TRUE将会使得成员l_linger的值变得重要。当l_linger非零时,这代表应用在close函数调用上的以秒计的超时时限。如果超时发生之前,有未发送的数据并且成功关闭,函数将会成功返回。否则,将会返回错误,而将变量errno的值设置为EWOULDBLOCK。
3 将l_onoff设置为TRUE而l_linger设置为零时使得连接中止,在调用close时任何示发送的数据都会丢弃。

我们也许希望得到一些建议,在我们的程序中使用SO_LINGER选项,并且提供一个合理的超时时限。然后,可以检测由close函数的返回值来确定连接是否成功关闭。如果返回了一个错误,这就告知我们的程序也许远程程序并不能接收我们发送的全部数据。相对的,他也许仅意味着连接关闭时发生的问题。

然而,我们必须保持清醒,这样的方法在一些服务器设计中会产生新的问题。当在close函数调用上将SO_LINGER选项配置为超时(linger),当我们的服务器在close函数调用中执行超时时会阻止其他的客户端进行服务。如果我们正在一个进程中服务多个客户端进程时就会存在这个问题。使用默认的行为也许更为合适,因为这允许close函数立即返回。而任何未发送的数据也会为内核继续发送。

最后,如果程序或是服务器知道连接应何时中止时可以使用中止行为。这也许适用于当服务器认为没有访问权限的用户正试着进行访问的情况。这种情况下的客户并不会得到特别的关注。

下面的代码是一个使用SO_LINGER选项的例子,使用30秒的超时时限:
#define TRUE 1
#define FALSE 0
int z; /* Status code
*/ int s; /* Socket s */
struct linger so_linger;
...
so_linger.l_onoff = TRUE;
so_linger.l_linger = 30;
z = setsockopt(s,
SOL_SOCKET,
SO_LINGER,
&so_linger,
sizeof so_linger);
if ( z )
perror("setsockopt(2)");

下面的例子显示了如何设置SO_LINGER的值来中止套接口s上的当前连接:
#define TRUE 1
#define FALSE 0
int z; /* Status code */
int s; /* Socket s */
struct linger so_linger;
...
so_linger.l_onoff = TRUE;
so_linger.l_linger = 0;
z = setsockopt(s,
SOL_SOCKET,
SO_LINGER,
&so_linger,
sizeof so_linger);
if ( z )
perror("setsockopt(2)");
close(s); /* Abort connection */

在上面的这个例子中,当调用close函数时,套接口s会立即中止。中止的语义是通过将超时值设置为0来实现的。

设置SO_KKEPALIVE选项

当使用连接时,有时他们会空闲相当长的时间。例如,建立一个telnet会话通过访问股票交易服务。他也许会执行一些初始的查询,然后离开连接而保持服务打开,因为他希望回来查询更多的内容。然而,同时连接处理空闲状态,也许一次就是一个小时。

任何一个服务器认为他有一个连接的客户时会为其分配相应的资源。如果服务器是一个派生类型(fork),那么整个Linux进程及其相应的内存都分配给这个客户。如果事情顺利,这个场景并不会产生任何问题。然而当出现网络崩溃时,困难出现了,我们所有的578个客户都会从我们的股票交易服务中失去连接。

在网络服务恢复后,578个客户会试着连接到我们的服务器,重建连接。这对于我们来说是一个真实的问题,因为我们的服务器在之前并没有意识到他失去了空闲客户--SO_KKEPALIVE来解决这个问题。

下面的例子显示了如何在套接口s上使用SO_KKEPALIVE选项,从而一个断开的空闲连接可以被检测到:
#define TRUE 1
#define FALSE 0
int z; /* Status code */ int s; /* Socket s */
int so_keepalive;
...
so_keepalive = TRUE;
z = setsockopt(s,
SOL_SOCKET,
SO_KEEPALIVE,
&so_keepalive,
sizeof so_keepalive);
if ( z )
perror("setsockopt(2)");

在上面的例子中设置了SO_KEEPALIVE选项,这样当套接口连接空闲相当长的时间时,一个探测信息(probe message)就会发送到远程端。这通常是在两个小时的无活动后完成的。对于一个保持活动的探测信息会有三个可能的反应。他们分别是:
1 端会合适的返回表明一切正常。并没有向程序返回任何指示信息,因为这是程序假定的开始。
2 端响应表明他对连接一无所知。这表明端自上次通信以后与主机进行重新连接。这样当下次套接口操作时会向程序返回ECONNRESET错误代码。
3 端没有响应。在这种情况下,内核也许做了几次尝试进行连接。如果没有响应请求,TCP通常会在大约11分钟内放弃。当这种情况发生时,在下次套接口操作时会返回ETIMEOUT错误。其他的错误,例如EHOSTUNREACH会在网络不再能到达主机时返回。

SO_KEEPALIVE 所调用的时间框架会限制他通常的用处。探测信息也只在大约两个小时的无活动后才会发送。然后,当没有响应时,在连接返回错误时还需要另外的11分钟。无论怎样,这个选项确实允许探测空闲的无连接套接口,然后由服务器进行关闭。相应的,支持长空闲连接的服务器应允许这个特征。

设置SO_BROADCAST选项

我们现在还没有讨论到使用UDP进行广播的主题。然而,我们很容易意识到广播功能的误用以及所造成的网络灾难。为了避免在没有计划广播时进行广播,套接口禁用了广播功能。如果确实需要广播,那么C程序员要为套接口的这个功能处理相应的麻烦。

SO_BROADCAST是一个布尔标志选项,由int数据类型进行设置。下面的例子显示了如何设置SO_BROADCAST选项:
#define TRUE 1
#define FALSE 0
int z; /* Status code */
int s; /* Socket s */
int so_broadcast;
...
so_broadcast = TRUE;
z = setsockopt(s,
SOL_SOCKET,
SO_BROADCAST,
&so_broadcast,
sizeof so_broadcast);
if ( z )
perror("setsockopt(2)");
如果要setsockopt函数返回零,套接口s已经允许进行广播。然而在这里要注意的是所选用的套接口类型必须具有广播功能,例如UDP套接口。

设置SO_OOBINLINE选项

在一些情况下,已发送的数据也许会超过所限制的数据量。通常,这些越界的数据是用不同于通常的数据接收函数来进行接收的。然而有时却更喜欢使用通常的方式来接收这些越界数据。当选择这种方法时,越界数据作为通常数据流的一部分在通常数据之前到达。

要使用这个特征,我们可以用下面的代码来完成:
#define TRUE 1
#define FALSE 0
int z; /* Status code */
int s; /* Socket s */
int so_oobinline;
...
so_oobinline = TRUE;
z = setsockopt(s,
SOL_SOCKET,
SO_OOBINLINE,
&so_oobinline,
sizeof so_oobinline);
if ( z )
perror("setsockopt(2)");
在设置了SO_OOBINLINE选项之后,越界数据就会与通常数据一起接收。在这种方式下,所接收的越界数据与通常数据相同。

SO_PASSCRED与SO_PEERCRED选项

这些选项仅适用于PF_UNIX(PF_LOCAL)套接口。这些选项用来在当前主机的本地套接口上控制与传递凭证。这也许是最难掌握的一个主题。就现在而言,我们只需要简单的注意到,如果我们希望编写服务本地主机客户的服务程序时,我们也许会对这两个选项感兴趣。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值