七、实现全双工通信

        系列文章目录:C++ asio网络编程-CSDN博客 

        在全双工通信方式中,服务器会一直监听写事件,接收对端数据,也可以随时发送数据给对端,所以保证数据有序尤为重要。在这一节中,我们将会封装一个数据队列,保证数据有序。

1、封装数据结点

class MsgNode
{
	friend class Session;
public:
	MsgNode(char* msg, int max_len) {
		_data = new char[max_len];
		memcpy(_data, msg, max_len);
	}
	~MsgNode() {
		delete[] _data;
	}
private:
	int _cur_len;  // 数据当前已处理的长度
	int _max_len;  // 数据总长度
	char* _data;   // 数据
};

2、发送接口设计

        在session类中,实现公有的send方法,用来发送数据,在设置两个私有成员变量,分别为要发送的数据队列、互斥锁,因为要保证线程安全,所以在操作数据队列时要加锁。

class Session : public std::enable_shared_from_this<Session>
{
public:
	Session(boost::asio::io_context& ioc, Server* server);

	boost::asio::ip::tcp::socket& getSocket();

	void start();

	void send(char* msg, int max_length);

	std::string& getUuid();

private:
	void handle_read(const boost::system::error_code& ec,
		std::size_t bytes_transferred,
		std::shared_ptr<Session> self_share);
	void handle_write(const boost::system::error_code& ec, 
		std::shared_ptr<Session> self_share);

	boost::asio::ip::tcp::socket _socket;
	Server* _server;
	std::string _uuid;

	enum {MAX_LENGTH = 1024};
	char _data[MAX_LENGTH];

	std::queue<std::shared_ptr<MsgNode>> _send_que;
	std::mutex _send_lock;
};

        实现send方法

void Session::send(char* msg, int max_length)
{
	bool pending = false;

	std::lock_guard<std::mutex> lock(_send_lock);
	if (_send_que.size() > 0) {
		pending = true;
	}
	_send_que.push(std::make_shared<MsgNode>(msg, max_length));
	if (pending) {
		return;
	}

	boost::asio::async_write(_socket, boost::asio::buffer(msg, max_length),
		std::bind(&Session::handle_write, this, std::placeholders::_1, shared_from_this()));
}

        修改写回调函数

void Session::handle_write(const boost::system::error_code& ec, 
	std::shared_ptr<Session> self_share)
{
	if (!ec) {
		std::lock_guard<std::mutex> lock(_send_lock);
		_send_que.pop();
		if (!_send_que.empty()) {
			auto& msgNode = _send_que.front();
			boost::asio::async_write(_socket, boost::asio::buffer(msgNode->_data, msgNode->_max_len),
				std::bind(&Session::handle_write, this, std::placeholders::_1, self_share));
		}
	}
	else {
		std::cout << "write error: " << ec.value() << std::endl;
		// delete this;
		_server->clearSession(_uuid);
	}
}

        读回调函数也可以修改一下

void Session::handle_read(const boost::system::error_code& ec, 
	std::size_t bytes_transferred, std::shared_ptr<Session> self_share)
{
	if (!ec) {
		std::cout << "server receive data is " << _data << std::endl;
		send(_data, bytes_transferred);
		memset(_data, 0, MAX_LENGTH);
		_socket.async_read_some(boost::asio::buffer(_data, MAX_LENGTH),
			std::bind(&Session::handle_read, this,
				std::placeholders::_1, std::placeholders::_2, self_share));
	}
	else {
		std::cout << "read error" << std::endl;
		// delete this;
		_server->clearSession(_uuid);
	}
}

3、总结

        这就是一个全双工通信的基本逻辑,大家可以用之前的同步读写客户端进行运行测试。但是写到这里仍然存在大量缺陷,下一节中将解决粘包问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值