You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Wii平台devKitPro创建Socket报错:Illegal byte sequence求助

Wii网页服务器Socket初始化报错:Illegal byte sequence 解决方案

核心问题诊断

Illegal byte sequence错误本质是devKitPro的Wii网络API(libogc)对POSIX socket接口的兼容存在细节差异,加上部分初始化流程缺失、参数使用不当导致的。以下是针对性修复步骤:


1. 补全完整的Wii网络初始化流程

devKitPro的网络栈需要完成全局初始化才能正常创建socket,在WebServer::Run()开头添加:

// 初始化Wii网络栈
if (!net_init()) {
    perror("net_init failed");
    exit(EXIT_FAILURE);
}

// 获取本地IP(可选,确保网络栈完全就绪)
struct in_addr ip_addr;
if (net_gethostip(&ip_addr) < 0) {
    perror("net_gethostip failed");
    exit(EXIT_FAILURE);
}

2. 修正Socket创建参数与错误判断

libogc的net_socket要求显式指定TCP协议,且失败返回-1而非0,修正代码:

// 创建TCP Socket,显式指定IPPROTO_TCP,错误判断改为<0
if ((server = net_socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
    perror("socket failed");
    exit(EXIT_FAILURE);
}

3. 拆分SO_REUSEADDR与SO_REUSEPORT选项

部分嵌入式平台不支持同时设置两个复用选项,分开调用:

int opt = 1;
// 设置SO_REUSEADDR
if (net_setsockopt(server, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) {
    perror("setsockopt SO_REUSEADDR failed");
    exit(EXIT_FAILURE);
}
// 设置SO_REUSEPORT(不支持可注释)
if (net_setsockopt(server, SOL_SOCKET, SO_REUSEPORT, &opt, sizeof(opt)) < 0) {
    perror("setsockopt SO_REUSEPORT failed");
    // exit(EXIT_FAILURE);
}

4. 显式转换INADDR_ANY字节序

严格遵循Wii平台要求,对INADDR_ANY执行字节序转换:

address.sin_addr.s_addr = htonl(INADDR_ANY);

5. 使用net_前缀IO函数替换标准接口

Wii的socket文件描述符不兼容标准read()/write(),必须使用对应net_前缀函数:

// 替换read为net_read
valread = net_read(ssocket, buffer, 1024);

// 替换write为net_write
net_write(ssocket, response.c_str(), response.size());

// 替换close为net_close
net_close(ssocket);

6. 修复FAT子系统重复初始化问题

将fatInitDefault()移到Run()开头,仅执行一次:

void Run() {
    // 初始化FAT子系统(仅执行一次)
    if (!fatInitDefault()) {
        std::cout << "\033[31mError: Could not initialize the FAT subsystem. Exiting to system menu." << std::endl << "\033[0m";
        SYS_ResetSystem(SYS_RETURNTOMENU, 0, 0);
    }

    // 后续网络初始化、Socket创建逻辑...
}

修复后的完整Run()代码示例

void Run() {
    // 初始化FAT子系统(仅执行一次)
    if (!fatInitDefault()) {
        std::cout << "\033[31mError: Could not initialize the FAT subsystem. Exiting to system menu." << std::endl << "\033[0m";
        SYS_ResetSystem(SYS_RETURNTOMENU, 0, 0);
    }

    // 初始化Wii网络栈
    if (!net_init()) {
        perror("net_init failed");
        exit(EXIT_FAILURE);
    }

    // 获取本地IP
    struct in_addr ip_addr;
    if (net_gethostip(&ip_addr) < 0) {
        perror("net_gethostip failed");
        exit(EXIT_FAILURE);
    }

    int server, ssocket, valread;
    struct sockaddr_in address;
    socklen_t addrlen = sizeof(address);
    char buffer[1024] = {0};

    // 创建TCP Socket
    if ((server = net_socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
        perror("socket failed");
        exit(EXIT_FAILURE);
    }

    int opt = 1;
    // 设置SO_REUSEADDR
    if (net_setsockopt(server, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) {
        perror("setsockopt SO_REUSEADDR failed");
        exit(EXIT_FAILURE);
    }

    address.sin_family = AF_INET;
    address.sin_addr.s_addr = htonl(INADDR_ANY);
    address.sin_port = htons(port_);

    if (net_bind(server, (struct sockaddr *)&address, sizeof(address)) < 0) {
        perror("bind failed");
        exit(EXIT_FAILURE);
    }

    if (net_listen(server, 3) < 0) {
        perror("listen failed");
        exit(EXIT_FAILURE);
    } else {
        std::cout << "Server is now running at port " << port_ << std::endl;
        std::cout << "Local IP: " << inet_ntoa(ip_addr) << std::endl;
    }

    while (true) {
        if ((ssocket = net_accept(server, (struct sockaddr *)&address, &addrlen)) < 0) {
            perror("accept failed");
            exit(EXIT_FAILURE);
        }

        valread = net_read(ssocket, buffer, 1024);
        if (valread < 0) {
            perror("net_read failed");
            net_close(ssocket);
            continue;
        }
        std::string request(buffer, valread);
        size_t start = request.find(' ') + 1;
        size_t end = request.find(' ', start);
        if (start == std::string::npos || end == std::string::npos) {
            std::string bad_request = "HTTP/1.1 400 Bad Request\r\nContent-Length: 0\r\n\r\n";
            net_write(ssocket, bad_request.c_str(), bad_request.size());
            net_close(ssocket);
            continue;
        }
        std::string path = request.substr(start, end - start);

        if (path.back() == '/') {
            path += "index.html";
        }

        std::string webp = "./html" + path;

        std::ifstream file(webp, std::ios::binary);
        if (file) {
            std::stringstream ss;
            ss << file.rdbuf();
            std::string contents = ss.str();
            std::string response = "HTTP/1.1 200 OK\r\nContent-Length: " + std::to_string(contents.size()) + "\r\n\r\n" + contents;
            net_write(ssocket, response.c_str(), response.size());
        } else {
            std::string error_page = "<html>\n\t<head>\n\t\t<title>404 Not Found</title>\n\t</head>\n\t<body>\n\t\t<h1>404 Not Found</h1>\n\t\t<p>The requested URL <i>" + path + "</i> was not found on this server.</p>\n\t</body>\n</html>";
            std::string response = "HTTP/1.1 404 Not Found\r\nContent-Length: " + std::to_string(error_page.size()) + "\r\n\r\n" + error_page;
            net_write(ssocket, response.c_str(), response.size());
        }

        net_close(ssocket);
    }
}

额外注意事项

  • 确保使用最新版devKitPro,旧版libogc可能存在socket接口bug
  • 真机测试时确认Wii已接入局域网,目标端口未被占用
  • 编译时需链接-lwiiuse -lbte -logc -lfat等必要库

内容的提问来源于stack exchange,提问作者Javier Zayas

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 01:10:06