AUST自助上网_CPP

Ubanillx 发布于 2024-11-10 659 次阅读


#include <iostream>
#include <fstream>
#include <string>
#include <map>
#include <curl/curl.h>
#include <thread>
#include <atomic>
#include <chrono>

// 读取 .config 文件,并将配置存储到 map 中
std::map<std::string, std::string> readConfigFile(const std::string& filename) {
    std::map<std::string, std::string> config;
    std::ifstream file(filename);

    if (!file.is_open()) {
        std::cerr << "无法打开文件: " << filename << std::endl;
        return config;
    }

    std::string line;
    while (std::getline(file, line)) {
        if (line.empty() || line[0] == '#') continue;

        size_t delimiterPos = line.find('=');
        if (delimiterPos != std::string::npos) {
            std::string key = line.substr(0, delimiterPos);
            std::string value = line.substr(delimiterPos + 1);

            key.erase(0, key.find_first_not_of(" \t"));
            key.erase(key.find_last_not_of(" \t") + 1);
            value.erase(0, value.find_first_not_of(" \t"));
            value.erase(value.find_last_not_of(" \t") + 1);

            config[key] = value;
        }
    }
    file.close();
    return config;
}

// 写入 .config 文件
void writeConfigFile(const std::string& filename, const std::map<std::string, std::string>& config) {
    std::ofstream file(filename);

    if (!file.is_open()) {
        std::cerr << "无法打开文件: " << filename << std::endl;
        return;
    }

    for (const auto& entry : config) {
        file << entry.first << "=" << entry.second << std::endl;
    }

    file.close();
}

// 收集服务器响应内容
size_t WriteCallback(void* contents, size_t size, size_t nmemb, void* userp) {
    ((std::string*)userp)->append((char*)contents, size * nmemb);
    return size * nmemb;
}

// 发送 POST 请求的函数
void sendPostRequest(const std::string& url, const std::string& user, const std::string& password, const std::string& server) {
    CURL* curl;
    CURLcode res;
    long http_code = 0;

    std::string data = "callback=dr1003&DDDDD=" + user + "@" + server +
        "&upass=" + password + "&0MKKey=123456&R1=0&R3=0&R6=0&para=00&v6ip=&v=";

    std::cout << "发送的数据: " << data << std::endl;

    std::string response; // 用于存储服务器响应
    curl = curl_easy_init();
    if (curl) {
        curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
        curl_easy_setopt(curl, CURLOPT_POST, 1L);
        curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data.c_str());

        // 设置Content-Type头
        struct curl_slist* headers = nullptr;
        headers = curl_slist_append(headers, "Content-Type: application/x-www-form-urlencoded");
        curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);

        // 设置接收响应的回调
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);

        res = curl_easy_perform(curl);
        curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code);

        if (res != CURLE_OK) {
            std::cerr << "curl_easy_perform() failed: " << curl_easy_strerror(res) << std::endl;
        }
        else {
            std::cout << "HTTP 状态码: " << http_code << std::endl;
        }

        curl_slist_free_all(headers);
        curl_easy_cleanup(curl);
    }
    else {
        std::cerr << "初始化 curl 失败!" << std::endl;
    }
}

// 使用 HTTP 状态码验证是否连接到外部网络
bool checkInternetConnection() {
    CURL* curl;
    CURLcode res;
    long http_code = 0;
    bool isConnected = false;

    curl = curl_easy_init();
    if (curl) {
        curl_easy_setopt(curl, CURLOPT_URL, "http://www.baidu.com");
        curl_easy_setopt(curl, CURLOPT_TIMEOUT, 2L); // 设置超时为 2 秒
        curl_easy_setopt(curl, CURLOPT_NOBODY, 1L); // 仅请求头部
        res = curl_easy_perform(curl);

        if (res == CURLE_OK) {
            curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code);
            if (http_code == 200) {
                isConnected = true;
            }
        }

        curl_easy_cleanup(curl);
    }
    return isConnected;
}

// 检查用户输入并判断是否退出程序
std::atomic<bool> stopFlag(false);
void userInputThread() {
    std::string userInput;
    while (!stopFlag) {
        std::cin >> userInput;
        if (userInput == "q" || userInput == "Q") {
            stopFlag = true;
        }
    }
}

int main() {
    std::string configFileName = ".config";
    std::map<std::string, std::string> config = readConfigFile(configFileName);

    if (config.empty()) {
        std::cout << "未找到配置文件或配置为空,请输入以下信息以生成配置文件:" << std::endl;

        std::cout << "学号: ";
        std::cin >> config["user"];
        std::cout << "密码: ";
        std::cin >> config["password"];
        std::cout << "运营商 (电信:aust, 联通:unicom, 移动:cmcc): ";
        std::cin >> config["server"];
        config["url"] = "http://10.255.0.19/a79.htm";
        std::cout << "配置文件已生成。" << std::endl;

        writeConfigFile(configFileName, config);
    }

    std::string user = config["user"];
    std::string password = config["password"];
    std::string server = config["server"];
    std::string url = config.count("url") > 0 ? config["url"] : "http://10.255.0.19/a79.htm";

    std::thread inputThread(userInputThread);

    // 主循环检查网络连接状态
    while (!stopFlag) {
        if (checkInternetConnection()) {
            std::cout << "\r已连接到Internet" << std::flush;
        }
        else {
            std::cout << "\r未连接到Internet, 正在尝试重新连接..." << std::flush;
            sendPostRequest(url, user, password, server);
        }
        std::this_thread::sleep_for(std::chrono::seconds(1));
    }

    if (inputThread.joinable()) {
        inputThread.join();
    }

    return 0;
}

嗨!欢迎来到我的小世界。 我是来自安徽理工大学的一名计算机学生,一个在代码和咖啡之间穿梭的数字游民。我的技术旅程始于 Java 的严谨逻辑,在 Python 的优雅中找到了快速实现的乐趣,然后又被 React 和 Vue 的前端魅力深深吸引。我喜欢从零开始,用代码构建一个完整的应用,从后端的服务设计到前端的像素级实现,每一步都充满挑战与创造的快感。 我坚信生活不止眼前的 bug,还有诗和远方。我的镜头记录着校园四季的变幻,也捕捉着城市街头的光影故事。当你在这里看到一些关于摄影的分享,请不要惊讶,那是我在代码之外的另一种表达方式。此外,我还喜欢在周末骑着单车,穿梭于乡间小道,享受风带来的自由。这些爱好让我保持着对世界的好奇心和对生活的热情。 这个博客是我分享技术心得、记录成长轨迹、展示个人爱好的地方。在这里,你可能会看到: Java、Python、React、Vue 等技术深度解析 项目开发中的踩坑记录与解决方案 摄影作品与拍摄技巧分享 户外骑行或徒步的游记随笔
最后更新于 2024-11-10