国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

C++ TCP/IP 關于tcp斷線重連的問題

這篇具有很好參考價值的文章主要介紹了C++ TCP/IP 關于tcp斷線重連的問題。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

在工控上經常用到tcp連接,比如串口服務器或某些支持modbustcp協(xié)議的儀表等,以前盡量使用串口服務器的虛擬串口功能,現(xiàn)在逐步使用上了tcpserver或tcpclient模式。

搜索了個C++ 的tcp斷線重連的案例(http://www.cnblogs.com/kingdom_0/articles/2571727.html),使用這個的原因還因其使用的是收發(fā)多線程。server和client都很全,也許是作者的疏忽,client出現(xiàn)了明顯的bug。如果掉線了,client的send和recv將重新建兩個socket。

所以send和recv兩個線程中的socket必須以指針形式傳入,其次關閉socket不能用shutdown。經改進,目前已實現(xiàn)比較完美的斷線(斷開服務器程序和拔掉網(wǎng)線方式測試)自動連接功能。

完整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"http://線程自動鎖 ThreadLock.h 

WSADATA  Ws;
SOCKET ClientSocket;
struct sockaddr_in ServerAddr;
int Ret = 0;

HANDLE hSendThread = NULL;
HANDLE hRevcThread = NULL;

//發(fā)送消息結構體
struct SendMsgStruct
{
    SOCKET* clientSocket;
    string msg;
    struct sockaddr_in ServerAddr;
};

//接收消息結構體
struct RecvMsgStruct
{
    SOCKET* clientSocket;
    struct sockaddr_in ServerAddr;
};

DWORD WINAPI SendThread(LPVOID lpParameter);//發(fā)送消息子線程
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;
    }

    //創(chuàng)建 Socket
    ClientSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (ClientSocket == INVALID_SOCKET)
    {
        cout << "創(chuàng)建 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 << "建立連接過程發(fā)生錯誤:" << GetLastError() << endl;
    }
    else
    {
        cout << "連接建立成功" << endl;
    }

    //創(chuàng)建一個子線程,用于向服務器端發(fā)送消息
    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 << "創(chuàng)建發(fā)送消息子線程失敗" << endl;
        system("pause");
        return -1;
    }

    //創(chuàng)建一個子線程,用于接收從服務器端發(fā)送過來的消息
    struct RecvMsgStruct* msgRecv = new struct RecvMsgStruct();
    msgRecv->clientSocket = &ClientSocket;
    msgRecv->ServerAddr = ServerAddr;
    //傳遞一個struct指針參數(shù)
    hRevcThread = CreateThread(NULL, 0, RecvThread, (LPVOID)msgRecv, 0, NULL);
    //WaitForSingleObject(hRevcThread, INFINITE);

    if (hRevcThread == NULL)
    {
        cout << "創(chuàng)建接收消息子線程失敗" << endl;
        system("pause");
        return -1;
    }

    //客戶端輸入exit,退出
   /* string  clientString;
    do
    {
        getline(cin, clientString);

    } while (clientString != "exit" && clientString != "EXIT");*/

    closesocket(ClientSocket);
    WSACleanup();
}

//發(fā)送消息子線程
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秒發(fā)送一次
    }
    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 << "建立連接發(fā)生錯誤,錯誤代碼:" << 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"http://發(fā)送屬性實體(根據(jù)需求自定義變量即可)
#include "TcpDatas.h"http://接收屬性實體(根據(jù)需求自定義變量即可)
#include "Totype.h"http://類型轉化函數(shù)類

class ClientTcp
{
public:
    ClientTcp(std::string strIp, unsigned int uPort);
    virtual ~ClientTcp();

    //初始化網(wǎng)絡服務端
    bool InitClient(); 

private:
    unsigned int m_uPort;//監(jiān)聽端口
    std::string m_strIp;//用于監(jiān)聽本機指定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文章來源地址http://www.zghlxwxcb.cn/news/detail-693302.html

到了這里,關于C++ TCP/IP 關于tcp斷線重連的問題的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。如若轉載,請注明出處: 如若內容造成侵權/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經查實,立即刪除!

領支付寶紅包贊助服務器費用

相關文章

  • Linux網(wǎng)絡編程——C++實現(xiàn)進程間TCP/IP通信

    地址接口 1、通用地址接口 共16字節(jié) = 2字節(jié)地址類型 + 14字節(jié)地址數(shù)據(jù) 2、自定義地址接口 地址轉換 1、需要將點分字符串ip轉化為程序ip,使用inet_addr函數(shù): 2、字節(jié)序轉換 地址接口配置中的端口需要字節(jié)序轉換,網(wǎng)絡規(guī)定使用大端字節(jié)序。 地址接口配置 1、socket:創(chuàng)建套接

    2024年02月20日
    瀏覽(33)
  • IP報文解析(TCP、UDP、 ICMP)及代碼分享(C++)

    IP報文解析(TCP、UDP、 ICMP)及代碼分享(C++)

    1.1 OSI 7層模型: 應用層: 功能:用戶接口,文件傳輸、電子郵件、虛擬終端、文件服務 設備:網(wǎng)關 協(xié)議:HTTP、TFTP、SMTP、FTP、SNMP、DNS、Telnet 表示層: 功能:數(shù)據(jù)的表示,壓縮和加密 設備:網(wǎng)關 協(xié)議:無 會話層: 功能:會話的建立和結束 設備:網(wǎng)關 協(xié)議:無 傳輸層:

