2012-09-28 32 views
0

我的Linux x86机器上的syscall有一些问题。 考虑我在我的应用程序中与LAN中的其他主机建立了SSH连接。然后,我放下网络(例如拔下电缆)并调用(通过我的应用程序)通过连接发送一些SSH数据包的功能。该函数内部调用sendsend(2)在无法访问的网络上成功建立连接

w = send(s->fd_out,buffer, len, 0); 

在调试器中我发现,send回报len(即w == len呼叫后)。 如果网络无法访问,这会如何呢?当我打电话给netstat它说我的SSH连接处于ESTABLISHED状态,即使网络关闭了。

无法理解为什么send正常执行并且不会返回任何错误(如EPIPEECONNRESET)。可能是SSH连接在网络放下后的一段时间?

感谢所有。

+0

你真的拔掉了一根电缆吗?还是以更微妙的方式放下网络? 'len'多少钱? –

+0

如果你从调用'send()'的主机(而不是**,例如,该主机上的虚拟机,或者你拔下的路由器的下游机器上)拔下了电缆,则打开套接字确实应该返回EIO缺失在另一个内核线程可以传播错误之前的一段时间。你试图测试的失败究竟是什么? –

+0

其实我使用networkmanager的无线接口。但是对于有线接口也一样(我使用ifconfig down /拔掉了电缆)。 'len'在我的情况下是'52'。我试图找到一种在SSH会话期间检测连接丢失的方法。而且我没有找到任何可以帮助我使用该应用的'libssh'的东西。 – maverik

回答

3

这是由于实施TCP(和SSH使用TCP)。你的send()只是写入一个套接字,它只是一个文件描述符,返回意味着这个操作是成功的。这并不意味着数据已经发送。毕竟,文件描述符只是一些带有内核状态的指针。它在内核中实现以在失败会话之前保持TCP状态更长一些。事实上,内核被允许无限期地保持这个会话,直到你明确地调用close()或者终止你的进程。因此,您的数据实际上会缓存在内核空间以供网卡在稍后提供。

下面是一个简单的实验,你可以这样做: 编写不断建立连接

socket(); 
bind(); 
listen(); 
while (1) { 
    accept(); 
    recv(); 
} 

写客户端建立连接后,接收消息,需要CIN输入的服务器,并且将消息发送到服务器时你打回来了。

socket(); 
connect(); 
while (1) { 
    getline(); 
    send(); 
} 

请注意,您从不在任何一边的while循环中调用close()。现在,如果您在建立连接之后拔出电缆,发送消息,重新连接并发送另一条消息,则会在服务器端找到这两条消息。
你永远不会看到的是,你收到第一条消息之前的第二条消息。你要么全部丢失,要么按顺序接收它们。

现在让我解释为什么它的行为如此。这是TCP会话的状态图。
https://dl.dropbox.com/u/17011409/TCP_State.png

您可以清楚地看到,除非明确调用close(),否则连接将始终处于已建立状态。这是TCP的预期行为。建立TCP连接非常昂贵,并且保持会话活动对性能有好处。 (这部分是TCP DOS的工作原理,攻击者在服务器耗尽资源以保持TCP状态信息的同时保持连接。)

在这种状态下,send()将被委派给内核以进行实际发送。 TCP保证按顺序,可靠的传输,但网络随时可能丢失数据包。所以TCP有缓冲你的数据包,并继续尝试。有一些算法可以抑制这种重试,但是在声明失败之前它会被缓冲很长时间。在Linux中,假设丢包的默认超时时间为3秒。但是在损失之后,TCP会重试。然后在几秒钟后再试。拔掉电缆的事实与通往目的地的数据包丢失情况一样。再次插入电缆后,重试会成功,并且TCP将按顺序开始发送剩余的消息。

我知道我一定没有彻底解释它。你真的需要知道TCP的细节来推断这种行为。它是TCP给你的属性所必需的。将内部实现暴露给程序员是不可接受的。 (发送调用有时会在几毫秒内返回,有时在10秒后返回,我敢打赌,没有人会希望在他们的代码中使用这个性能炸弹。拥有一个TCP库的目的正是为了隐藏网络的这种丑陋本质。)实际上,您甚至需要了解多个RFC以及TCP如何通过有损网络实现可靠传输的算法。拥塞控制进入缓冲区将在那里存在多久。维基百科是一个很好的起点,但如果你真的想了解细节,这是一个完整的学期本科课程。

2

对于零标志参数,send()等价于write(2)。它会将您的数据写入文件描述符(存储在内核空间中以提供)。

您必须使用其他类型的标志:MSG_CONFIRM可能会对您有所帮助。

+0

从手册页中,MSG_CONFIRM仅对SOCK_DGRAM或SOCK_RAW有效。 TCP提供了一个无尽的字节流的抽象(SOCK_STREAM),而不是单独的数据包。我不知道有任何标志会指示TCP发送的实际传送。如果我错了,请随时纠正我,但由于RFC标准中没有“数据包”概念,我不认为这样的标志永远不会存在。 – wujj123456

相关问题