windows客户端代码,使用了C++11新特性:
为了在控制台输入消息的时候不影响接收,loop放在另外一个线程里
// BaseLoopThread.h
#pragma once
#include <thread>
#include <mutex>
#include <condition_variable>
#include <functional>
struct bufferevent;
class BaseLoopThread
{
public:
typedef std::function<void(struct bufferevent *)> ThreadCallback;
BaseLoopThread();
~BaseLoopThread(void);
struct bufferevent *startLoop(const ThreadCallback &cb);
void exitLoop();
private:
BaseLoopThread(const BaseLoopThread&);
BaseLoopThread& operator=(const BaseLoopThread&);
void threadFunc();
ThreadCallback callback_;
struct bufferevent *be_;
bool exiting_;
std::mutex mutex_;
std::condition_variable cond_;
std::thread *thread_;
};
// BaseLoopThraed.cpp
#include "stdafx.h"
#include "BaseLoopThread.h"
#include "event2/event.h"
#include "event2/bufferevent.h"
#include "event2/util.h"
#include <iostream>
BaseLoopThread::BaseLoopThread()
: callback_(nullptr)
, be_(nullptr)
, exiting_(false)
, mutex_()
, cond_()
, thread_(nullptr)
{
}
BaseLoopThread::~BaseLoopThread(void)
{
exitLoop();
}
struct bufferevent *BaseLoopThread::startLoop(const ThreadCallback &cb)
{
callback_ = cb;
thread_ = new std::thread(std::bind(&BaseLoopThread::threadFunc, this));
{
std::unique_lock<std::mutex> ul(mutex_);
while(nullptr == be_) {
cond_.wait(ul);
}
}
return be_;
}
void BaseLoopThread::exitLoop()
{
if (!exiting_) {
exiting_ = true;
// 注意销毁顺序
struct event_base *base = bufferevent_get_base(be_);
bufferevent_free(be_);
event_base_loopexit(base, NULL);
if (thread_) {
thread_->join();
delete thread_;
}
}
}
void BaseLoopThread::threadFunc()
{
struct event_base *base = event_base_new();
struct bufferevent *be = bufferevent_socket_new(base, -1, BEV_OPT_CLOSE_ON_FREE);
callback_(be);
{
std::unique_lock<std::mutex> ul(mutex_);
be_ = be;
cond_.notify_one();
}
event_base_dispatch(base);
std::cout << "threadFunc exiting" << std::endl;
}
#include "stdafx.h"
#include <iostream>
#include <assert.h>
#include <string>
#include <stdint.h>
#include "event2/event.h"
#include "event2/bufferevent.h"
#include "event2/buffer.h"
#include "event2/listener.h"
#include "windowsSocket.h" // windows socket init
#include "BaseLoopThread.h"
const char* CONNECT_IP = "192.168.239.150";
const unsigned short CONNECT_PORT = 5000;
class ChatClient
{
public:
ChatClient(struct event_base *base, const struct sockaddr_in &sin)
: baseThread_(nullptr)
, sin_(sin)
, be_(bufferevent_socket_new(base, -1, BEV_OPT_CLOSE_ON_FREE))
{
}
ChatClient(BaseLoopThread *baseThread, const struct sockaddr_in &sin)
: baseThread_(baseThread)
, sin_(sin)
, be_(nullptr)
{
}
void start()
{
if (baseThread_) {
be_ = baseThread_->startLoop(std::bind(&ChatClient::connect, this, std::placeholders::_1));
} else {
connect(be_);
}
}
void disconnect()
{
baseThread_->exitLoop();
std::cout << "disconnect..." << std::endl;
}
void write(const std::string &msg)
{
// loop线程外不能使用input, output buffer???
struct evbuffer *buf = evbuffer_new();
evbuffer_add(buf, msg.c_str(), msg.length());
int num = evbuffer_write(buf, bufferevent_getfd(be_));
evbuffer_free(buf);
std::cout << "write num:" << num << std::endl;
}
private:
ChatClient(const ChatClient&);
ChatClient& operator=(const ChatClient&);
void connect(struct bufferevent *be)
{
bufferevent_setcb(be, ChatClient::onMessage, ChatClient::OnWrite, ChatClient::onEvent, NULL);
bufferevent_enable(be, EV_READ | EV_WRITE | EV_PERSIST);
bufferevent_socket_connect(be, (sockaddr*)&sin_, sizeof(sin_));
}
static void onMessage(struct bufferevent *bufferEvent, void *val)
{
std::cout << "read_cb is comming..." << std::endl;
char buf[1024] = {0};
size_t len = bufferevent_read(bufferEvent, buf, sizeof(buf));
std::cout << "recv:" << buf << std::endl;
}
static void OnWrite(struct bufferevent *bufferEvent, void *val)
{
std::cout << "write cb is comming..." << std::endl;
}
static void onEvent(struct bufferevent *be, short event, void *val)
{
std::cout << "on event - ";
if (event & BEV_EVENT_TIMEOUT) {
std::cout << "time out" << std::endl;
} else if (event & BEV_EVENT_EOF) {
std::cout << "connection closed" << std::endl;
} else if (event & BEV_EVENT_ERROR) {
std::cout << "event error" << std::endl;
} else if (event & BEV_EVENT_CONNECTED) {
std::cout << "connected" << std::endl;
} else if (event & BEV_EVENT_READING) {
std::cout << "reading" << std::endl;
} else if (event & BEV_EVENT_WRITING) {
std::cout << "writing" << std::endl;
} else {
std::cout << "others" << std::endl;
}
}
BaseLoopThread *baseThread_;
struct sockaddr_in sin_;
struct bufferevent *be_;
};
int _tmain(int argc, _TCHAR* argv[])
{
WindowsSocket::Startup(2, 2);
struct sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = inet_addr(CONNECT_IP);
sin.sin_port = htons(CONNECT_PORT);
BaseLoopThread loopThread;
ChatClient cc(&loopThread, sin);
cc.start();
std::string line;
while (std::getline(std::cin, line) && line!="quit") {
cc.write(line);
}
cc.disconnect();
WindowsSocket::Cleanup();
system("pause");
return 0;
}
linux服务端代码:
#include <iostream>
#include <arpa/inet.h>
#include <time.h>
#include <stdlib.h>
#include <string.h>
#include <event2/event.h>
#include <event2/bufferevent.h>
#include <event2/buffer.h>
#include <event2/listener.h>
#include <event2/util.h>
#include <set>
#include <vector>
class ChatServer
{
public:
ChatServer(struct event_base *base, unsigned short port)
: base_(base), port_(port), listener_(NULL)
{
}
~ChatServer()
{
std::cout << "~ChatServer" << std::endl;
for (std::set<struct bufferevent*>::iterator iter = connections_.begin(); iter != connections_.end(); ++iter) {
bufferevent_free((*iter));
}
evconnlistener_free(listener_);
}
void start()
{
struct sockaddr_in sin;
bzero(&sin, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = htonl(0);
sin.sin_port = htons(port_);
listener_ = evconnlistener_new_bind(base_, ListenerCallback, this, LEV_OPT_CLOSE_ON_FREE | LEV_OPT_REUSEABLE,
-1, (struct sockaddr*)&sin, sizeof(sin));
}
private:
void OnEvent(struct bufferevent *be, short event)
{
std::cout << "event cb - ";
if (event & BEV_EVENT_TIMEOUT) {
std::cout << "time out" << std::endl;
} else if (event & BEV_EVENT_EOF) {
std::cout << "connection eof" << std::endl;
goto exit;
} else if (event & BEV_EVENT_ERROR) {
std::cout << "event error" << std::endl;
goto exit;
} else if (event & BEV_EVENT_CONNECTED) {
std::cout << "connected" << std::endl;
} else if (event & BEV_EVENT_READING) {
std::cout << "reading" << std::endl;
} else if (event & BEV_EVENT_WRITING) {
std::cout << "writing" << std::endl;
} else {
std::cout << "others" << std::endl;
}
return;
exit:
std::cout << "connect exit:" << be << std::endl;
connections_.erase(be);
bufferevent_free(be);
}
void OnRead(struct bufferevent *be)
{
std::cout << "read_cb" << std::endl;
struct evbuffer *input = bufferevent_get_input(be);
if (input) {
int len = evbuffer_get_length(input);
std::vector<char> response(len, '\0');
len = evbuffer_remove(input, &response[0], len);
for (std::set<struct bufferevent*>::iterator iter = connections_.begin();
iter != connections_.end(); ++iter) {
bufferevent_write((*iter), &response[0], len);
}
std::cout << "write num:" << len << std::endl;
}
}
void OnListener(struct evconnlistener *listener, evutil_socket_t fd, struct sockaddr *addr, int socklen)
{
std::cout << "listener_cb, in, fd:" << fd << std::endl;
struct bufferevent *be = bufferevent_socket_new(base_, fd, BEV_OPT_CLOSE_ON_FREE);
if (be) {
bufferevent_setcb(be, ReadCallback, NULL, EventCallback, this);
bufferevent_enable(be, EV_READ | EV_PERSIST);
connections_.insert(be);
}
}
static void EventCallback(struct bufferevent *be, short event, void *self)
{
ChatServer *p = static_cast<ChatServer*>(self);
p->OnEvent(be, event);
}
static void ReadCallback(struct bufferevent *be, void *self)
{
ChatServer *p = static_cast<ChatServer*>(self);
p->OnRead(be);
}
static void ListenerCallback(struct evconnlistener *listener, evutil_socket_t fd, struct sockaddr *addr, int socklen, void *self)
{
ChatServer *p = static_cast<ChatServer*>(self);
p->OnListener(listener, fd, addr, socklen);
}
private:
struct event_base *base_;
unsigned short port_;
std::set<struct bufferevent*> connections_;
struct evconnlistener *listener_;
};
int main()
{
struct event_base *base = event_base_new();
ChatServer cs(base, 5000);
cs.start();
std::cout << "start..." << std::endl;
event_base_dispatch(base);
std::cout << "exit..." << std::endl;
return 0;
}