boost.asio的同步echo服务器端和客户端实现

// 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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值