muduo实现聊天服务器
muduo实现一个聊天室服务器,客户发送的消息将广播到连入的所有客户(包括自己)。
1.消息编码
消息的字节流定义成这种形式 0xXX 0xXX 0xXX 0xXX XXXXXX
,前面四个字节表示消息的长度,后面是消息实体,在服务器收到消息后,需要将该消息解码,把前面四个字节的长度信息剥离,把消息发送出去。
muduo作者选择自己编写一个编解码器LengthHeaderCodec
,用来解决头部信息的编解码,当已连接套接字可读时,muduo的TcpConnction会读数据并存入input buffer中,然后回调用户的函数。通过LengthHeaderCodec这一层封装,让用户代码只关心“消息到达”而不是“数据到达”。
//muduo/examples/asio/chat/codec.h
#ifndef __CODEC_H__
#define __CODEC_H__
#include<muduo/base/Logging.h>
#include<muduo/net/Buffer.h>
#include<muduo/net/Endian.h>
#include<muduo/net/TcpConnection.h>
class LengthHeaderCodec:boost::noncopyable
{
public:
typedef boost::function<void (const muduo::net::TcpConnectionPtr&,
const muduo::string& message,
muduo::Timestamp)> StringMessageCallback; //回调类型
//构造函数
explicit LengthHeaderCodec(const StringMessageCallback& cb)
:messageCallback_(cb)
{
}
void onMessage(const muduo::net::TcpConnectionPtr& conn,
muduo::net::Buffer* buf,
muduo::Timestamp receiveTime)
{
while (buf->readableBytes() >= kHeaderLen) // kHeaderLen == 4
{
// FIXME: use Buffer::peekInt32()
const void* data = buf->peek();//读取长度
int32_t be32 = *static_cast<const int32_t*>(data); // SIGBUS
const int32_t len = muduo::net::sockets::networkToHost32(be32);
if (len > 65536 || len < 0)
{
LOG_ERROR << "Invalid length " << len;
conn->shutdown(); // FIXME: disable reading
break;
}
else if (buf->readableBytes