加-lws2_32

#include <iostream>
#include <string>
#include <cstring>
#include <winsock2.h>
#include <windows.h>
#include <process.h>

#ifdef __GNUC__
#pragma comment(lib, "ws2_32")
#endif

using namespace std;

// 全局变量
bool g_running = true;
SOCKET g_sock = INVALID_SOCKET;
sockaddr_in g_remote_addr;

// 接收线程函数
unsigned int __stdcall ReceiveThreadFunc(void* pArg) {
    char buffer[1024];
    sockaddr_in senderAddr;
    int senderAddrLen = sizeof(senderAddr);

    while (g_running) {
        memset(buffer, 0, sizeof(buffer));
        
        // 接收数据
        int result = recvfrom(g_sock, buffer, sizeof(buffer) - 1, 0, 
                              (sockaddr*)&senderAddr, &senderAddrLen);
        
        if (result > 0) {
            // 成功收到消息
            cout << "\r[收到] " << buffer << "                \r"; 
            cout << "[发送] ";
            fflush(stdout); 
        } 
        else if (result == SOCKET_ERROR) {
            int errCode = WSAGetLastError();
            
            // 【关键修改】如果是 10054 (连接重置),通常是因为之前发送的数据对方没收
            // 我们不应该退出,而是应该忽略这次错误,继续循环等待
            if (errCode == WSAECONNRESET) {
                // 可以选择打印一个看不见的字符刷新界面,或者什么都不做
                // cerr << "\r[系统] 远程主机重置连接(10054),请检查对方是否在线..." << endl; 
                continue; 
            }
            // 如果是 Socket 被关闭导致的错误,则退出线程
            else if (errCode == WSAENOTSOCK) {
                break;
            }
            // 其他错误
            else {
                cerr << "\r[系统] 接收错误: " << errCode << "                \r";
                cerr << "[发送] ";
                fflush(stdout);
            }
        }
        Sleep(100);
    }
    return 0;
}

int main() {
    cout << "=== 局域网UDP聊天室 (C++98版) ===" << endl;

    // 1. 初始化 Winsock
    WSADATA wsaData;
    if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
        cout << "WSA初始化失败!" << endl;
        return -1;
    }

    // 2. 创建 Socket
    g_sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    if (g_sock == INVALID_SOCKET) {
        cout << "Socket创建失败!" << endl;
        WSACleanup();
        return -1;
    }

    // 3. 绑定本地端口
    sockaddr_in localAddr;
    memset(&localAddr, 0, sizeof(localAddr));
    localAddr.sin_family = AF_INET;
    localAddr.sin_port = htons(60001); 
    localAddr.sin_addr.s_addr = INADDR_ANY; 

    if (bind(g_sock, (sockaddr*)&localAddr, sizeof(localAddr)) == SOCKET_ERROR) {
        cout << "绑定端口失败! 可能是端口被占用。" << endl;
        closesocket(g_sock);
        WSACleanup();
        return -1;
    }

    // 4. 设置目标IP
    string targetIP;
    int targetPort = 60001; 

    cout << "请输入对方IP地址: ";
    cin >> targetIP;
    cin.ignore(); 

    memset(&g_remote_addr, 0, sizeof(g_remote_addr));
    g_remote_addr.sin_family = AF_INET;
    g_remote_addr.sin_port = htons(targetPort);
    g_remote_addr.sin_addr.s_addr = inet_addr(targetIP.c_str());

    if (g_remote_addr.sin_addr.s_addr == INADDR_NONE) {
        cout << "无效的IP地址!" << endl;
        closesocket(g_sock);
        WSACleanup();
        return -1;
    }

    cout << "已连接到 " << targetIP << ":" << targetPort << endl;
    cout << "开始聊天 (输入 'exit' 退出):" << endl;

    // 5. 启动线程
    unsigned int threadID;
    HANDLE hThread = (HANDLE)_beginthreadex(NULL, 0, ReceiveThreadFunc, NULL, 0, &threadID);

    // 6. 主循环
    string msg;
    while (g_running) {
        cout << "[发送] ";
        getline(cin, msg); 

        if (msg == "exit") {
            g_running = false;
            break;
        }

        if (!msg.empty()) {
            int sendResult = sendto(g_sock, msg.c_str(), msg.length(), 0, 
                                    (sockaddr*)&g_remote_addr, sizeof(g_remote_addr));
            if (sendResult == SOCKET_ERROR) {
                // 发送也可能报 10054,如果此时网络不通
                int err = WSAGetLastError();
                if(err == WSAECONNRESET) {
                     cout << "[系统] 警告:发送失败,对方可能未开启或未响应(10054)" << endl;
                }
            }
        }
    }

    // 7. 清理
    closesocket(g_sock); 
    if (hThread) {
        WaitForSingleObject(hThread, 2000); 
        CloseHandle(hThread);
    }

    WSACleanup();
    return 0;
}