    2024年02月09日
    瀏覽(23)
  • 基于C++和Qt封裝一個簡單的socket(TCP/IP)通信UI界面

    基于C++和Qt封裝一個簡單的socket(TCP/IP)通信UI界面

    ????????最近在學習TCP/IP和socket套接字的有關知識,了解了三次握手四次揮手,TCP協(xié)議等等一大堆知識,但紙上得來終覺淺。網(wǎng)絡上C++代碼實現(xiàn)socket通信的資料很多,方便學習,于是想到自己用Qt實現(xiàn)一個基礎的具有網(wǎng)絡通信收發(fā)功能的服務端UI軟件。進入正題: ? ? ? ?

    2024年02月08日
    瀏覽(21)
  • C++網(wǎng)絡通信實例(TCP/IP協(xié)議,包括服務端與客戶端通信)

    C++網(wǎng)絡通信實例(TCP/IP協(xié)議,包括服務端與客戶端通信)

    創(chuàng)作不易 覺得有幫助請點贊關注收藏 TCP/IP是當下網(wǎng)絡協(xié)議棧中的主流協(xié)議 TCP屬于傳輸層的協(xié)議? 可靠傳輸 包括經典的三次握手等等 IP協(xié)議是網(wǎng)絡層協(xié)議 盡全力傳輸?shù)豢煽?學過計算機網(wǎng)絡的同學們對這個應該比較熟悉 以下是使用C++進行網(wǎng)絡通信的實例? 服務端 主要使用

    2024年02月14日
    瀏覽(20)
  • C++ Qt TCP協(xié)議,處理粘包、拆包問題,加上數(shù)據(jù)頭來處理

    目錄 前言: 場景: 原因: 解決: 方案2具體細節(jié): 純C++服務端處理如下: Qt客戶端處理如下: ? ? ? ? tcp協(xié)議里面,除了心跳檢測是關于長連接操作的處理,這個在前一篇已經提到過了,這一篇將會對tcp本身的一個問題,進行處理:那就是做網(wǎng)絡通信大概率會遇到的問題

    2024年02月04日
    瀏覽(22)
  • 2023.9.7 關于 TCP / IP 的基本認知

    2023.9.7 關于 TCP / IP 的基本認知

    目錄 網(wǎng)絡協(xié)議分層 TCP/IP 五層(四層)模型 應用層 傳輸層 網(wǎng)絡層(互聯(lián)網(wǎng)層) 數(shù)據(jù)鏈路層(網(wǎng)絡接口層) 物理層 ?網(wǎng)絡數(shù)據(jù)傳輸?shù)幕玖鞒?分層之后,類似于面向接口編程,定義好兩層的接口規(guī)范,讓雙方遵循這個規(guī)范來對接,這樣 有利于更好的擴展和維護 TCP/IP 是一種

    2024年02月09日
    瀏覽(70)
  • TCP重連 - 筆記

    1?C++ TCP/IP 關于tcp斷線重連的問題 C++ TCP/IP 關于tcp斷線重連的問題_c++ 斷線重連_Bug猿柒。的博客-CSDN博客 2?C++基礎--完善Socket C/S ,實現(xiàn)客戶端,服務器端斷開重連? https://www.cnblogs.com/kingdom_0/articles/2571727.html 3??C++實現(xiàn)Tcp通信(考慮客戶端和服務端斷開重連的情況)

    2024年02月13日
    瀏覽(8)
  • 關于TCP/IP協(xié)議的講解及端口的介紹

    TCP協(xié)議(傳輸控制協(xié)議)和IP協(xié)議(網(wǎng)際協(xié)議)是計算機網(wǎng)絡中兩個重要的協(xié)議。它們在互聯(lián)網(wǎng)通信中起著關鍵的作用。 ?TCP協(xié)議是一種傳輸層協(xié)議,建立在IP協(xié)議之上,提供可靠的、面向連接的數(shù)據(jù)傳輸。TCP協(xié)議使用端口號來標識不同的應用程序或服務。它通過創(chuàng)建一個虛擬

    2024年02月04日
    瀏覽(20)
  • Qt音視頻開發(fā)36-超時檢測和自動重連的設計

    Qt音視頻開發(fā)36-超時檢測和自動重連的設計

    如果網(wǎng)絡環(huán)境正常設備正常,視頻監(jiān)控系統(tǒng)一般都是按照正常運行下去,不會出現(xiàn)什么問題,但是實際情況會很不同,奇奇怪怪七七八八的問題都會出現(xiàn),就比如網(wǎng)絡出了問題都有很多情況(交換機故障、網(wǎng)線故障、帶寬故障等),所以監(jiān)控系統(tǒng)在運行過程中,還得做超時檢

    2023年04月13日
    瀏覽(31)
  • TCP/IP網(wǎng)絡編程 第十六章:關于IO流分離的其他內容

    TCP/IP網(wǎng)絡編程 第十六章:關于IO流分離的其他內容

    兩次I/O流分離 我們之前通過2種方法分離過IO流,第一種是第十章的“TCPI/O過程(Routine)分離”。這種方法通過調用fork函數(shù)復制出1個文件描述符,以區(qū)分輸入和輸出中使用的文件描述符。雖然文件描述符本身不會根據(jù)輸入和輸出進行區(qū)分,但我們分開了2個文件描述符的用途

    2024年02月16日
    瀏覽(29)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領取紅包,優(yōu)惠每天領

二維碼1

領取紅包

二維碼2

領紅包