使用muduo编写聊天室

来源:互联网 发布:淘宝塑唐玩具是正品吗 编辑:程序博客网 时间:2024/06/07 03:05

服务端,我们需要设计的回调函数有:连接的建立与断开,消息到来。
消息分包的话,这里采用的头部设置长度信息。

#include <muduo_five\net\EventLoop.h>#include <muduo_five\net\TcpServer.h>#include <string>#include <set>#include <iostream>using namespace std;class ChatServer : noncopyable{public:    ChatServer(EventLoop* loop, const InetAddress& listenAddr)        : server_(loop, listenAddr, "ChatServer")    {        server_.setConnectionCallback(std::bind(&ChatServer::onConnection, this, _1));        server_.setMessageCallback(std::bind(&ChatServer::onMessage, this, _1, _2, _3));    }    void start()    {        server_.start();    }private:    void onConnection(const TcpConnectionPtr& conn)    {        if (conn->connected())        {            connections_.insert(conn);        }        else        {            connections_.erase(conn);        }    }    void onMessage(const TcpConnectionPtr& conn, Buffer* buf, Timestamp receiveTime)    {        while (buf->readableBytes() >= kHeaderLen)        {            const void* data = buf->peek();            int32_t be32 = *static_cast<const int32_t*>(data); // SIGBUS            const int32_t len = ntohl(be32);            if (len > 65536 || len < 0)            {                conn->shutdown();                break;            }            else if (buf->readableBytes() >= len + kHeaderLen)            {                buf->retrieve(kHeaderLen);                string message(buf->peek(), len);                onStringMessage(conn, message, receiveTime);                buf->retrieve(len);            }            else            {                break;            }        }    }private:    void onStringMessage(const TcpConnectionPtr&, const string& message, Timestamp)    {        for (ConnectionList::iterator it = connections_.begin(); it != connections_.end(); ++it)        {            send(get_pointer(*it), message);        }    }    void send(TcpConnection* conn, const std::string& message)    {        Buffer buf;        buf.append(message.data(), message.size());        int32_t len = static_cast<int32_t>(message.size());        int32_t be32 = ntohl(len);        buf.prepend(&be32, sizeof be32);        conn->send((buf.retrieveAllAsString()));    }private:    static const int kHeaderLen = 4;    typedef std::set<TcpConnectionPtr> ConnectionList;    TcpServer server_;    ConnectionList connections_;};int main(){    WSADATA wsaData;    WSAStartup(MAKEWORD(2, 2), &wsaData);    {        EventLoop loop;        InetAddress serverAddr(7878);        ChatServer server(&loop, serverAddr);        server.start();        loop.loop();    }    WSACleanup();    //char c; cin >> c;}

客户端,我们需要编写的回调函数有,连接的建立与断开,消息到来。还需要设计一个write函数发送数据。

#include <muduo_five\net\Tcpconnection.h>#include<muduo_five\net\TcpClient.h>#include <muduo_five\net\EventLoopThread.h>#include<string>#include <map>#include<mutex>#include <iostream>#include <stdio.h>using namespace std;class ChatClient : noncopyable{public:    ChatClient(EventLoop* loop, const InetAddress& serverAddr)        : client_(loop, serverAddr, "ChatClient")    {        client_.setConnectionCallback(std::bind(&ChatClient::onConnection, this, _1));        client_.setMessageCallback(std::bind(&ChatClient::onMessage, this, _1, _2, _3));        client_.enableRetry();    }    void connect()    {        client_.connect();    }    void disconnect()    {        client_.disconnect();    }    void write(const std::string& message)    {        std::lock_guard<std::mutex> lock(mutex_);        if (connection_)        {            send(get_pointer(connection_), message);        }    }private:    void onConnection(const TcpConnectionPtr& conn)    {        std::lock_guard<std::mutex> lock(mutex_);        if (conn->connected())        {            connection_ = conn;        }        else        {            connection_.reset();        }    }    void onMessage(const TcpConnectionPtr& conn, Buffer* buf, Timestamp receiveTime)    {        while (buf->readableBytes() >= kHeaderLen)        {            const void* data = buf->peek();            int32_t be32 = *static_cast<const int32_t*>(data); // SIGBUS            const int32_t len = ntohl(be32);            if (len > 65536 || len < 0)            {                conn->shutdown();                break;            }            else if (buf->readableBytes() >= len + kHeaderLen)            {                buf->retrieve(kHeaderLen);                string message(buf->peek(), len);                onStringMessage(conn, message, receiveTime);                buf->retrieve(len);            }            else            {                break;            }        }    }private:    void onStringMessage(const TcpConnectionPtr&, const std::string& message, Timestamp)    {        printf("<<< %s\n", message.c_str());    }    void send(TcpConnection* conn, const std::string& message)    {        Buffer buf;        buf.append(message.data(), message.size());        int32_t len = static_cast<int32_t>(message.size());        int32_t be32 = ntohl(len);        buf.prepend(&be32, sizeof be32);        string temp = buf.retrieveAllAsString();        conn->send((temp));    }private:    static const int kHeaderLen = 4;    TcpClient client_;    mutex mutex_;    TcpConnectionPtr connection_;};int main( ){    WSADATA wsaData;    WSAStartup(MAKEWORD(2, 2), &wsaData);    {        EventLoopThread  loop;        InetAddress serverAddr("127.0.0.1", 7878);        ChatClient client(loop.startThread(), serverAddr);        client.connect();        std::string line;        while (std::getline(std::cin, line))        {            client.write(line);        }        client.disconnect();    }    WSACleanup();    //char c; std::cin >> c;}