在工控上经常用到tcp连接,比如串口服务器或某些支持modbustcp协议的仪表等,以前尽量使用串口服务器的虚拟串口功能,现在逐步使用上了tcpserver或tcpclient模式。
搜索了个C++ 的tcp断线重连的案例(http://www.cnblogs.com/kingdom_0/articles/2571727.html),使用这个的原因还因其使用的是收发多线程。server和client都很全,也许是作者的疏忽,client出现了明显的bug。如果掉线了,client的send和recv将重新建两个socket。
所以send和recv两个线程中的socket必须以指针形式传入,其次关闭socket不能用shutdown。经改进,目前已实现比较完美的断线(断开服务器程序和拔掉网线方式测试)自动连接功能。
完整client代码修改如下:
#define WIN32
#include <iostream>
#include <Winsock2.h>
#include <Windows.h>
#include <fstream>
#include <map>
#include <string>
#include <sstream>
#pragma comment(lib,"Ws2_32.lib")
using namespace std;
#define PORT 12345
#define IP_ADDRESS "192.168.1.5"
#include "ThreadLock.h"
//#define LISTEN_PORT 8081
//#define LISTEN_IP_ADDRESS "172.16.20.181"
//发送消息结构体
struct SendMsgStruct
{
SOCKET *clientSocket;
string msg;
struct sockaddr_in ServerAddr;
};
//接收消息结构体
struct RecvMsgStruct
{
SOCKET *clientSocket;
struct sockaddr_in ServerAddr;
};
DWORD WINAPI SendThread(LPVOID lpParameter);//发送消息子线程
DWORD WINAPI RecvThread(LPVOID lpParameter);//接收消息子线程
CThreadLock ctLock;
//---------------------------------------------------------------------------
#pragma argsused
int main(int argc, char *argv[])
{
WSADATA Ws;
SOCKET ClientSocket, ServerSocket;
struct sockaddr_in ServerAddr;
int Ret = 0;
HANDLE hSendThread = NULL;
HANDLE hRevcThread = NULL;
//The WSAStartup function initiates use of WS2_32.DLL by a process.
//初始化 Windows Socket
if ( WSAStartup(MAKEWORD(2, 2), &Ws) != 0 )
{
cout << "初始化 Socket 失败:" << GetLastError() << endl;
return -1;
}
//创建 Socket
ClientSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if ( ClientSocket == INVALID_SOCKET )
{
cout << "创建 Socket 失败:" << GetLastError() << endl;
return -1;
}
ServerAddr.sin_family = AF_INET;
ServerAddr.sin_addr.s_addr = inet_addr(IP_ADDRESS);
ServerAddr.sin_port = htons(PORT);
//设置ServerAddr中前8个字符为0x00
memset(ServerAddr.sin_zero, 0x00, 8);
Ret = connect(ClientSocket, (struct sockaddr *)&ServerAddr, sizeof(ServerAddr));
if( Ret == SOCKET_ERROR )
{
cout << "建立连接过程发生错误:" << GetLastError() << endl;
}
else
{
cout << "连接建立成功" << endl;
}
//创建一个子线程,用于向服务器端发送消息
struct SendMsgStruct *msgSend = new struct SendMsgStruct();
msgSend->clientSocket = &ClientSocket;
msgSend->msg = "你好,Msg From Client";
msgSend->ServerAddr = ServerAddr;
//传递一个struct
hSendThread = CreateThread(NULL, 0, SendThread, (LPVOID)msgSend, 0, NULL);
//WaitForSingleObject(hSendThread, INFINITE);
if( hSendThread == NULL )
{
cout << "创建发送消息子线程失败" << endl;
system("pause");
return -1;
}
//创建一个子线程,用于接收从服务器端发送过来的消息
struct RecvMsgSt