我的编程空间,编程开发者的网络收藏夹
学习永远不晚

C++ TCP/IP 关于tcp断线重连的问题

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

C++ TCP/IP 关于tcp断线重连的问题

在工控上经常用到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代码cpp文件如下:

include #include #include #include #include #include #include #pragma comment(lib,"Ws2_32.lib")using namespace std;#define PORT 6100#define IP_ADDRESS "127.0.0.1"#include "ClientTcp.h"#include "ThreadLock.h"//线程自动锁 ThreadLock.h WSADATA  Ws;SOCKET ClientSocket;struct sockaddr_in ServerAddr;int Ret = 0;HANDLE hSendThread = NULL;HANDLE hRevcThread = NULL;//发送消息结构体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);//接收消息子线程ClientTcp::ClientTcp(std::string strIp, unsigned int uPort) :    m_strIp(strIp),    m_uPort(uPort){}ClientTcp::~ClientTcp(){       if (ClientSocket)       {           closesocket(ClientSocket);           ClientSocket = NULL;       }}bool ClientTcp::InitClient(){    //初始化 Windows Socket    if (WSAStartup(MAKEWORD(2, 2), &Ws) != 0)    {       std::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 RecvMsgStruct* msgRecv = new struct RecvMsgStruct();    msgRecv->clientSocket = &ClientSocket;    msgRecv->ServerAddr = ServerAddr;    //传递一个struct指针参数    hRevcThread = CreateThread(NULL, 0, RecvThread, (LPVOID)msgRecv, 0, NULL);    //WaitForSingleObject(hRevcThread, INFINITE);    if (hRevcThread == NULL)    {        cout << "创建接收消息子线程失败" << endl;        system("pause");        return -1;    }    //客户端输入exit,退出       closesocket(ClientSocket);    WSACleanup();}//发送消息子线程DWORD WINAPI SendThread(LPVOID lpParameter){    SendMsgStruct* myStruct = (SendMsgStruct*)lpParameter;    SOCKET* ClientSocket = myStruct->clientSocket;    string SendMsg = myStruct->msg;    struct sockaddr_in ServerAddr = myStruct->ServerAddr;    while (true)    {        int flag = 0;        int bufSize = SendMsg.length();        char* buf = const_cast(SendMsg.c_str());        {            CAutoLock ALock(&ctLock);            flag = send(*ClientSocket, buf, bufSize, 0);            //判断当前时候存在可用连接,如果没有,再次连接            while (flag == SOCKET_ERROR || flag == 0)            {                cout << "准备重连" << endl;                closesocket(*ClientSocket);                *ClientSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);                if (connect(*ClientSocket, (struct sockaddr*)&ServerAddr, sizeof(ServerAddr)) == SOCKET_ERROR)                {                    cout << "重连失败 :" << GetLastError() << endl;                    Sleep(5000);                }                else                {                    break;                }            }            if (flag < bufSize)            {                flag = send(*ClientSocket, buf, bufSize - flag, 0);            }            else    //传输成功            {                cout << "\n消息传输成功" << endl;            }        }        Sleep(2000);       //每2秒发送一次    }    return 0;}//接收消息子线程DWORD WINAPI RecvThread(LPVOID lpParameter){    RecvMsgStruct* recvStruct = (RecvMsgStruct*)lpParameter;    SOCKET* ClientSocket = recvStruct->clientSocket;    struct sockaddr_in ServerAddr = recvStruct->ServerAddr;    while (true)    {        char recvBuf[500] = { "0" };        int byteRecv = recv(*ClientSocket, recvBuf, 500, 0);        CAutoLock ALock(&ctLock);        int connectState;        while (byteRecv == 0 || byteRecv == SOCKET_ERROR)        {            //连接断开,重连            cout << "byteRecv <= 0" << endl;             closesocket(*ClientSocket);            *ClientSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);            connectState = connect(*ClientSocket, (struct sockaddr*)&ServerAddr, sizeof(ServerAddr));            if (connectState == SOCKET_ERROR)            {                cout << "建立连接发生错误,错误代码:" << GetLastError() << endl;            }            else            {                cout << "重连成功!!!!!!!" << endl;                break;            }            Sleep(5000);        }        cout << recvBuf << endl;    }    return 0;}

H头文件中代码如下:

#pragma once#include #include #include #pragma comment(lib,"ws2_32")//Standard socket API.#include "sendByte.h"//发送属性实体(根据需求自定义变量即可)#include "TcpDatas.h"//接收属性实体(根据需求自定义变量即可)#include "Totype.h"//类型转化函数类class ClientTcp{public:    ClientTcp(std::string strIp, unsigned int uPort);    virtual ~ClientTcp();    //初始化网络服务端    bool InitClient(); private:    unsigned int m_uPort;//监听端口    std::string m_strIp;//用于监听本机指定IP地址  }; 

入口文件中调用:

void TcpClientRun(){    ClientTcp clienttcp("192.168.124.3", 6100);    if (!clienttcp.InitClient())    {        getchar();    }}int main(int argc, char* argv[]){    std::thread CTcpTh(TcpClientRun);    this_thread::sleep_for(std::chrono::milliseconds(1000));    CTcpTh.join();    return 0;  }

这样就可以了 

线程自动锁 ThreadLock.h 选用https://www.cnblogs.com/pilipalajun/p/5415673.html

本文主要参考原文链接:https://blog.csdn.net/gongzhu110/article/details/83147994

来源地址:https://blog.csdn.net/qiuyuanxiang1230/article/details/130487710

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

C++ TCP/IP 关于tcp断线重连的问题

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

关于Java单个TCP(Socket)连接发送多个文件的问题

这篇文章主要介绍了关于Java单个TCP(Socket)连接发送多个文件的问题,每次我只能使用一个Socket发送一个文件,没有办法做到连续发送文件,本文来解决这个问题,需要的朋友可以参考下
2023-05-15

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录