利用Keep-Alive处理Socket网络异常断开的方法

来源:本站
导读:目前正在解读《利用Keep-Alive处理Socket网络异常断开的方法》的相关信息,《利用Keep-Alive处理Socket网络异常断开的方法》是由用户自行发布的知识型内容!下面请观看由(电工技术网 - www.9ddd.net)用户发布《利用Keep-Alive处理Socket网络异常断开的方法》的详细说明。
简介:今天讲一下网络方面的知识,希望对你的学习提供很好的帮助。

在写TCP/IPServer程时候,发现有时候网线拔了,没有办法检测网络异常,最后在网上找到,用Keep-Alive感觉还不错。

下面先说一下网络异常的种类有:

1、客户端程序异常。

对于这种情况,我们很好处理,因为客户端程序异常退出会在服务端引发ConnectionReset的Socket异常(就是WinSock2中的10054异常)。只要在服务端处理这个异常就可以了。

2、网络链路异常。

如:网线拔出、交换机掉电、客户端机器掉电。当出现这些情况的时候服务端不会出现任何异常。这样的话上面的代码就不能处理这种情况了。对于这种情况在MSDN里面是这样处理的,我在这里贴出MSDN的原文:如果您需要确定连接的当前状态,请进行非阻止、零字节的 Send 调用。如果该调用成功返回或引发 WAEWOULDBLOCK 错误代码 (10035),则该套接字仍然处于连接状态;否则,该套接字不再处于连接状态。

但是我在实际应用中发现,MSDN说的这种处理方法在很多时候根本无效,无法检测出网络已经异常断开了。那我们该怎么办呢?

我们知道,TCP有一个连接检测机制,就是如果在指定的时间内(一般为2个小时)没有数据传送,会给对端发送一个Keep-Alive数据报,使用的序列号是曾经发出的最后一个报文的最后一个字节的序列号,对端如果收到这个数据,回送一个TCP的ACK,确认这个字节已经收到,这样就知道此连接没有被断开。如果一段时间没有收到对方的响应,会进行重试,重试几次后,向对端发一个reset,然后将连接断掉。

下面是我对代码稍微修改一下实例,在VC6可以调通:

#pragma comment(lib, "ws2_32.lib")

#pragma comment(lib, "wsock32.lib")

#include <winsock2.h>

#include <windows.h>

#include <stdio.h>

#include <stdlib.h>

#include <iostream.h>

//以下宏需要自定义

#define SIO_RCVALL IOC_IN | IOC_VENDOR | 1

#define SIO_RCVALL_MCAST IOC_IN | IOC_VENDOR | 2

#define SIO_RCVALL_IGMPMCAST IOC_IN | IOC_VENDOR | 3

#define SIO_KEEPALIVE_VALS IOC_IN | IOC_VENDOR | 4

#define SIO_ABSORB_RTRALERT IOC_IN | IOC_VENDOR | 5

#define SIO_UCAST_IF IOC_IN | IOC_VENDOR | 6

#define SIO_LIMIT_BROADCASTS IOC_IN | IOC_VENDOR | 7

#define SIO_INDEX_BIND IOC_IN | IOC_VENDOR | 8

#define SIO_INDEX_MCASTIF IOC_IN | IOC_VENDOR | 9

#define SIO_INDEX_ADD_MCAST IOC_IN | IOC_VENDOR | 10

#define SIO_INDEX_DEL_MCAST IOC_IN | IOC_VENDOR | 11

//自定义的结构体

typedef struct tcp_keepalive

{

u_long onoff;//是否启用Keep-Alive

u_long keepalivetime;//多久时间后第一次探测(ms)

u_long keepaliveinterval;//探测时间间隔(ms)

}TCP_KEEPALIVE,*PTCP_KEEPALIVE;

int main()

{

WSADATA wsaData = {0};

if (WSAStartup(MAKEWORD(2,2), &wsaData) != 0)

{

cout << "WSAStartup failed. error code = " << WSAGetLastError() << endl;

cout << "Press any key exit." << endl;

getchar();

return 0;

}

SOCKET s = INVALID_SOCKET;

s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

if (s == INVALID_SOCKET)

{

cout << "socket failed. error code = " << WSAGetLastError() << endl;

}else

{

int iKeepAlive = -1;

int iOptLen = sizeof(iKeepAlive);

//取得SO_KEEPALIVE选项信息

if (getsockopt(s, SOL_SOCKET, SO_KEEPALIVE, (char *)&iKeepAlive, &iOptLen) == SOCKET_ERROR)

{

cout << "getsockopt failed. error code = " << WSAGetLastError() << endl;

}else

{

iKeepAlive = 1;

//这里设置成功的Keep Alive是针对操作系统的所有网络通信

if (setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, (char *)&iKeepAlive, iOptLen) == SOCKET_ERROR)

{

cout << "setsockopt failed. error code = " << WSAGetLastError() << endl;

}else

{

iKeepAlive = -1;

if(getsockopt(s, SOL_SOCKET, SO_KEEPALIVE, (char *)&iKeepAlive, &iOptLen) == SOCKET_ERROR)

{

cout << "getsockopt failed. error code = " << WSAGetLastError() << endl;

}else if (iKeepAlive == 1)

{

TCP_KEEPALIVE inKeepAlive = {0};

unsigned long ulInLen = sizeof(TCP_KEEPALIVE);

TCP_KEEPALIVE outKeepAlive = {0};

unsigned long ulOutLen = sizeof(TCP_KEEPALIVE);

unsigned long ulBytesReturn = 0;

//设置socket的keep alive为10秒,并且发送次数为3次

inKeepAlive.onoff = 1;

inKeepAlive.keepaliveinterval = 10000;

inKeepAlive.keepalivetime = 3;

//为选定的SOCKET设置Keep Alive,成功后SOCKET可通过Keep Alive自动检测连接是否断开

if (WSAIoctl(s, SIO_KEEPALIVE_VALS, (LPVOID)&inKeepAlive, ulInLen, (LPVOID)&outKeepAlive, ulOutLen, &ulBytesReturn, NULL, NULL) == SOCKET_ERROR)

{

//cout << "WSAIoctl failed. error code = " << WSAGetLastError() << endl;

}

}

}

}

}

WSACleanup();

cout << "Press any key exit." << endl;

getchar();

return 0;

}

提醒:《利用Keep-Alive处理Socket网络异常断开的方法》最后刷新时间 2024-03-14 01:12:48,本站为公益型个人网站,仅供个人学习和记录信息,不进行任何商业性质的盈利。如果内容、图片资源失效或内容涉及侵权,请反馈至,我们会及时处理。本站只保证内容的可读性,无法保证真实性,《利用Keep-Alive处理Socket网络异常断开的方法》该内容的真实性请自行鉴别。