add tcp server
parent
7e40fdb76e
commit
4fac2c2a98
|
@ -1,4 +1,7 @@
|
|||
|
||||
cmake_minimum_required(VERSION 3.21)
|
||||
project(superdog_server)
|
||||
|
||||
add_executable(superdog_server main.cpp)
|
||||
include_directories(superdog_server "third/include/libevent/include")
|
||||
add_executable(superdog_server main.cpp tcp_client.cpp)
|
||||
target_link_directories(superdog_server PUBLIC "./third/lib")
|
||||
target_link_libraries(superdog_server event.lib event_extra.lib event_core.lib ws2_32)
|
|
@ -0,0 +1,194 @@
|
|||
//
|
||||
// Created by 29019 on 2020/4/18.
|
||||
//
|
||||
|
||||
#include "tcp_client.h"
|
||||
|
||||
void conn_writecb(struct bufferevent *, void *);
|
||||
void conn_readcb(struct bufferevent *, void *);
|
||||
void conn_eventcb(struct bufferevent *, short, void *);
|
||||
|
||||
void delay(int ms);
|
||||
int ThreadRun(TcpClientLibevent *p);
|
||||
|
||||
//conn_writecwritecb函数将在bufferevent中的output evbuffer缓冲区发送完成后被调用。
|
||||
//此时evbuffer_get_length(output) = 0,说明output evbuffer缓冲区被清空。
|
||||
//假设发现有10000条记录要发送出去,1次发送10000条将占用大量内存,所以,我们要分批发送
|
||||
//先发送100条数据,假设每条数据为1024字节bufferevent_write(bev,buf,1024 *100);
|
||||
//系统在这100条记录发送完成后将调用conn_writecbb回调函数,然后在该函数中循环发送剩下的
|
||||
//数据
|
||||
void conn_writecb(struct bufferevent *bev, void *user_data)
|
||||
{
|
||||
// struct evbuffer *output = bufferevent_get_output(bev);
|
||||
// if (evbuffer_get_length(output) == 0)
|
||||
// {
|
||||
// printf("Output evbuffer is flushed\n");
|
||||
// bufferevent_free(bev);
|
||||
// }
|
||||
//delay 1 second
|
||||
//delay(1000);
|
||||
//static int msg_num = 1;
|
||||
//char reply_msg[1000] = { '\0' };
|
||||
//char *str = "I receive a message from client ";
|
||||
//memcpy(reply_msg, str, strlen(str));
|
||||
//sprintf(reply_msg + strlen(str), "%d", msg_num);
|
||||
//bufferevent_write(bev, reply_msg, strlen(reply_msg));
|
||||
//msg_num++;
|
||||
}
|
||||
|
||||
// 运行线程
|
||||
int ThreadRun(TcpClientLibevent *p) {
|
||||
if (nullptr != p) {
|
||||
p->mStatus = TcpClientLibevent::UNCONNECTED;
|
||||
int ret = p->Dispatch();
|
||||
if (0 > ret){
|
||||
}
|
||||
while ((p->mStatus != TcpClientLibevent::UNCONNECTED ))
|
||||
{
|
||||
if (p->mStatus == TcpClientLibevent::FAIL) { //连接失败,如果有设置自动重连就一直重连
|
||||
p->ConnectServer();
|
||||
#ifdef _WIN32
|
||||
Sleep(100);
|
||||
#else
|
||||
//todo linux版本sleep
|
||||
#endif
|
||||
}
|
||||
ret = p->Dispatch();
|
||||
}
|
||||
}
|
||||
p->mStatus = TcpClientLibevent::UNCONNECTED;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void conn_readcb(struct bufferevent *bev, void *user_data)
|
||||
{
|
||||
TcpClientLibevent *server = (TcpClientLibevent*)user_data;
|
||||
struct evbuffer *input = bufferevent_get_input(bev);
|
||||
size_t sz = evbuffer_get_length(input);
|
||||
if (sz > 0)
|
||||
{
|
||||
uint8_t *msg = new uint8_t[sz];
|
||||
int ret = bufferevent_read(bev, msg, sz);
|
||||
printf("%s\n", msg);
|
||||
if(server->mObserver != nullptr){
|
||||
}
|
||||
server->mObserver->OnData(msg,ret);
|
||||
delete[] msg;
|
||||
}
|
||||
}
|
||||
|
||||
void conn_eventcb(struct bufferevent *bev, short events, void *user_data)
|
||||
{
|
||||
TcpClientLibevent *p;
|
||||
p = (TcpClientLibevent *)user_data;
|
||||
if (events & BEV_EVENT_EOF)
|
||||
{
|
||||
if (nullptr != p->mObserver)
|
||||
p->mObserver->OnDisConnected();
|
||||
if (p != nullptr)
|
||||
p->mStatus = TcpClientLibevent::UNCONNECTED;
|
||||
printf("Connection closed\n");
|
||||
}
|
||||
else if (events & BEV_EVENT_ERROR)
|
||||
{
|
||||
printf("Got an error on the connection: %s\n", strerror(errno));
|
||||
if (nullptr != p->mObserver)
|
||||
p->mObserver->OnDisConnected();
|
||||
p->mStatus = TcpClientLibevent::FAIL;
|
||||
}
|
||||
else if (events & BEV_EVENT_CONNECTED)
|
||||
{
|
||||
printf("Connect succeed\n");
|
||||
//客户端链接成功后,给服务器发送第一条消息
|
||||
if (nullptr != p->mObserver)
|
||||
p->mObserver->OnConnected();
|
||||
if (p != nullptr)
|
||||
p->mStatus = TcpClientLibevent::UNCONNECTED;
|
||||
return;
|
||||
}
|
||||
bufferevent_free(bev);
|
||||
}
|
||||
|
||||
void delay(int ms)
|
||||
{
|
||||
clock_t start = clock();
|
||||
while (clock() - start < ms);
|
||||
}
|
||||
|
||||
bool TcpClientLibevent::Connected() {
|
||||
return (((mStatus != UNCONNECTED)&& (mStatus != FAIL) )?true : false);
|
||||
}
|
||||
|
||||
TcpClientLibevent::TcpClientLibevent(std::string addrinfo, int port, TcpClientLibevent::TcpClientObserver *p) :
|
||||
mStatus(UNCONNECTED),
|
||||
mObserver(nullptr)
|
||||
{
|
||||
memset(&mSrv, 0, sizeof(mSrv));
|
||||
#ifdef linux
|
||||
mSrv.sin_addr.s_addr = inet_addr(addrinfo.c_str());
|
||||
mSrv.sin_family = AF_INET;
|
||||
#endif
|
||||
#ifdef _WIN32
|
||||
mSrv.sin_addr.S_un.S_addr = inet_addr(addrinfo.c_str());
|
||||
mSrv.sin_family = AF_INET;
|
||||
#endif
|
||||
mSrv.sin_port = htons(port);
|
||||
|
||||
mBase = event_base_new();
|
||||
if (!mBase)
|
||||
{
|
||||
printf("Could not initialize libevent\n");
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
evthread_use_windows_threads();
|
||||
#else
|
||||
evthread_use_pthreads();
|
||||
#endif
|
||||
ConnectServer();
|
||||
this->mThread = new thread(ThreadRun,this);
|
||||
this->mObserver = p;
|
||||
}
|
||||
|
||||
int TcpClientLibevent::ConnectServer() {
|
||||
printf("connect server\r\n");
|
||||
evthread_make_base_notifiable(mBase);
|
||||
bev = bufferevent_socket_new(mBase, -1,
|
||||
BEV_OPT_CLOSE_ON_FREE | BEV_OPT_THREADSAFE);
|
||||
if (nullptr == bev) {
|
||||
this->mStatus = TcpClientLibevent::FAIL;
|
||||
return - 1;
|
||||
}
|
||||
bufferevent_setcb(bev, conn_readcb, conn_writecb, conn_eventcb, this);
|
||||
int flag = bufferevent_socket_connect(bev, (struct sockaddr *)&mSrv, sizeof(mSrv));
|
||||
bufferevent_enable(bev, EV_READ | EV_WRITE);
|
||||
if (-1 == flag)
|
||||
{
|
||||
this->mStatus = TcpClientLibevent::FAIL;
|
||||
bufferevent_free(bev);
|
||||
bev = nullptr;
|
||||
printf("Connect failed\n");
|
||||
return -1;
|
||||
}
|
||||
this->mStatus = TcpClientLibevent::CONNECTED;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int TcpClientLibevent::SetReconnect(bool reconn) {
|
||||
this->mReConnect = reconn;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int TcpClientLibevent::SetObserver(TcpClientLibevent::TcpClientObserver *ob) {
|
||||
this->mObserver = ob;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int TcpClientLibevent::Dispatch() {
|
||||
return event_base_dispatch(mBase);;
|
||||
}
|
||||
|
||||
int TcpClientLibevent::Close() {
|
||||
event_base_free(mBase);
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
//
|
||||
// Created by 29019 on 2020/4/18.
|
||||
//
|
||||
|
||||
#ifndef GENERAL_TCPCLIENT_H
|
||||
#define GENERAL_TCPCLIENT_H
|
||||
|
||||
#ifndef _WIN32_WINNT
|
||||
#define _WIN32_WINNT 0x0500
|
||||
#endif
|
||||
#ifdef linux
|
||||
#include<sys/types.h>
|
||||
#include<sys/socket.h>
|
||||
#include<arpa/inet.h>
|
||||
#define EVENT__HAVE_PTHREADS
|
||||
#endif
|
||||
|
||||
extern "C"{
|
||||
#include "event2/bufferevent.h"
|
||||
#include "event2/buffer.h"
|
||||
#include "event2/listener.h"
|
||||
#include "event2/util.h"
|
||||
#include "event2/event.h"
|
||||
#include "event2/thread.h"
|
||||
};
|
||||
|
||||
#include <iostream>
|
||||
// #include "PackageReceiver.h"
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
using namespace std;
|
||||
|
||||
class TcpClientLibevent {
|
||||
public:
|
||||
typedef enum {
|
||||
UNCONNECTED, // 未连接
|
||||
CONNECTED, //已经连接
|
||||
FAIL, // 连接失败
|
||||
}Status;
|
||||
class TcpClientObserver{
|
||||
public:
|
||||
virtual ~TcpClientObserver(){return;}
|
||||
mutex mMux;
|
||||
virtual void OnConnected() { return; };
|
||||
virtual void OnDisConnected() { return; };
|
||||
virtual void OnData(uint8_t *dat,uint64_t len){return;};
|
||||
virtual void OnClose(){return;};
|
||||
};
|
||||
TcpClientLibevent(std::string addrinfo,int port, TcpClientObserver *p);
|
||||
~TcpClientLibevent(){
|
||||
event_base_free(mBase);
|
||||
};
|
||||
int ConnectServer();
|
||||
bool Connected();
|
||||
int Dispatch();
|
||||
int OnTCPPackage(uint8_t *, uint16_t);
|
||||
int SetReconnect(bool);
|
||||
int SetObserver(TcpClientObserver*);
|
||||
int Close();
|
||||
Status mStatus;
|
||||
TcpClientObserver *mObserver;
|
||||
private:
|
||||
bool mReConnect = false;
|
||||
int sendData(void*,size_t);
|
||||
struct event_base *mBase;
|
||||
struct bufferevent* bev;
|
||||
struct sockaddr_in mSrv;
|
||||
std::thread *mThread;
|
||||
mutex mLock;
|
||||
};
|
||||
|
||||
#endif //GENERAL_TCPCLIENT_H
|
Loading…
Reference in New Issue