如何用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); } }
问题分析与修复建议
核心问题
- 代码执行逻辑阻塞:
serv.run()在main开头就调用,会让Boost.Asio的IO服务一直阻塞运行,后面的控制台交互代码(选择功能、输入昵称等)永远不会执行。 - 端口选择不当:代码里服务器用了端口13,这是Daytime服务的默认端口,可能被系统占用或防火墙拦截,建议换成自定义端口(比如12345)。
- 缺少客户端逻辑:当前代码只实现了服务器端监听,没有主动发起连接到其他主机的客户端逻辑,无法建立双向通信。
- 错误的对象创建:
tcp_connection tc();是函数声明,不是创建对象,且即使创建对象,也未与实际socket绑定来发送消息。 - 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
相关产品推荐
相关产品推荐

