// Synchronous echo server.
#include <array>
#include <iostream>
#include <string>
#include "boost/asio.hpp"
using boost::asio::ip::tcp;
enum { BUF_SIZE = 1024 };
void Session(tcp::socket socket) {
try {
while (true) {
std::array<char, BUF_SIZE> data;
boost::system::error_code ec;
std::size_t length = socket.read_some(boost::asio::buffer(data), ec);
if (ec == boost::asio::error::eof) {
std::cout << "Connection closed cleanly by peer." << std::endl;
break;
}
else if (ec) {
// Some other error
throw boost::system::system_error(ec);
}
boost::asio::write(socket, boost::asio::buffer(data, length));
}
}
catch (const std::exception& e) {
std::cerr << "Exception: " << e.what() << std::endl;
}
}
int main(int argc, char* argv[]) {
if (argc != 2) {
std::cerr << "Usage: " << argv[0] << " <port>" << std::endl;
return 1;
}
unsigned short port = std::atoi(argv[1]);
boost::asio::io_context io_context;
// Create an acceptor to listen for new connections.
tcp::acceptor acceptor(io_context, tcp::endpoint(tcp::v4(), port));
try {
// Handle one connection at a time.
while (true) {
// The socket object returned from accept will be moved to Session's
// parameter without any copy cost.
Session(acceptor.accept());
}
}
catch (const std::exception& e) {
std::cerr << e.what() << std::endl;
}
return 0;
}
运行方式:
命令函参数,只需要输入一个端口号。
举例:vs2017中,可以直接将命令行参数设置到调试配置里:
我这里的命令行参数填入的是8000端口,这个端口号大家可以按照自己喜欢的填写。
如果是在linux系统上,可以忽略这个设置,直接在命令行参数输入一个端口号。
然后用netcat工具做客户端测试这个echo server。
下面我们看看同步方式的echo client如何写:
同步方式的echo客户端代码:
// Synchronous echo client.
#include <array>
#include <cstring> // for std::strlen
#include <iostream>
#include "boost/asio/connect.hpp"
#include "boost/asio/io_context.hpp"
#include "boost/asio/ip/tcp.hpp"
#include "boost/asio/read.hpp"
#include "boost/asio/write.hpp"
using boost::asio::ip::tcp;
#define USE_GLOBAL_READ 1
enum { BUF_SIZE = 1024 };
int main(int argc, char* argv[]) {
if (argc != 3) {
std::cerr << "Usage: " << argv[0] << " <host> <port>" << std::endl;
getchar();
return 1;
}
const char* host = argv[1];
const char* port = argv[2];
boost::asio::io_context io_context;
// NOTE:
// Don't use output parameter |error_code| in this example.
// Using exception handling could largely simplify the source code.
try {
tcp::resolver resolver{ io_context };
// Return type: tcp::resolver::results_type
auto endpoints = resolver.resolve(tcp::v4(), host, port);
// Don't use socket.connect() directly.
// Global function connect() calls socket.connect() internally.
tcp::socket socket{ io_context };
boost::asio::connect(socket, endpoints);
// Get user input.
char request[BUF_SIZE];
std::size_t request_length = 0;
do {
std::cout << "Enter message: ";
std::cin.getline(request, BUF_SIZE);
request_length = std::strlen(request);
} while (request_length == 0);
// Write to the socket.
boost::asio::write(socket, boost::asio::buffer(request, request_length));
// Read the response.
// Use global read() or not (please note the difference).
std::cout << "Reply is: ";
#if USE_GLOBAL_READ
// Receive reply with global read().
char reply[BUF_SIZE];
// Global read() returns once the specified size of buffer has been
// fully filled.
std::size_t reply_length = boost::asio::read(
socket, boost::asio::buffer(reply, request_length));
std::cout.write(reply, reply_length);
#else
// Receive reply with socket.read_some().
std::size_t total_reply_length = 0;
while (true) {
std::array<char, BUF_SIZE> reply;
std::size_t reply_length = socket.read_some(boost::asio::buffer(reply));
std::cout.write(reply.data(), reply_length);
total_reply_length += reply_length;
if (total_reply_length >= request_length) {
break;
}
}
#endif // USE_GLOBAL_READ
std::cout << std::endl;
}
catch (const std::exception& e) {
std::cerr << e.what() << std::endl;
}
getchar();
return 0;
}
客户端命令行需要两个参数:ip地址和端口号
因为我们是在同一台电脑上的,所以ip地址写127.0.0.1就可以了。
运行结果:
客户端输入hello,就马上收到hello,然后客户端输入回车,就退出。
echo服务端会打印一行Connection closed cleanly by peer.
代码来自:
https://github.com/sprinfall/boost-asio-study
先记录下来,后续再补充函数的用法讲解,相当于是一个学习笔记吧!大家共勉。
参考:
基于Asio的C++网络编程
VS2017中处理命令行参数的方法----C++语言 Windows系统
官网的asio参考文档
boost官网的blocking_tcp_echo_server.cpp
boost官网的blocking_tcp_echo_client.cpp