同步echo server
echo_server_sync
代码:
#include <array>
#include <iostream>
#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;
//socket.close(); //可以这样关闭,也可以直接等socket析构时自动关闭
break;
}
else if (ec)
{
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;
tcp::acceptor acceptor(io_context, tcp::endpoint(tcp::v4(), port));
try
{
while(true)
{
Session(std::move(acceptor.accept()));
}
}
catch (const std::exception& e)
{
std::cerr << e.what() << std::endl;
}
getchar();
return 0;
}
其中std::array<char, BUF_SIZE> data;是定义一个缓冲区,boost::array也是可以的,标准库里有std::array,我们尽量用标准库里的。
Session(std::move(acceptor.accept()));
是使用std::move,减少一次tcp::socket拷贝。
socket.read_some(boost::asio::buffer(data), ec);
if (ec == boost::asio::error::eof)
如果大家对这个socket.read_some可能有些陌生的话,可以把每次收到的数据打印出来。
std::cout << std::string(data.data(), length) << std::endl;
有个小技巧,就是BUF_SIZE = 10,设置小,就能看到真的是分几次去读取的。这样的socket.read_some的好处就是可以不用知道“应该”读多少个字节,只管去读就好了,最终把所有的数据读到,每次读的正确的字节数加起来,就是总数了。
同步的客户端:
#include <array>
#include <cstring>
#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"
#include "boost/asio.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;
return 1;
}
const char* host = argv[1];
const char* port = argv[2];
boost::asio::io_context io_context;
try
{
tcp::resolver resolver{ io_context };
auto endpoints = resolver.resolve(tcp::v4(), host, port);
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 messaget: ";
std::cin.getline(request, BUF_SIZE);
request_length = std::strlen(request);
} while (request_length == 0);
boost::asio::write(socket, boost::asio::buffer(request, request_length));
std::cout << "Reply is: ";
#if USE_GLOBAL_READ
char reply[BUF_SIZE];
std::size_t reply_length = boost::asio::read(socket, boost::asio::buffer(reply, request_length));
std::cout.write(reply, reply_length);
#else
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 >= reply_length)
{
break;
}
}
#endif
std::cout << std::endl;
}
catch (const std::exception& e)
{
std::cerr << e.what() << std::endl;
}
getchar();
return 0;
}
注释:
因为是echo,所有客户端是知道自己要发多少个字节的,所以它可以先预先指定要读的长度进行读取,就可以用boost::asio::read去读,也可以假装自己不知道要读多少个字节,分多次去读,知道结束,如socket.read_some
客户端建立一次连接后,等待用户的输入,然后将用户输入的字符串发送给服务器端,等待服务器返回。
先运行echo server
我是在windows上运行的
echo_server_sync.exe 9000
再运行客户端:
echo_client_sync.exe 127.0.0.1 9000
Enter messaget: 222
Reply is: 222
此时服务器端会看到:
Connection closed cleanly by peer.