windows平台,vs2010IDE,C++编程语言
- 问题:socketTool软件建立Server,自编软件实现Client,在退出Client时,Server报下面的异常,如图1所示
图1
原因:
在建立Socket时,使用到了 SO_LINGER 选项,函数如下:
struct linger so_linger;
so_linger.l_onoff = 1;
so_linger.l_linger = 0;
setsockopt(sock->hSocket,SOL_SOCKET,SO_LINGER, (char *)&so_linger,sizeof(so_linger)); //关闭时直接关闭
linger的值为0,就会出现上面的问题。
解决方法:
关闭该功能,即onOff为0或者linger给大于0的值
- SO_LINGER
// 以下是转自: 老鱼_新浪博客点击打开链接
SO_LINGER,如果选择此选项, close或 shutdown将等到所有套接字里排队的消息成功发送或到达延迟时间后>才会返回. 否则, 调用将立即返回。
该选项的参数(option_value)是一个linger结构:struct linger {
int l_onoff;
int l_linger;
};
如果linger.l_onoff值为0(关闭),则清 sock->sk->sk_flag中的SOCK_LINGER位;否则,置该位,并赋sk->sk_lingertime值为 linger.l_linger。
- 我的工程示例程序
EXPORT_DLL void * DLL_EXPORT CreateNetMbDevice(char *strServerIP, unsigned short port)
{
char zero=0;
char NotZero = 1;
int BufSize=1500;
//int nZero=1500;
CMbDevice *dev = new CMbDevice;
//MbDeviceInit(dev); //初始化modbus设备
CMySocket *sock = new CMySocket;
//QTcpSocket *socket = new QTcpSocket;
//sock->hSocket=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
//初始化WSA
WORD sockVersion = MAKEWORD(2,2);
WSADATA wsaData;
if(WSAStartup(sockVersion, &wsaData)!=0)
{
delete dev;
delete sock;
DllDebugOut("WSAStartup failed:%d", GetLastError());
return(NULL);
}
//sock->hSocket=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
sock->hSocket=socket(AF_INET,SOCK_STREAM,0);
if(sock->hSocket==INVALID_SOCKET)
{
dev->param = NULL;
DllDebugOut("Invalid socket \n");
return(NULL);
}
#if 0
// linux下
struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = 200 * 1000;
#else
// windows下
int tv = SOCKETTIOMEOUT; // 超时时间
#endif
setsockopt(sock->hSocket, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(tv)); // 设置网络接收延时
setsockopt(sock->hSocket, SOL_SOCKET, SO_SNDTIMEO, (char *)&tv, sizeof(tv));
setsockopt(sock->hSocket, IPPROTO_TCP, TCP_NODELAY, (char *)&NotZero, 1); // 设置网络非延时传输
setsockopt(sock->hSocket, SOL_SOCKET, SO_SNDBUF, (char *)&BufSize, sizeof(BufSize));
setsockopt(sock->hSocket, SOL_SOCKET, SO_RCVBUF, (char *)&BufSize, sizeof(BufSize));
// 设置了该功能,则在测试时,退出时SocketTool会报错
struct linger so_linger;
so_linger.l_onoff = 1;
so_linger.l_linger = 0;
setsockopt(sock->hSocket,SOL_SOCKET,SO_LINGER, (char *)&so_linger,sizeof(so_linger)); //关闭时直接关闭
strcpy_s(sock->strServerIP,sizeof(sock->strServerIP),strServerIP);
sock->port = port;
dev->adu_type = ADU_TYPE_MBAP;
dev->pfnRead = net_read;
dev->pfnSend = net_send;
dev->retry_times = 3;
dev->server_addr = 1; //网络设备不需要该参数
dev->sem = new CSemaphore(1,1);
dev->param = sock;
//CMySocket *sock = (CMySocket *)dev->param;
SOCKADDR_IN addrSrv;
addrSrv.sin_addr.S_un.S_addr = inet_addr(sock->strServerIP); // 本机地址,服务器在本机开启
addrSrv.sin_family=AF_INET;
addrSrv.sin_port=htons(sock->port);// 设置端口号
if(connect(sock->hSocket, (SOCKADDR*)&addrSrv, sizeof(SOCKADDR))) // 连接服务器 应使用非阻塞式调用
{
printf("Socket connect error !");
closesocket(sock->hSocket);
delete dev;
delete sock;
return(NULL);
}
// 测试
char * sendData = "你好,TCP服务端,我是客户端!\n";
send(sock->hSocket, sendData, strlen(sendData), 0);
//connect(socket, SIGNAL(connected()), 0, SLOT(connectedSlot()));
//socket->SetTimeout(tmo_second);
return(dev);
}