服务端:
#include <iostream>
#include <string>
#include <array>
#include <list>
#include <functional>
#include <map>
#include <memory>
#include <algorithm>
#include <boost/asio.hpp>
static constexpr size_t MAX_IP_PACK_SIZE = 65536;
static constexpr size_t IP_PACK_HEAD = 4;
static constexpr size_t MAX_CONNECTION_NUM = 128;
class rw_handler {
public:
rw_handler(boost::asio::io_service &service) : sock_(service) {
}
rw_handler(const rw_handler &) = delete;
rw_handler & operator = (const rw_handler &) = delete;
~rw_handler() = default;
public:
void handle_read() {
boost::asio::async_read(sock_, boost::asio::buffer(buffer_), boost::asio::transfer_at_least(IP_PACK_HEAD), [this] (const boost::system::error_code &error_code, size_t size) {
if (error_code) { // 读出错或者读到不足IP_PACK_HEAD字节
handle_error(error_code);
return;
}
std::cout << buffer_.data() + IP_PACK_HEAD << std::endl;
handle_read();
});
}
inline void set_connect_id(int id) {
connect_id_ = id;
}
inline int get_connect_id() const {
return connect_id_;
}
void close_socket() {
boost::system::error_code error_code;
sock_.shutdown(boost::asio::ip::tcp::socket::shutdown_send, error_code);
std::cout << "socket shutdown error message:" << error_code.message() << std::endl;
sock_.close(error_code);
std::cout << "socket close error message:" << error_code.message() << std::endl;
}
inline boost::asio::ip::tcp::socket &get_socket() {
return sock_;
}
template <typename F>
inline void set_callback(const F &f) {
error_callback_fun = f;
}
private:
void handle_error(const boost::system::error_code &error_code) {
close_socket();
std::cout << "handle_error:" << error_code.message() << std::endl;
if (nullptr != error_callback_fun) {
error_callback_fun(connect_id_);
}
}
inline void send_data(const char *data, size_t len) {
size_t send_len = len > MAX_IP_PACK_SIZE ? MAX_IP_PACK_SIZE : len;
boost::system::error_code error_code;
boost::asio::write(sock_, boost::asio::buffer(data, send_len), error_code);
if (error_code) {
handle_error(error_code);
}
}
private:
int connect_id_;
std::array<char, MAX_IP_PACK_SIZE>buffer_;
std::function<void(int)>error_callback_fun;
boost::asio::ip::tcp::socket sock_;
};
class server {
public:
server(boost::asio::io_service &service, short port) : service_(service),
acceptor_(service_, boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), port)),
connect_pool_(MAX_CONNECTION_NUM) {
int current = 0;
std::generate_n(begin(connect_pool_), MAX_CONNECTION_NUM, [¤t] { return ++current; });
}
server(const server &) = delete;
server & operator = (const server &) = delete;
virtual ~server() = default;
public:
void accept() {
std::cout << "server start listening" << std::endl;
auto handle = create_handle();
acceptor_.async_accept(handle->get_socket(), [this, handle] (const boost::system::error_code &error_code) {
if (error_code) {
handle_accept_error(handle, error_code);
}
handle_map_[handle->get_connect_id()] = handle;
handle->handle_read();
accept();
});
}
private:
void recycle_connect_id(int id) {
auto it = handle_map_.find(id);
if (it != end(handle_map_)) {
handle_map_.erase(it);
}
std::cout << "current connect count = " << handle_map_.size() << std::endl;
connect_pool_.push_back(id);
}
std::shared_ptr<rw_handler> create_handle() {
int id = connect_pool_.front();
connect_pool_.pop_front();
auto handle = std::make_shared<rw_handler>(service_);
handle->set_connect_id(id);
handle->set_callback([this] (int id) {
recycle_connect_id(id);
});
return std::move(handle);
}
void stop_acceptor() {
boost::system::error_code error_code;
acceptor_.cancel(error_code);
std::cout << "acceptor cancel error message:" << error_code.message() << std::endl;
acceptor_.close(error_code);
std::cout << "acceptor close error message:" << error_code.message() << std::endl;
service_.stop();
}
void handle_accept_error(std::shared_ptr<rw_handler>handle, const boost::system::error_code &error_code) {
std::cout << "error code:" << error_code.value() << " reason:" << error_code.message() << std::endl;
handle->close_socket();
stop_acceptor();
}
private:
boost::asio::io_service &service_;
boost::asio::ip::tcp::acceptor acceptor_;
std::map<int, std::shared_ptr<rw_handler>>handle_map_; // key -- connect id
std::list<int>connect_pool_;
};
class message {
public:
message() = default;
~message() = default;
public:
inline const char *data() const {
return data_;
}
inline size_t size() const {
return HEAD_LEN + body_size_;
}
inline const char *body() const {
return data_ + HEAD_LEN;
}
private:
static constexpr size_t HEAD_LEN = 4;
static constexpr size_t MAX_BODY_LEN = 512;
private:
char data_[HEAD_LEN + MAX_BODY_LEN] = { 0 };
size_t body_size_ = 0;
};
int main() {
boost::asio::io_service service;
server my_server(service, 9901);
my_server.accept();
service.run();
return 0;
}
客户端:
#include <netdb.h>
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <memory.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <iostream>
int main(int argc, char* argv[])
{
if(argc<3)
{
printf("usage : %s ip port\n", argv[0]);
exit(1);
}
// create socket
// tcp
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
if(sockfd<0)
{
perror("socket error");
exit(1);
}
struct sockaddr_in serveraddr;
memset(&serveraddr,0, sizeof(serveraddr));
serveraddr.sin_family = AF_INET;
serveraddr.sin_port = htons(atoi(argv[2]));
inet_pton(AF_INET, argv[1],
&serveraddr.sin_addr.s_addr);
if(connect(sockfd, (struct sockaddr*)&serveraddr,
sizeof(serveraddr))<0)
{
perror("connect error");
exit(1);
}
while (true) {
char buffer[1024] = "";
std::cin >> buffer;
size_t size = strlen(buffer);
if(write(sockfd, buffer,size)!=size) {
perror("write error");
}
else {
// char buffer[1024] = "";
// size = read(sockfd, buffer, sizeof(buffer));
// std::cout << "client read size = " << size << " read " << buffer << std::endl;
}
}
close(sockfd);
return 0;
}