1. 用read函数来判断
读到长度0不能断定是已经断开.除非是-1,才代表输入流已经被关闭,说名socket已经close,而且关键在于你怎么读,实际上应该是一个单独的线程一直在读,因为你无法预先知道能不能一次将发过来的包读完,也无法知道一次是不是读完整了包,所以线称一直循环在读并且一直在解包.这样即能知道什么时候server断,也完成了消息的解读
// 判断是否连接
char ch = 'A';
if (read(g_sockfd, &ch, 1)<=0)
{
if (connect(g_sockfd,(struct sockaddr*)&g_serv_addr, sizeof(g_serv_addr) ) == 0)
{
ServiceLog.write_log("[NotifyDAU]:connect to DAU success.");
}
else
{
ServiceLog.write_log("[NotifyDAU]:can't connect to DAU ");
return;
}
}
用try{}catch{}是比较合适。
当他是连着的,当进行通讯时发生异常后就知道了.
当你不断的read的时候,server断,exception就catch到了。
2. 心跳包
可以在Client设一个定时器,每隔一段时间发一条消息给服务器,看能不能收到服务器的响应。
心跳包就是定时发包,没回应就判断断开。
3. getsockopt
(2014更新说明)最初以为使用这个方式很次,在最近一个项目需要用到getsockopt才又仔细去深入研究,发现当初自己的使用是存在问题的所以造成结果不准确。
使用getsockopt时,实际上是检查端口状态来间接判断连接是否成功,打个比方,有种情况你没用recv而是做send操作,这个时候如果你老是检查read状态是你会发现一直是失败的。根据状态来判断连接,使用好你要判断端口的哪个状态(以前我的问题就是出在这里)
bool Connected(const SOCKET socketfd)
{
if(socketfd == INVALID_SOCKET) return false;
struct timeval timeout;
timeout.tv_sec = 0;
timeout.tv_usec = 0;
fd_set fdwrite;
fd_set fdread;
FD_ZERO(&fdwrite);
FD_ZERO(&fdread);
FD_SET(socketfd,&fdwrite);
FD_SET(socketfd,&fdread);
int ret = select(socketfd+1, &fdread, &fdwrite, NULL, &timeout);
if(ret == -1)
return false;
if(ret > 0)
{
if(FD_ISSET(socketfd,&fdread))
return false;
else if(FD_ISSET(socketfd,&fdwrite))
{
int err = 0;
int len = sizeof(err);
int result = getsockopt(socketfd,SOL_SOCKET,SO_ERROR,(char*)&err,&len);
if(result < 0 || err != 0)
return false;
return true;
}
}
return false;
}