Created
September 26, 2017 21:11
-
-
Save nerzhul/8a02cfd49ee4573f32f77c700cb35a59 to your computer and use it in GitHub Desktop.
asio tcp server/client
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <iostream> | |
#include <asio/io_service.hpp> | |
#include <asio/ip/tcp.hpp> | |
#include <thread> | |
#include <asio.hpp> | |
using asio::ip::tcp; | |
#define MAX_DATABUF_SIZE 10240 | |
#define HEADER_LEN 4 | |
class GameSession: | |
public std::enable_shared_from_this<GameSession> | |
{ | |
public: | |
GameSession(tcp::socket socket): | |
m_socket(std::move(socket)) | |
{} | |
~GameSession() | |
{ | |
// Called when tcp socket is closed | |
} | |
void start() | |
{ | |
do_read_header(); | |
} | |
private: | |
void do_read_header() | |
{ | |
auto self(shared_from_this()); | |
m_socket.async_read_some(asio::buffer(m_databuffer, HEADER_LEN), | |
[this, self](std::error_code ec, std::size_t length) { | |
if (!ec) { | |
memcpy(&buf_waited_len, &m_databuffer[0], 4); | |
if (buf_waited_len == 0) { | |
m_socket.close(); | |
return; | |
} | |
std::cout << "Header length waited: " << buf_waited_len << std::endl; | |
do_read_body(); | |
} | |
else { | |
m_socket.close(); | |
return; | |
} | |
do_read_body(); | |
}); | |
} | |
void do_read_body() | |
{ | |
auto self(shared_from_this()); | |
m_socket.async_read_some(asio::buffer(m_databuffer, buf_waited_len), | |
[this, self](std::error_code ec, std::size_t length) { | |
if (!ec) { | |
std::cout << "Length: " << length << ", Buffer: " | |
<< std::endl << "===========" << std::endl | |
<< &m_databuffer[0] << std::endl << "===========" << std::endl; | |
} | |
else { | |
m_socket.close(); | |
return; | |
} | |
do_read_header(); | |
}); | |
} | |
tcp::socket m_socket; | |
uint32_t buf_waited_len = 0; | |
std::array<char, MAX_DATABUF_SIZE> m_databuffer; | |
}; | |
class GameClient | |
{ | |
public: | |
GameClient(asio::io_service &io_service, tcp::resolver::iterator endpoint_iterator): | |
m_socket(io_service), | |
m_io_service(io_service) | |
{ | |
do_connect(endpoint_iterator); | |
} | |
private: | |
void do_connect(tcp::resolver::iterator endpoint_iterator) | |
{ | |
asio::async_connect(m_socket, endpoint_iterator, | |
[this](std::error_code ec, tcp::resolver::iterator) { | |
if (!ec) { | |
do_write(); | |
} | |
}); | |
} | |
void do_read_header() | |
{ | |
m_socket.async_read_some(asio::buffer(m_databuffer, HEADER_LEN), | |
[this](std::error_code ec, std::size_t length) { | |
if (!ec) { | |
memcpy(&buf_waited_len, &m_databuffer[0], 4); | |
if (buf_waited_len == 0) { | |
m_socket.close(); | |
return; | |
} | |
std::cout << "Header length waited: " << buf_waited_len << std::endl; | |
do_read_body(); | |
} | |
else { | |
m_socket.close(); | |
return; | |
} | |
do_read_body(); | |
}); | |
} | |
void do_read_body() | |
{ | |
m_socket.async_read_some(asio::buffer(m_databuffer, buf_waited_len), | |
[this](std::error_code ec, std::size_t length) { | |
if (!ec) { | |
std::cout << "Length: " << length << ", Buffer: " | |
<< std::endl << "===========" << std::endl | |
<< &m_databuffer[0] << std::endl << "===========" << std::endl; | |
} | |
else { | |
m_socket.close(); | |
return; | |
} | |
do_read_header(); | |
}); | |
} | |
void do_write() | |
{ | |
char buf[4096 + 4]; | |
memset(buf, 'A', sizeof(buf)); | |
uint32_t size = 4096; | |
memcpy(&buf[0], &size, 4); | |
asio::async_write(m_socket, asio::buffer(buf, 4096 + 4), | |
[this](std::error_code ec, std::size_t /*length*/) | |
{ | |
if (!ec) { | |
do_write(); | |
} | |
else | |
{ | |
m_socket.close(); | |
} | |
}); | |
} | |
tcp::socket m_socket; | |
uint32_t buf_waited_len = 0; | |
std::array<char, MAX_DATABUF_SIZE> m_databuffer; | |
asio::io_service &m_io_service; | |
}; | |
class GameListener | |
{ | |
public: | |
GameListener(asio::io_service &io_service, const tcp::endpoint &endpoint): | |
m_acceptor(io_service, endpoint), | |
m_socket(io_service) | |
{ | |
do_accept(); | |
} | |
private: | |
void do_accept() | |
{ | |
m_acceptor.async_accept(m_socket, [this](std::error_code ec) { | |
if (!ec) { | |
std::make_shared<GameSession>(std::move(std::move(m_socket)))->start(); | |
} | |
std::cout << "accept new client" << std::endl; | |
do_accept(); | |
}); | |
} | |
tcp::acceptor m_acceptor; | |
tcp::socket m_socket; | |
}; | |
void run_server() | |
{ | |
try { | |
std::cout << "Server starts..." << std::endl; | |
asio::io_service io_service; | |
tcp::endpoint endpoint(tcp::v6(), 34000); | |
GameListener gameListener_v6(io_service, endpoint); | |
io_service.run(); | |
} | |
catch (std::exception &e) { | |
std::cerr << "Server Exception: " << e.what() << std::endl; | |
} | |
} | |
void run_client() | |
{ | |
std::this_thread::sleep_for(std::chrono::milliseconds(100)); | |
try { | |
std::cout << "Client starts..." << std::endl; | |
asio::io_service io_service; | |
tcp::resolver resolver(io_service); | |
auto endpoint_iterator = resolver.resolve({ "localhost", "34000" }); | |
GameClient c(io_service, endpoint_iterator); | |
io_service.run(); | |
} | |
catch (std::exception &e) { | |
std::cerr << "Client Exception: " << e.what() << std::endl; | |
} | |
} | |
int main() | |
{ | |
//std::thread server(run_server); | |
std::thread client(run_client); | |
//server.join(); | |
client.join(); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment