Skip to content

Commit

Permalink
add chat_server
Browse files Browse the repository at this point in the history
  • Loading branch information
zhaozhengcoder committed Oct 31, 2018
1 parent 7648362 commit c6f6433
Show file tree
Hide file tree
Showing 12 changed files with 569 additions and 0 deletions.
13 changes: 13 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"files.associations": {
"memory": "cpp",
"initializer_list": "cpp",
"list": "cpp",
"type_traits": "cpp",
"vector": "cpp",
"xhash": "cpp",
"xstring": "cpp",
"xutility": "cpp",
"system_error": "cpp"
}
}
32 changes: 32 additions & 0 deletions muduo_tutorial/chatserver/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
MUDUO_DIRECTORY ?= $(HOME)/code_test/muduo/build/release-install
#MUDUO_DIRECTORY ?= $(HOME)/build/install
MUDUO_INCLUDE = $(MUDUO_DIRECTORY)/include
MUDUO_LIBRARY = $(MUDUO_DIRECTORY)/lib
SRC = ./

CXXFLAGS = -g -O0 -Wall -Wextra -Werror \
-Wconversion -Wno-unused-parameter \
-Wold-style-cast -Woverloaded-virtual \
-Wpointer-arith -Wshadow -Wwrite-strings \
-march=native -rdynamic \
-I$(MUDUO_INCLUDE)

LDFLAGS = -L$(MUDUO_LIBRARY) -lmuduo_net -lmuduo_base -lpthread -lrt -std=c++11

all: chat_server chat_client chat_client2 chat_server2
clean:
rm -f chat_server core

chat_server: $(SRC)/server.cc
g++ $(CXXFLAGS) -o $@ $^ $(LDFLAGS)

chat_server2: $(SRC)/server2.cc
g++ $(CXXFLAGS) -o $@ $^ $(LDFLAGS)

chat_client: $(SRC)/client.cc
g++ $(CXXFLAGS) -o $@ $^ $(LDFLAGS)

chat_client2: $(SRC)/client2.cc
g++ $(CXXFLAGS) -o $@ $^ $(LDFLAGS)

.PHONY: all clean
Binary file added muduo_tutorial/chatserver/chat_client
Binary file not shown.
Binary file added muduo_tutorial/chatserver/chat_client2
Binary file not shown.
Binary file added muduo_tutorial/chatserver/chat_server
Binary file not shown.
Binary file added muduo_tutorial/chatserver/chat_server2
Binary file not shown.
110 changes: 110 additions & 0 deletions muduo_tutorial/chatserver/client.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
#include <muduo/base/Logging.h>
#include <muduo/net/Endian.h>
#include <muduo/net/EventLoop.h>
#include <muduo/net/InetAddress.h>
#include <muduo/net/TcpClient.h>

#include <boost/bind.hpp>

#include <utility>
#include <iostream>
#include <stdio.h>
#include <unistd.h>

using namespace muduo;
using namespace muduo::net;

class TimeClient : boost::noncopyable
{
public:
TimeClient(EventLoop* loop, const InetAddress& serverAddr)
: loop_(loop),
client_(loop, serverAddr, "TimeClient")
{
client_.setConnectionCallback(
boost::bind(&TimeClient::onConnection, this, _1));
client_.setMessageCallback(
boost::bind(&TimeClient::onMessage, this, _1, _2, _3));
// client_.enableRetry();
}

void connect()
{
client_.connect();
}

private:

EventLoop* loop_;
TcpClient client_;

void onConnection(const TcpConnectionPtr& conn)
{
LOG_INFO << conn->localAddress().toIpPort() << " -> "
<< conn->peerAddress().toIpPort() << " is "
<< (conn->connected() ? "UP" : "DOWN");

string str = "hello world";
StringPiece message(str);
muduo::net::Buffer buf;
buf.append(message.data(), message.size());


conn->send(&buf);
if (!conn->connected())
{
loop_->quit();
}
}

void onMessage(const TcpConnectionPtr& conn, Buffer* buf, Timestamp receiveTime)
{
// if (buf->readableBytes() >= sizeof(int32_t))
// {
// const void* data = buf->peek();
// int32_t be32 = *static_cast<const int32_t*>(data);
// buf->retrieve(sizeof(int32_t));
// time_t time = sockets::networkToHost32(be32);
// Timestamp ts(implicit_cast<uint64_t>(time) * Timestamp::kMicroSecondsPerSecond);
// LOG_INFO << "Server time = " << time << ", " << ts.toFormattedString();
// }
// else
// {
// LOG_INFO << conn->name() << " no enough data " << buf->readableBytes()
// << " at " << receiveTime.toFormattedString();
// }
std::cout<<buf->readableBytes()<<std::endl;
if(buf->readableBytes() >= 4) // kHeaderLen == 4
{
const void* data = buf->peek();
int32_t be32 = *static_cast<const int32_t*>(data); // SIGBUS
const int32_t len = muduo::net::sockets::networkToHost32(be32);
std::cout<<"[msg len] "<<len<<std::endl;


buf->retrieve(4);
muduo::string message(buf->peek(), len);
buf->retrieve(len);
std::cout<<"[msg ] "<<message<<std::endl;
}
}
};

int main(int argc, char* argv[])
{
LOG_INFO << "pid = " << getpid();
if (argc > 1)
{
EventLoop loop;
InetAddress serverAddr(argv[1], 7001);

TimeClient timeClient(&loop, serverAddr);
timeClient.connect();
loop.loop();
}
else
{
printf("Usage: %s host_ip\n", argv[0]);
}
}

130 changes: 130 additions & 0 deletions muduo_tutorial/chatserver/client2.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
#include <muduo/base/Logging.h>
#include <muduo/net/Endian.h>
#include <muduo/net/EventLoop.h>
#include <muduo/net/InetAddress.h>
#include <muduo/net/TcpClient.h>
#include <muduo/base/Mutex.h>
#include <boost/bind.hpp>

#include <utility>
#include <iostream>
#include <stdio.h>
#include <unistd.h>
#include <muduo/net/EventLoopThread.h>
#include <iostream>

using namespace muduo;
using namespace muduo::net;

class TimeClient : boost::noncopyable
{
public:
TimeClient(EventLoop* loop, const InetAddress& serverAddr)
: loop_(loop),
client_(loop, serverAddr, "TimeClient")
{
client_.setConnectionCallback(
boost::bind(&TimeClient::onConnection, this, _1));
client_.setMessageCallback(
boost::bind(&TimeClient::onMessage, this, _1, _2, _3));
// client_.enableRetry();
}

void connect()
{
client_.connect();
}

void mysend(muduo::net::TcpConnection* conn, const muduo::StringPiece& message)
{
muduo::net::Buffer buf;
buf.append(message.data(), message.size());
int32_t len = static_cast<int32_t>(message.size());
int32_t be32 = muduo::net::sockets::hostToNetwork32(len);
buf.prepend(&be32, sizeof be32);
conn->send(&buf);
}

void write(const StringPiece& message)
{
MutexLockGuard lock(mutex_);
if (connection_)
{
mysend(get_pointer(connection_), message);
}
}

void disconnect()
{
client_.disconnect();
}

private:

EventLoop* loop_;
TcpClient client_;
MutexLock mutex_;
TcpConnectionPtr connection_;

void onConnection(const TcpConnectionPtr& conn)
{
LOG_INFO << conn->localAddress().toIpPort() << " -> "
<< conn->peerAddress().toIpPort() << " is "
<< (conn->connected() ? "UP" : "DOWN");

if (!conn->connected())
{
loop_->quit();
}
else
{
connection_ = conn;
}
}

void onMessage(const TcpConnectionPtr& conn, Buffer* buf, Timestamp receiveTime)
{
std::cout<<buf->readableBytes()<<std::endl;
if(buf->readableBytes() >= 4) // kHeaderLen == 4
{

const void* data = buf->peek();
int32_t be32 = *static_cast<const int32_t*>(data); // SIGBUS
const int32_t len = muduo::net::sockets::networkToHost32(be32);
std::cout<<"[msg len] "<<len<<std::endl;


buf->retrieve(4);
muduo::string message(buf->peek(), len);
buf->retrieve(len);
std::cout<<"[msg ] "<<message<<std::endl;
}
}
};

int main(int argc, char* argv[])
{
LOG_INFO << "pid = " << getpid();
if (argc > 1)
{
EventLoopThread loopThread;
InetAddress serverAddr(argv[1], 7001);

TimeClient timeClient(loopThread.startLoop(), serverAddr);
timeClient.connect();
//loop.loop();

std::string line;
while(std::getline(std::cin,line))
{

timeClient.write(line);
}
timeClient.disconnect();
}
else
{
printf("Usage: %s host_ip\n", argv[0]);
}
}

67 changes: 67 additions & 0 deletions muduo_tutorial/chatserver/codec.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
#ifndef MUDUO_EXAMPLES_ASIO_CHAT_CODEC_H
#define MUDUO_EXAMPLES_ASIO_CHAT_CODEC_H

#include <muduo/base/Logging.h>
#include <muduo/net/Buffer.h>
#include <muduo/net/Endian.h>
#include <muduo/net/TcpConnection.h>

#include <boost/function.hpp>
#include <boost/noncopyable.hpp>

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() >= len + kHeaderLen)
{
buf->retrieve(kHeaderLen);
muduo::string message(buf->peek(), len);
messageCallback_(conn, message, receiveTime);
buf->retrieve(len);
}
else
{
break;
}
}
}

// FIXME: TcpConnectionPtr
void send(muduo::net::TcpConnection *conn,
const muduo::StringPiece &message)
{
muduo::net::Buffer buf;
buf.append(message.data(), message.size());
int32_t len = static_cast<int32_t>(message.size());
int32_t be32 = muduo::net::sockets::hostToNetwork32(len);
buf.prepend(&be32, sizeof be32);
conn->send(&buf);
}

private:
StringMessageCallback messageCallback_;
const static size_t kHeaderLen = sizeof(int32_t);
};

#endif // MUDUO_EXAMPLES_ASIO_CHAT_CODEC_H
19 changes: 19 additions & 0 deletions muduo_tutorial/chatserver/readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# 实现muduo里面的chatserver的例子


这个是利用muduo实现一个应用层的广播。另外,就是加上了**tcp的分包和拆包机制**

client1.cc 和 server1.cc 是一个半成品,理解起来更快一点。

client2.cc 和 server2.cc 是写完成的东西。


---

## 收获

* 拆包的时候,有一个写法很好
```
const void *data = buf->peek(); //拿到的数据
int32_t be32 = *static_cast<const int32_t *>(data); //获得头部的int
```
Loading

0 comments on commit c6f6433

Please sign in to comment.