好的,我们来详细理解一下 Error 10053 和 Error 10054 这两个网络错误码,常见于 Windows 下的网络编程,特别是使用 Winsock 或 TCP 连接时。


1. Error 10053 — Software caused connection abort

含义

  • 这个错误表示连接被本地软件(通常是你的程序或者操作系统)异常中止了。
  • 通常是应用层主动关闭连接,或者由于网络中断、超时等原因,导致本地网络栈中断了连接。

常见原因

  • 应用程序调用了 closesocket() 或者直接关闭了连接。
  • 应用程序超时未响应,操作系统为了释放资源主动关闭连接。
  • 防火墙或杀毒软件拦截了连接,强制关闭。
  • 网络不稳定,导致本地检测到错误并关闭连接。

典型场景

  • 客户端连接服务器时,中途客户端程序异常退出或者调用关闭。
  • 长时间无数据传输,某些设备或者操作系统超时关闭了连接。
  • 发送数据时本地网络栈检测到异常,终止连接。

2. Error 10054 — Connection reset by peer

含义

  • 连接被对端(远程主机)强制关闭,表现为“连接重置”。
  • 远程主机发送了 TCP RST(重置包),告诉本地主机连接异常被切断。

常见原因

  • 远程服务器程序崩溃、重启或异常退出。
  • 远程服务器主动调用关闭连接,且没有正常关闭流程。
  • 网络设备(防火墙、路由器)主动拒绝或重置连接。
  • 远程主机网络故障或重置连接。

典型场景

  • 客户端发送数据到服务器,服务器进程已关闭连接,返回 RST 包。
  • 远程主机超时未响应,主动断开连接。
  • 远程主机的防火墙策略拒绝当前连接。

3. 简单对比总结

错误码发生位置关闭主动方说明
10053本地本地主机本地软件主动中止连接
10054远端远程主机(对端)远程主机重置连接,强制关闭

4. 解决思路

  • 对于 10053
    • 检查本地应用程序是否合理关闭了套接字。
    • 排查防火墙、杀毒软件是否误拦截。
    • 增加超时和重连机制,避免长时间无响应被关闭。
  • 对于 10054
    • 检查服务器端程序是否异常退出或重启。
    • 查看服务器防火墙设置,是否主动拒绝连接。
    • 网络链路质量排查,避免中间设备断开。

好,给你准备了两个小工具示例,分别帮助你排查 Error 10053 和 Error 10054,以及示范如何在 Winsock 程序中捕获和处理这些错误。


1. 简单的网络状态检测脚本(Python)

这个脚本通过 TCP 连接目标服务器,检测连接是否正常,方便快速判断网络和服务器状态。

import socket
import sys

def test_connect(host, port):
    try:
        sock = socket.create_connection((host, port), timeout=5)
        print(f"连接成功: {host}:{port}")
        sock.close()
    except socket.timeout:
        print(f"连接超时: {host}:{port}")
    except ConnectionResetError:
        print(f"连接被远端重置 (Error 10054)")
    except ConnectionAbortedError:
        print(f"连接被本地中止 (Error 10053)")
    except Exception as e:
        print(f"连接失败: {e}")

if __name__ == "__main__":
    if len(sys.argv) != 3:
        print("用法: python test_connect.py <host> <port>")
        sys.exit(1)

    host = sys.argv[1]
    port = int(sys.argv[2])
    test_connect(host, port)

运行示例:

python test_connect.py 192.168.1.100 80

2. Winsock 错误捕获示例(C++)

演示如何在 Winsock TCP 客户端程序中捕获 10053 和 10054 错误,并做相应处理。

#include <winsock2.h>
#include <ws2tcpip.h>
#include <iostream>

#pragma comment(lib, "ws2_32.lib")

int main() {
    WSADATA wsaData;
    SOCKET sock = INVALID_SOCKET;
    sockaddr_in serverAddr;

    WSAStartup(MAKEWORD(2, 2), &wsaData);

    sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (sock == INVALID_SOCKET) {
        std::cerr << "socket error: " << WSAGetLastError() << std::endl;
        WSACleanup();
        return 1;
    }

    serverAddr.sin_family = AF_INET;
    serverAddr.sin_port = htons(80);
    inet_pton(AF_INET, "192.168.1.100", &serverAddr.sin_addr);

    int ret = connect(sock, (sockaddr*)&serverAddr, sizeof(serverAddr));
    if (ret == SOCKET_ERROR) {
        int err = WSAGetLastError();
        if (err == 10053) {
            std::cerr << "Error 10053: Connection aborted locally." << std::endl;
            // 处理本地中止逻辑
        } else if (err == 10054) {
            std::cerr << "Error 10054: Connection reset by peer." << std::endl;
            // 处理远程重置逻辑
        } else {
            std::cerr << "连接失败,错误码: " << err << std::endl;
        }
        closesocket(sock);
        WSACleanup();
        return 1;
    }

    // 连接成功,发送/接收代码

    closesocket(sock);
    WSACleanup();
    return 0;
}

