关键代码时:
主要是主线程必须等待子线程退出才可以
测试代码
#include "RecvData.h"
static struct event_base *base;
static struct evconnlistener *listener;
static struct event *signal_event;
static std::shared_ptr<std::thread> work_thread;
static void listener_cb(struct evconnlistener *, evutil_socket_t,
struct sockaddr *, int socklen, void *);
static void conn_writecb(struct bufferevent *, void *);
static void conn_eventcb(struct bufferevent *, short, void *);
static void signal_cb(evutil_socket_t, short, void *);
static void read_cb(struct bufferevent *bev, void *ctx);
static void listener_cb(struct evconnlistener *listener, evutil_socket_t fd,
struct sockaddr *sa, int socklen, void *user_data)
{
struct event_base *base = (event_base *)user_data;
struct bufferevent *bev;
//struct evdns_base host;
bev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE);
if (!bev) {
fprintf(stderr, "Error constructing bufferevent!");
event_base_loopbreak(base);
return;
}
char ip[32];
int port=0;
//bufferevent_socket_connect_hostname(bev, NULL, AF_INET, ip, port);
bufferevent_setcb(bev, read_cb, conn_writecb, conn_eventcb, NULL);
bufferevent_enable(bev, EV_WRITE | EV_READ);
//bufferevent_disable(bev, EV_READ);
//bufferevent_write(bev, MESSAGE, strlen(MESSAGE));
}
static void read_cb(struct bufferevent *bev, void *ctx)
{
static int i = 0;
static uint8_t buff[1024] = { 0 };
memset(buff, 0, 1024);
int len = bufferevent_read(bev, buff, 1024);
bufferevent_write(bev, buff, len);
printf("read:");
for (int i = 0; i < len; i++)
{
printf("%x ", buff[i]);
}
printf("\n");
}
static void conn_writecb(struct bufferevent *bev, void *user_data)
{
//struct evbuffer *output = bufferevent_get_output(bev);
//if (evbuffer_get_length(output) == 0) {
// printf("flushed answer\n");
// //bufferevent_free(bev);
//}
}
static void conn_eventcb(struct bufferevent *bev, short events, void *user_data)
{
if (events & BEV_EVENT_EOF) {
printf("Connection closed.\n");
}
else if (events & BEV_EVENT_ERROR) {
printf("Got an error on the connection: %s\n",errno);
}
bufferevent_free(bev);
}
static void signal_cb(evutil_socket_t sig, short events, void *user_data)
{
struct timeval delay = { 2, 0 };
printf("Caught an interrupt signal; exiting cleanly in two seconds.\n");
evconnlistener_free(listener);
event_free(signal_event);
event_base_loopbreak(base);
event_base_loopexit(base, &delay);
event_base_free(base);
}
CRecvData::CRecvData()
{
}
CRecvData::~CRecvData()
{
//优雅的退出关键
work_thread->join();
}
uint8_t CRecvData::StartServer(uint16_t port/*=6001*/)
{
struct sockaddr_in sin;
#ifdef _WIN32
WSADATA wsa_data;
WSAStartup(0x0201, &wsa_data);
#endif
base = event_base_new();
if (!base) {
fprintf(stderr, "Could not initialize libevent!\n");
return 1;
}
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_port = htons(port);
listener = evconnlistener_new_bind(base, listener_cb, (void *)base,
LEV_OPT_REUSEABLE | LEV_OPT_CLOSE_ON_FREE, -1,
(struct sockaddr*)&sin,
sizeof(sin));
if (!listener) {
fprintf(stderr, "Could not create a listener!\n");
return 1;
}
signal_event = evsignal_new(base, SIGINT, signal_cb, (void *)base);
if (!signal_event || event_add(signal_event, NULL) < 0) {
fprintf(stderr, "Could not create/add a signal event!\n");
return 1;
}
work_thread = std::make_shared<std::thread>([](){
event_base_dispatch(base);
});
return 0;
}
#pragma once
#include <cstdint>
#include <event2/bufferevent.h>
#include <event2/buffer.h>
#include <event2/listener.h>
#include <event2/util.h>
#include <event2/event.h>
#include <signal.h>
#include<thread>
#include <condition_variable>
#include <mutex>
#include <memory>
#pragma comment(lib, "ws2_32.lib")
#pragma comment(lib, "wsock32.lib")
#pragma comment(lib, "libevent.lib")
#pragma comment(lib, "libevent_core.lib")
#pragma comment(lib, "libevent_extras.lib")
class CRecvData
{
public:
public:
CRecvData();
~CRecvData();
uint8_t StartQSYServer(uint16_t port=6001);
};
#include "RecvData.h"
int main(int argc, char **argv)
{
CRecvData recv;
recv.StartQSYServer();
getchar();
return 0;
}