如何可靠的判断SOCKET连接已经断开?

我之前的一个程序通过select()函数和recv()和send()函数的返回值来判断,这在局域网中好象没有问题,但是在有时好象判断不出来,谁有可靠的方法呢?

取决你需要在多少时间里,判断出来。

10分钟之内就可以

假设你是TCP连接。

如果你在连接上发包的话,因为TCP自动重传,大概要9分半钟才会传递失败。
所以,恐怕在建立TCP连接的同时,建立别一个UDP连接,在这上面传心跳包来得确实。

请问xtang:
tcp传输的时候, 有没有办法控制传输的时间呢,比如, 如果传了15ms,还没有传完,就放弃此次传输。
因为我的定时器是22ms。定时采集数据并传输到远程机器显示用的, 我不想因为远端接受的问题影想我本地的定时采集。 谢谢!

TCP的特性,定义了它不会轻易“放弃传输”。不过,你的问题可能不在于此。

首先,用户程序的 send/sendto/write,都只是把用户数据考贝到TCPIP空间。send/sendto/write 会立即返回成功。TCPIP然后,才按协议定议把数据发出去,监视对方收没收到并决定重发。也就是说,不管远程收没收到数据,你的 send/sento/write都会成功返回。

唯一你不能从send/sendto/write返回的情形(我猜想这是你想防止的事),是SOCKET的传送缓存满了。这种情况下,TCPIP会阻塞用户程序,等缓存空出来,够把用户数据复制进来了,才会让用户程序继续运行。

如果你不希望这样,你有几种选项。

1) 把socket置成“非阻塞”的(NONBLOCK),这样,TCPIP当缓存满之后,不会阻塞用户程序,而是直接让你的send/sendto/write出错返回。出错值是EBUSY。你可以自己觉定怎么办。

2)你可以设setsockopt(), SO_SNDTIMEO,这样TCPIP在缓存满之后,会阻塞你一定的时间。如果过了这时间,TCPIP还是没有办法复制你的用户数据的话,你也会被出错返回。

另外,根据你每次传递多少数据,你也可以修改传送缓存大小。SO_SNDBUF。标准是16K

请xtang帮我看一下下面的数据发送函数:其中select函数是不是控制了m_hSocket可能被该类对象的其他的读写数据占用的情况呢. 您上面说如果缓冲区没有满,send会立刻返回,然后tcpip复责低层的数据传输,请问在tcpip传输的时候,m_hSocket一直被占用的吧. 这样的话, 下一次SendData(…)会在select处由于m_hSocket不可用超时(1ms),send(…)就没有发送的必要了吧. 这样也能达到控制的目的了吧.(定时器每次发送的数据量大概为4KB,正常情况下内部局域网1ms应该可以传完,18ms用于数据采集,采完了就发送。定时器的周期为22ms) .不知道我的理解对不对.
概括一下我的问题,就是send成功返回的时候,tcpip在负责传数据的时候,m_hSocket对下一次数据发送是不是可用的.我的理解是不可用。如果可用的话,select函数的使用就没有意义了。

int CBlockSocket::SendData(const char* pch, const int nSize, int nSeconds)
{
ASSERT(m_hSocket != NULL);//m_hSocket是CBlockSocket类的数据成员
ASSERT(nSize > 0);
if (nSeconds < SECONDS_MIN) nSeconds = SECONDS_MIN;
if (nSeconds > SECONDS_MAX) nSeconds = SECONDS_MAX;
fd_set fd ;
FD_ZERO(&fd);
FD_SET(m_hSocket,&fd);
TIMEVAL tv = {0,nSeconds};//special for realtime show (us)
if (select(m_hSocket+1, NULL, &fd, NULL, &tv) == 0)
{
throw new CBlockSocketException(“Send timeout”);
}
else
{
int nBytesSent = send(m_hSocket, pch, nSize, 0);
if (nBytesSent == SOCKET_ERROR)
{
throw new CBlockSocketException(“Send”);
}
}
return nBytesSent;
}

这种情况下,如果双方连接存在,但是远程接受端在程序控制上由于某种原因没有写接收语句,想忽略数据的接受. tcpip是不是一直都会发送不成功,在自动重传一定次数后,大概9分半钟,应该向应用层返回出错信息. 由于send已经成功返回了, 请教xtang,应用层通过什么知道传输出错了呢此后又做了呢些相应的处理呢,谢谢!(我对低层传输和编程之间的对话机制了解不深)

select()从语义上讲,不是“m_hSocket 有没有被占用”。而只是“m_hSocket”可不可以写(或读,取决你用哪个fd_set)。

当TCPIP在传数据的时候,只要传输缓存有空,select()一样返回(可写)。select()会阻塞,只有当缓存变满,再也不能写的时候。

即使远程序程不来接收数据,TCP同TCP之间没有问题,依然可以传递数据。数据传到远程后,会存在远程的“接收缓存”(rcv buf) 中。当远程的rcvbuf变满时,远程的TCP会通知本地TCP,本地TCP就暂停发送。如果本地程序连续发送,本地sndbuf会越来越满,最后导致发送被阻塞。

这整个过程中,没有重传超时,也就没有出错。

如果,远程机器重启,或是比方网络断了,TCP会重传,最后超时。这时,如果用户程序正在send/sendto/write,用户程序会出错返回。否则,用户程序会收到一个SIGPIPE的信号。用户程序如果预设了忽略SIGPIPE ( signal(SIGPIPE,SIGIGN),那么下一次用户程序写socket的时候会得到出错返回。

非常感谢xtang深入详细的讲解,我终于理清思路了。 :laughing:
顺便问一下:
有什么好的资料深入介绍了这方面的阿。我也学了Andrew S.Tanenbaum的computer networks。但是编程时,还是不清楚应该用哪个函数,会返回哪些信号. :slight_smile: 一般的网络编程的书讲的都比较一般化。 xtang 能不能推荐一下这方面的好书啊 :wink:

Very Thanks!