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

如何用C++ boost::asio在Windows CMD实现多机网络字符串传输?

问题描述

我想让程序在两台或多台电脑之间通过网络建立连接,最终目标是在Windows的CMD环境下做一个对话应用。我尝试过搭建主机与服务器的连接,但没成功,而且我觉得我需要的是**主机对主机(P2P)**的连接方式。我写了下面的代码,但各种连接实现都没法正常运行。

现有代码
#define _CRT_SECURE_NO_WARNINGS
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <WinSock2.h>
#pragma comment(lib, "ws2_32.lib")

#include <iostream>
#include <boost/asio.hpp>
#include <fstream>
#include <ctime>
#include <time.h>
#include <boost/bind/bind.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>

using namespace std;
using namespace boost::asio;
using boost::asio::ip::tcp;

string message;
string nickname;

string Mess(string name, string text);

class tcp_connection
  : public boost::enable_shared_from_this<tcp_connection>
{
public:
    typedef boost::shared_ptr<tcp_connection> pointer;

    static pointer create(boost::asio::io_context& io_context)
    {
    return pointer(new tcp_connection(io_context));
    }

    tcp::socket& socket()
    {
    return socket_;
    }

    void start()
    {
        message_ = Mess(nickname, message);

        boost::asio::async_write(socket_, boost::asio::buffer(message_),
            boost::bind(&tcp_connection::handle_write, shared_from_this(),
              boost::asio::placeholders::error,
              boost::asio::placeholders::bytes_transferred));
    }

private:
    tcp_connection(boost::asio::io_context& io_context)
    : socket_(io_context)
    {

    }

    void handle_write(const boost::system::error_code& /*error*/,
      size_t /*bytes_transferred*/)
    {

    }

    tcp::socket socket_;
    std::string message_;
};

class tcp_server
{
public:
    tcp_server(boost::asio::io_context& io_context)
    : io_context_(io_context),
      acceptor_(io_context, tcp::endpoint(tcp::v4(), 13))
    {
        start_accept();
    }

private:
    void start_accept()
    {
    tcp_connection::pointer new_connection =
      tcp_connection::create(io_context_);

    acceptor_.async_accept(new_connection->socket(),
        boost::bind(&tcp_server::handle_accept, this, new_connection,
          boost::asio::placeholders::error));
    }

    void handle_accept(tcp_connection::pointer new_connection,
      const boost::system::error_code& error)
    {
    if (!error)
    {
      new_connection->start();
    }

    start_accept();
    }

    boost::asio::io_context& io_context_;
    tcp::acceptor acceptor_;
};

string Current_time()
{
    auto start = std::chrono::system_clock::now();
    auto end = std::chrono::system_clock::now();
    
    std::chrono::duration<double> elapsed_sec = end - start;
    std::time_t end_time = std::chrono::system_clock::to_time_t(end);

    return std::ctime(&end_time);

}

string Mess(string name, string text)
{
    string mes = name + ": " + text;
    return mes;
}

int main()
{

    boost::asio::io_context io;
    boost::asio::steady_timer timer(io, boost::asio::chrono::seconds(3));

    io_service serv;
    string ipadress;
    int start;
    ip::tcp::socket socket1(serv);
    ip::tcp::socket socket2(serv);
    tcp_server server(serv);
    serv.run();

    cout << "\n\t\tYou in my Social network\n" << std::endl;

    cout << "\n1 - to start chating, 2 - to exit, 3 - to check your host name: ";
    cin >> start;
    
    if (start == 1)
    {
        cout << "\nWrite your nickname (more than 3 symbols): ";
        cin >> nickname;

        if (nickname.length() <= 3)
        {
            system("cls");
            cout << "\n\n\t\tYour nickname should be more than 3 symbols\n\n\n";
            exit(1);
        }
        else
        {
            system("cls");
            
            //cout << "ip: " << IPad() << endl;

            cout << "Your nick is: '" << nickname << "'";

            tcp_connection tc();

            cout << "\n\nWrite your message (to end, press Ctrl + Z): ";
            cin >> message;

            cout << "\n" << Mess(nickname, message) << "\ttime when sended: " << Current_time() << "\n";

        }
    }
    else if (start == 2)
    {
        timer.wait();
        io.run();
        system("cls");
        exit(1);
    }
    else if (start == 3)
    {
        cout << "\n\tYour host name is: " << boost::asio::ip::host_name() << endl;
    }
    else
    {
        system("cls");
        cout << "\n\n\n\t\t\t1 or 2!!!\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n" << endl;
        cout << "bye";
        timer.wait();
        exit(1);
    }

}
问题分析与修复建议

核心问题

  1. 代码执行逻辑阻塞:serv.run()在main开头就调用,会让Boost.Asio的IO服务一直阻塞运行,后面的控制台交互代码(选择功能、输入昵称等)永远不会执行。
  2. 端口选择不当:代码里服务器用了端口13,这是Daytime服务的默认端口,可能被系统占用或防火墙拦截,建议换成自定义端口(比如12345)。
  3. 缺少客户端逻辑:当前代码只实现了服务器端监听,没有主动发起连接到其他主机的客户端逻辑,无法建立双向通信。
  4. 错误的对象创建:tcp_connection tc();是函数声明,不是创建对象,且即使创建对象,也未与实际socket绑定来发送消息。
  5. P2P实现难度:纯P2P在普通网络环境下很难实现(多数主机在NAT后),更简单的方案是先做客户端-服务器-客户端架构,服务器负责中转消息,两台主机通过服务器互相通信。

分步修复

1. 调整IO服务运行方式

把serv.run()放到交互逻辑之后,或用后台线程运行,避免阻塞控制台:

// 替换main中原有的serv.run()
std::thread t([&serv](){ serv.run(); });
t.detach(); // 让IO服务在后台线程运行

2. 修改服务器端口

将tcp::endpoint(tcp::v4(), 13)改为tcp::endpoint(tcp::v4(), 12345)(或其他未被占用的端口)。

3. 添加客户端连接逻辑

新增函数用于客户端连接指定IP的服务器:

void connect_to_server(io_service& serv, const string& ip, short port) {
    ip::tcp::socket socket(serv);
    ip::tcp::endpoint endpoint(ip::address::from_string(ip), port);
    boost::system::error_code ec;
    socket.connect(endpoint, ec);
    if (!ec) {
        cout << "连接服务器成功!" << endl;
        // 发送昵称到服务器
        string msg = "JOIN:" + nickname;
        boost::asio::write(socket, boost::asio::buffer(msg));
    } else {
        cout << "连接失败:" << ec.message() << endl;
    }
}

4. 完善消息收发逻辑

  • 修改tcp_connection类,添加异步读取逻辑,接收客户端消息
  • 在tcp_server中维护所有活跃连接列表,收到消息时转发给其他客户端

5. 先实现基础的客户端-服务器对话

先放弃P2P尝试,先做简单模型:一台机器启动服务器,另一台启动客户端连接服务器,客户端发送消息,服务器接收后转发给其他客户端,验证通信流程正常后再扩展功能。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 16:37:45