3. 处理建议

  • 捕获到 10053 错误时,建议检查是否应用层逻辑关闭了套接字,或者添加重连逻辑。
  • 捕获到 10054 错误时,建议排查服务器端是否异常关闭连接,同时做好断线重连处理。

好,我给你写一个带自动重连机制的 WinSock TCP 客户端示例,示范如何捕获错误 10053、10054 并尝试重连。

#include <winsock2.h>
#include <ws2tcpip.h>
#include <iostream>
#include <thread>
#include <chrono>

#pragma comment(lib, "ws2_32.lib")

bool connect_to_server(SOCKET& sock, const sockaddr_in& serverAddr) {
    sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (sock == INVALID_SOCKET) {
        std::cerr << "Socket 创建失败,错误码:" << WSAGetLastError() << std::endl;
        return false;
    }
    if (connect(sock, (sockaddr*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR) {
        int err = WSAGetLastError();
        std::cerr << "连接失败,错误码:" << err << std::endl;
        closesocket(sock);
        sock = INVALID_SOCKET;
        return false;
    }
    std::cout << "连接服务器成功!" << std::endl;
    return true;
}

void run_client(const char* ip, unsigned short port) {
    WSADATA wsaData;
    if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
        std::cerr << "WSAStartup失败" << std::endl;
        return;
    }

    sockaddr_in serverAddr{};
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_port = htons(port);
    inet_pton(AF_INET, ip, &serverAddr.sin_addr);

    SOCKET sock = INVALID_SOCKET;
    const int max_retries = 5;
    int retry_count = 0;

    while (true) {
        if (sock == INVALID_SOCKET) {
            if (!connect_to_server(sock, serverAddr)) {
                retry_count++;
                if (retry_count > max_retries) {
                    std::cerr << "重连超过最大次数,退出程序" << std::endl;
                    break;
                }
                std::cout << "等待3秒后重连..." << std::endl;
                std::this_thread::sleep_for(std::chrono::seconds(3));
                continue;
            }
            retry_count = 0; // 成功连接,重置计数
        }

        // 发送数据示例
        const char* msg = "Hello server";
        int ret = send(sock, msg, (int)strlen(msg), 0);
        if (ret == SOCKET_ERROR) {
            int err = WSAGetLastError();
            std::cerr << "发送数据失败,错误码:" << err << std::endl;
            if (err == 10053) {
                std::cerr << "本地中止连接(10053),尝试重连" << std::endl;
            } else if (err == 10054) {
                std::cerr << "远程重置连接(10054),尝试重连" << std::endl;
            } else {
                std::cerr << "其他错误,退出" << std::endl;
                break;
            }
            closesocket(sock);
            sock = INVALID_SOCKET;
            continue;
        }

        // 接收数据示例(简化)
        char buf[512];
        ret = recv(sock, buf, sizeof(buf) - 1, 0);
        if (ret == 0) {
            std::cerr << "连接关闭,尝试重连" << std::endl;
            closesocket(sock);
            sock = INVALID_SOCKET;
            continue;
        } else if (ret == SOCKET_ERROR) {
            int err = WSAGetLastError();
            std::cerr << "接收数据失败,错误码:" << err << std::endl;
            if (err == 10053 || err == 10054) {
                std::cerr << "连接异常断开,尝试重连" << std::endl;
                closesocket(sock);
                sock = INVALID_SOCKET;
                continue;
            } else {
                std::cerr << "其他错误,退出" << std::endl;
                break;
            }
        } else {
            buf[ret] = '\0';
            std::cout << "收到数据: " << buf << std::endl;
        }

        std::this_thread::sleep_for(std::chrono::seconds(5)); // 模拟间隔
    }

    if (sock != INVALID_SOCKET) {
        closesocket(sock);
    }
    WSACleanup();
}

int main() {
    const char* server_ip = "192.168.1.100";
    unsigned short server_port = 80;

    run_client(server_ip, server_port);

    return 0;
}

说明:

  • 失败时针对错误 10053/10054 关闭 socket 并重连,最多重连 5 次。
  • 每次重连间隔 3 秒。
  • 简单模拟发送“Hello server”,接收数据。
  • 其他错误会退出程序。

明白!我帮你写一个基于之前代码的多线程版 Winsock TCP 客户端,包含:

  • 独立线程做连接和自动重连
  • 主线程处理数据收发
  • 线程安全退出机制
  • 错误日志写文件

#include <winsock2.h>
#include <ws2tcpip.h>
#include <iostream>
#include <thread>
#include <atomic>
#include <chrono>
#include <fstream>
#include <mutex>

#pragma comment(lib, "ws2_32.lib")

std::atomic<bool> running{ true };
std::mutex log_mutex;

void log_error(const std::string& msg) {
    std::lock_guard<std::mutex> lock(log_mutex);
    std::ofstream log("client_error.log", std::ios::app);
    log << msg << std::endl;
    std::cerr << msg << std::endl;
}

bool connect_to_server(SOCKET& sock, const sockaddr_in& serverAddr) {
    sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (sock == INVALID_SOCKET) {
        log_error("Socket 创建失败,错误码:" + std::to_string(WSAGetLastError()));
        return false;
    }
    if (connect(sock, (sockaddr*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR) {
        int err = WSAGetLastError();
        log_error("连接失败,错误码:" + std::to_string(err));
        closesocket(sock);
        sock = INVALID_SOCKET;
        return false;
    }
    std::cout << "连接服务器成功!" << std::endl;
    return true;
}

void connection_manager(SOCKET& sock, const sockaddr_in& serverAddr) {
    const int max_retries = 5;
    int retry_count = 0;

    while (running) {
        if (sock == INVALID_SOCKET) {
            if (!connect_to_server(sock, serverAddr)) {
                retry_count++;
                if (retry_count > max_retries) {
                    log_error("重连超过最大次数,停止连接管理线程");
                    running = false;
                    break;
                }
                log_error("等待3秒后重连...");
                std::this_thread::sleep_for(std::chrono::seconds(3));
                continue;
            }
            retry_count = 0;
        }
        std::this_thread::sleep_for(std::chrono::seconds(1));
    }
}

void data_handler(SOCKET& sock) {
    while (running) {
        if (sock == INVALID_SOCKET) {
            std::this_thread::sleep_for(std::chrono::milliseconds(200));
            continue;
        }

        // 发送示例
        const char* msg = "Hello server";
        int ret = send(sock, msg, (int)strlen(msg), 0);
        if (ret == SOCKET_ERROR) {
            int err = WSAGetLastError();
            log_error("发送失败,错误码:" + std::to_string(err));
            if (err == 10053 || err == 10054) {
                log_error("连接异常断开,准备重连");
                closesocket(sock);
                sock = INVALID_SOCKET;
                continue;
            } else {
                log_error("未知错误,停止程序");
                running = false;
                break;
            }
        }

        // 接收示例
        char buf[512];
        ret = recv(sock, buf, sizeof(buf) - 1, 0);
        if (ret == 0) {
            log_error("服务器关闭连接,准备重连");
            closesocket(sock);
            sock = INVALID_SOCKET;
            continue;
        }
        else if (ret == SOCKET_ERROR) {
            int err = WSAGetLastError();
            log_error("接收失败,错误码:" + std::to_string(err));
            if (err == 10053 || err == 10054) {
                log_error("连接异常断开,准备重连");
                closesocket(sock);
                sock = INVALID_SOCKET;
                continue;
            } else {
                log_error("未知错误,停止程序");
                running = false;
                break;
            }
        }
        else {
            buf[ret] = '\0';
            std::cout << "收到数据: " << buf << std::endl;
        }

        std::this_thread::sleep_for(std::chrono::seconds(5));
    }
}

int main() {
    WSADATA wsaData;
    if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
        log_error("WSAStartup失败");
        return 1;
    }

    sockaddr_in serverAddr{};
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_port = htons(80);
    inet_pton(AF_INET, "192.168.1.100", &serverAddr.sin_addr);

    SOCKET sock = INVALID_SOCKET;

    std::thread conn_thread(connection_manager, std::ref(sock), std::ref(serverAddr));
    std::thread data_thread(data_handler, std::ref(sock));

    std::cout << "按回车退出程序..." << std::endl;
    std::cin.get();

    running = false;

    conn_thread.join();
    data_thread.join();

    if (sock != INVALID_SOCKET) {
        closesocket(sock);
    }
    WSACleanup();

    return 0;
}

说明:

  • connection_manager 线程负责连接和重连,最多尝试 5 次失败后停止程序。
  • data_handler 线程负责数据收发,检测错误 10053 和 10054 后关闭连接,等待重连。
  • 采用 std::atomic<bool> 控制线程退出。
  • 所有错误日志写入 client_error.log,同时输出到控制台。
  • 主线程等待用户回车后,安全退出所有线程和清理资源。

好,这里帮你写一个简单的 CMakeLists.txt,用于编译上面那个多线程 Winsock TCP 客户端示例。这个配置适合 Windows 平台,使用 Visual Studio 或者命令行编译。


CMakeLists.txt

cmake_minimum_required(VERSION 3.10)

project(WinSockClientMultiThread LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

add_executable(WinSockClientMultiThread main.cpp)

# 链接 Winsock 库
target_link_libraries(WinSockClientMultiThread PRIVATE ws2_32)

使用步骤

  1. 把你写好的 C++ 代码保存为 main.cpp(与 CMakeLists.txt 同目录)。
  2. 打开命令行(PowerShell 或 cmd),进入项目目录。
  3. 生成 Visual Studio 解决方案(假设你安装了 Visual Studio 和 CMake):
mkdir build
cd build
cmake .. -G "Visual Studio 17 2022"   # 或根据你的 VS 版本替换生成器
  1. 编译:
  • 在 Visual Studio 里打开生成的解决方案,编译运行。
  • 或者直接用命令行编译:
cmake --build . --config Release
  1. 编译成功后,在 build/Release 目录下会生成 WinSockClientMultiThread.exe,直接运行。