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

这篇具有很好参考价值的文章主要介绍了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 <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 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,退出
   /* string  clientString;
    do
    {
        getline(cin, clientString);

    } while (clientString != "exit" && clientString != "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<char*>(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 <string>
#include <winsock2.h>
#include <thread>
#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://www.toymoban.com/news/detail-693302.html

到了这里,关于C++ TCP/IP 关于tcp断线重连的问题的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • IP报文解析(TCP、UDP、 ICMP)及代码分享(C++)

    1.1 OSI 7层模型: 应用层: 功能:用户接口,文件传输、电子邮件、虚拟终端、文件服务 设备:网关 协议:HTTP、TFTP、SMTP、FTP、SNMP、DNS、Telnet 表示层: 功能:数据的表示,压缩和加密 设备:网关 协议:无 会话层: 功能:会话的建立和结束 设备:网关 协议:无 传输层:

    2024年02月09日
    浏览(43)
  • Linux网络编程——C++实现进程间TCP/IP通信

    地址接口 1、通用地址接口 共16字节 = 2字节地址类型 + 14字节地址数据 2、自定义地址接口 地址转换 1、需要将点分字符串ip转化为程序ip,使用inet_addr函数: 2、字节序转换 地址接口配置中的端口需要字节序转换,网络规定使用大端字节序。 地址接口配置 1、socket:创建套接

    2024年02月20日
    浏览(57)
  • C++网络通信实例(TCP/IP协议,包括服务端与客户端通信)

    创作不易 觉得有帮助请点赞关注收藏 TCP/IP是当下网络协议栈中的主流协议 TCP属于传输层的协议  可靠传输 包括经典的三次握手等等 IP协议是网络层协议 尽全力传输但不可靠 学过计算机网络的同学们对这个应该比较熟悉 以下是使用C++进行网络通信的实例  服务端 主要使用

    2024年02月14日
    浏览(50)
  • 基于C++和Qt封装一个简单的socket(TCP/IP)通信UI界面

            最近在学习TCP/IP和socket套接字的有关知识,了解了三次握手四次挥手,TCP协议等等一大堆知识,但纸上得来终觉浅。网络上C++代码实现socket通信的资料很多,方便学习,于是想到自己用Qt实现一个基础的具有网络通信收发功能的服务端UI软件。进入正题:        

    2024年02月08日
    浏览(55)
  • C++ Qt TCP协议,处理粘包、拆包问题,加上数据头来处理

    目录 前言: 场景: 原因: 解决: 方案2具体细节: 纯C++服务端处理如下: Qt客户端处理如下:         tcp协议里面,除了心跳检测是关于长连接操作的处理,这个在前一篇已经提到过了,这一篇将会对tcp本身的一个问题,进行处理:那就是做网络通信大概率会遇到的问题

    2024年02月04日
    浏览(57)
  • 2023.9.7 关于 TCP / IP 的基本认知

    目录 网络协议分层 TCP/IP 五层(四层)模型 应用层 传输层 网络层(互联网层) 数据链路层(网络接口层) 物理层  网络数据传输的基本流程 分层之后,类似于面向接口编程,定义好两层的接口规范,让双方遵循这个规范来对接,这样 有利于更好的扩展和维护 TCP/IP 是一种

    2024年02月09日
    浏览(27)
  • TCP重连 - 笔记

    1 C++ TCP/IP 关于tcp断线重连的问题 C++ TCP/IP 关于tcp断线重连的问题_c++ 断线重连_Bug猿柒。的博客-CSDN博客 2 C++基础--完善Socket C/S ,实现客户端,服务器端断开重连  https://www.cnblogs.com/kingdom_0/articles/2571727.html 3  C++实现Tcp通信(考虑客户端和服务端断开重连的情况)

    2024年02月13日
    浏览(19)
  • 关于TCP/IP协议的讲解及端口的介绍

    TCP协议(传输控制协议)和IP协议(网际协议)是计算机网络中两个重要的协议。它们在互联网通信中起着关键的作用。  TCP协议是一种传输层协议,建立在IP协议之上,提供可靠的、面向连接的数据传输。TCP协议使用端口号来标识不同的应用程序或服务。它通过创建一个虚拟

    2024年02月04日
    浏览(45)
  • Qt音视频开发36-超时检测和自动重连的设计

    如果网络环境正常设备正常,视频监控系统一般都是按照正常运行下去,不会出现什么问题,但是实际情况会很不同,奇奇怪怪七七八八的问题都会出现,就比如网络出了问题都有很多情况(交换机故障、网线故障、带宽故障等),所以监控系统在运行过程中,还得做超时检

    2023年04月13日
    浏览(46)
  • TCP/IP网络编程 第十六章:关于IO流分离的其他内容

    两次I/O流分离 我们之前通过2种方法分离过IO流,第一种是第十章的“TCPI/O过程(Routine)分离”。这种方法通过调用fork函数复制出1个文件描述符,以区分输入和输出中使用的文件描述符。虽然文件描述符本身不会根据输入和输出进行区分,但我们分开了2个文件描述符的用途

    2024年02月16日
    浏览(43)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包