libevent chat

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;
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值