如下是创建TCP服务器
#ifndef __CUVTCPSVR__H_
#define __CUVTCPSVR__H_
#include "UvNetBase.h"
class CUvTcpSvr : public CUvNetBase{
public:
CUvTcpSvr();
virtual ~CUvTcpSvr();
public:
static void ConnCb(uv_stream_t* pHandle, int iStatus);
protected:
virtual int OnAccept(uv_tcp_t* pUvTcp) = 0;//TODO free pUvTcp
virtual uv_tcp_t* AllocTcpCli();
protected:
int Listen(int iBackLog = 5);
protected:
uv_tcp_t* mpTcpSvr;
};
#endif
#include "UvTcpSvr.h"
CUvTcpSvr::CUvTcpSvr(){
mpTcpSvr = nullptr;
}
CUvTcpSvr::~CUvTcpSvr(){
}
uv_tcp_t* CUvTcpSvr::AllocTcpCli() {
uv_tcp_t* pTcpCli = (uv_tcp_t*)do_malloc(sizeof(uv_tcp_t));
//Can Use Another Loop In SubClass
uv_tcp_init(GetUvLoop(), pTcpCli);
return pTcpCli;
}
void CUvTcpSvr::ConnCb(uv_stream_t* pHandle, int iStatus){
CUvTcpSvr* pTcpSvr = (CUvTcpSvr*)uv_handle_get_data((uv_handle_t*)pHandle);
if (nullptr != pTcpSvr){
if (iStatus < 0){
LOG_ERR("uv_listen error:%s", uv_strerror(-iStatus));
return;
}
uv_tcp_t* pTcpCli = pTcpSvr->AllocTcpCli();
ASSERT_RET(nullptr != pTcpCli);
int iRet = uv_accept((uv_stream_t*)pTcpSvr->mpTcpSvr, (uv_stream_t*)pTcpCli);
if (iRet < 0){
LOG_ERR("uv_accept error:%s", uv_strerror(-iRet));
return;
}
if (pTcpSvr->OnAccept(pTcpCli) != 0){
DOFREE(pTcpCli);
}
}
}
int CUvTcpSvr::Listen(int iBackLog){
if (nullptr == mpUvLoop || nullptr == mpTcpSvr){
return 1;
}
uv_handle_set_data((uv_handle_t*)mpTcpSvr, (void*)this);
uv_tcp_init(mpUvLoop, mpTcpSvr);
int iRet = uv_tcp_bind(mpTcpSvr, (struct sockaddr*)&mstLocalAddr, SO_REUSEADDR);
if (iRet < 0){
LOG_ERR("uv_tcp_bind error:%s", uv_strerror(-iRet));
return 1;
}
return uv_listen((uv_stream_t*)mpTcpSvr, iBackLog, CUvTcpSvr::ConnCb);
}
如下是创建TCP客户端
#ifndef __CUVTCPCLI__H_
#define __CUVTCPCLI__H_
#include "UvNetBase.h"
#include <queue>
class CUvTcpCli : public CUvNetBase{
public:
CUvTcpCli();
virtual ~CUvTcpCli();
public:
static void RecvCb(uv_stream_t* pHandle, ssize_t nRead, const uv_buf_t* pBuf);
static void ConnCb(uv_connect_t* pReq, int iStatus);
static void SendCb(uv_write_t* pReq, int iStatus);
static void CloseCb(uv_handle_t* pHandle);
static void NotifySend(uv_async_t* pHandle);
public:
void SetTcpCli(uv_tcp_t* pTcpCli);
int Connect(std::string strIp, unsigned short sPort);
int Send(char* pData, ssize_t iLen);
int Close();
private:
void ParseIpPort();
int AfterConn();
int Recv();
int DoSend();
void CleanSendQueue();
protected:
virtual int OnRecv(ssize_t nRead, const uv_buf_t* pBuf) = 0;
virtual int OnConn(int iStatus) = 0;
virtual int OnClose() = 0;
virtual int OnSend(int iStatus) = 0;
protected:
uv_tcp_t* mpTcpCli;
uv_connect_t* mpUvConn;
private:
uv_async_t mstUvSendAsync;
CUvMutex mcSendAsyncMutex;
std::queue<uv_buf_t> mqueSendBuf;
CUvMutex mcSendMutex;
uv_write_t mstUvWriteReq;
uv_buf_t mstWriteBuf;
};
#endif
#include "UvTcpCli.h"
CUvTcpCli::CUvTcpCli(){
mpTcpCli = nullptr;
mpUvConn = nullptr;
memset(&mstUvWriteReq, 0, sizeof(mstUvWriteReq));
memset(&mstWriteBuf, 0, sizeof(mstWriteBuf));
}
CUvTcpCli::~CUvTcpCli(){
CleanSendQueue();
}
void CUvTcpCli::RecvCb(uv_stream_t* pHandle, ssize_t nRead, const uv_buf_t* pBuf){
CUvTcpCli* pTcpCli = (CUvTcpCli*)uv_handle_get_data((uv_handle_t*)pHandle);
if (nullptr != pTcpCli){
if (nRead == 0){
if (!uv_is_active((uv_handle_t*)pTcpCli->mpTcpCli)){
LOG_ERR("Cli is Closed!");
}
return;
}
if (nRead < 0) {
pTcpCli->Close();
return;
} else if (nRead > 0) {
pTcpCli->OnRecv(nRead, pBuf);
}
}
}
void CUvTcpCli::ParseIpPort() {
ASSERT_RET(nullptr != mpTcpCli);
struct sockaddr stSock;
int iSockNameLen = (int)sizeof(stSock);
uv_tcp_getpeername(mpTcpCli, &stSock, &iSockNameLen);
struct sockaddr_in *pSock = (struct sockaddr_in*)&stSock;
musPort = ntohs(pSock->sin_port);
#if defined(WIN32) || defined(_WIN32)
mstrIp = inet_ntoa(pSock->sin_addr);
#elif __linux__
struct in_addr in = pSock->sin_addr;
char str[INET_ADDRSTRLEN]; //INET_ADDRSTRLEN这个宏系统默认定义 16
inet_ntop(AF_INET, &in, str, sizeof(str));
mstrIp = str;
#endif
}
void CUvTcpCli::SetTcpCli(uv_tcp_t* pTcpCli) {
ASSERT_RET(nullptr != mpUvLoop);
mpTcpCli = pTcpCli;
ParseIpPort();
uv_handle_set_data((uv_handle_t*)mpTcpCli, (void*)this);
AfterConn();
}
int CUvTcpCli::AfterConn() {
Recv();
mcSendAsyncMutex.Lock();
uv_handle_set_data((uv_handle_t*)&mstUvSendAsync, (void*)this);
uv_async_init(mpUvLoop, &mstUvSendAsync, CUvTcpCli::NotifySend);
mcSendAsyncMutex.UnLock();
return 0;
}
void CUvTcpCli::ConnCb(uv_connect_t* pReq, int iStatus){
CUvTcpCli* pTcpCli = (CUvTcpCli*)uv_handle_get_data((uv_handle_t*)pReq);
if (nullptr != pTcpCli){
if (iStatus >= 0) {
pTcpCli->AfterConn();
}
pTcpCli->OnConn(iStatus);
pTcpCli->DoSend();
}
}
int CUvTcpCli::Connect(std::string strIp, unsigned short sPort){
if (nullptr == mpTcpCli || nullptr == mpUvLoop || nullptr == mpUvConn){
return 1;
}
uv_handle_set_data((uv_handle_t*)mpTcpCli, (void*)this);
uv_tcp_init(mpUvLoop, mpTcpCli);
if (musPort > 0) {
int iRet = uv_tcp_bind(mpTcpCli, (struct sockaddr*)&mstLocalAddr, SO_REUSEADDR);
if (iRet < 0){
LOG_ERR("uv_tcp_bind error:%s", uv_strerror(-iRet));
return 1;
}
}
struct sockaddr_in stRemoteAddr;
uv_ip4_addr(strIp.c_str(), sPort, &stRemoteAddr);
uv_handle_set_data((uv_handle_t*)mpUvConn, (void*)this);
return uv_tcp_connect(mpUvConn, mpTcpCli, (struct sockaddr*)&stRemoteAddr, CUvTcpCli::ConnCb);
}
int CUvTcpCli::Recv() {
if (nullptr == mpTcpCli || nullptr == mpUvLoop) {
return 1;
}
int iSockBufLen = (int)(mstUvBuf.iLen - mstUvBuf.iUse);
uv_recv_buffer_size((uv_handle_t*)mpTcpCli, &iSockBufLen);
return uv_read_start((uv_stream_t*)mpTcpCli, CUvBase::UvBufAlloc, CUvTcpCli::RecvCb);
}
void CUvTcpCli::SendCb(uv_write_t* pReq, int iStatus) {
CUvTcpCli* pTcpCli = (CUvTcpCli*)uv_handle_get_data((uv_handle_t*)pReq);
if (nullptr != pTcpCli)
{
pTcpCli->mcSendMutex.Lock();
if (!pTcpCli->mqueSendBuf.empty()) {
uv_buf_t stTmp = pTcpCli->mqueSendBuf.front();
DOFREE(stTmp.base);
pTcpCli->mqueSendBuf.pop();
}
pTcpCli->mcSendMutex.UnLock();
pTcpCli->OnSend(iStatus);
if (iStatus < 0) {
if (iStatus == UV_ECANCELED) {
return;
}
LOG_ERR("uv_write:%s", uv_strerror(-iStatus));
pTcpCli->Close();
}
else
{
pTcpCli->DoSend();
}
}
}
void CUvTcpCli::NotifySend(uv_async_t* pHandle){
CUvTcpCli* pTcpCli = (CUvTcpCli*)uv_handle_get_data((uv_handle_t*)pHandle);
if (nullptr != pTcpCli){
pTcpCli->DoSend();
}
}
int CUvTcpCli::DoSend() {
memset(&mstWriteBuf, 0, sizeof(mstWriteBuf));
mcSendMutex.Lock();
if (!mqueSendBuf.empty()) {
uv_buf_t stTmp = mqueSendBuf.front();
mstWriteBuf.base = stTmp.base;
mstWriteBuf.len = stTmp.len;
}
mcSendMutex.UnLock();
if (mstWriteBuf.len <= 0) {
return 0;
}
uv_handle_set_data((uv_handle_t*)&mstUvWriteReq, (void*)this);
return uv_write(&mstUvWriteReq, (uv_stream_t*)mpTcpCli, &mstWriteBuf, 1, CUvTcpCli::SendCb);
}
int CUvTcpCli::Send(char* pData, ssize_t iLen){
if (nullptr == pData || iLen <= 0 || nullptr == mpTcpCli || nullptr == mpUvLoop || uv_is_active((uv_handle_t*)&mstUvSendAsync) == 0) {
return 1;
}
uv_buf_t stTmp;
stTmp.base = (char*)do_malloc(iLen);
stTmp.len = (unsigned long)iLen;
memcpy(stTmp.base, pData, iLen);
mcSendMutex.Lock();
mqueSendBuf.push(stTmp);
mcSendMutex.UnLock();
mcSendAsyncMutex.Lock();
if (uv_is_active((uv_handle_t*)&mstUvSendAsync) != 0) {
uv_async_send(&mstUvSendAsync);
}
mcSendAsyncMutex.UnLock();
return 0;
}
void CUvTcpCli::CleanSendQueue(){
mcSendMutex.Lock();
while (!mqueSendBuf.empty()){
uv_buf_t stTmp = mqueSendBuf.front();
DOFREE(stTmp.base);
mqueSendBuf.pop();
}
mcSendMutex.UnLock();
}
void CUvTcpCli::CloseCb(uv_handle_t* pHandle){
CUvTcpCli* pTcpCli = (CUvTcpCli*)uv_handle_get_data((uv_handle_t*)pHandle);
if (nullptr != pTcpCli){
pTcpCli->OnClose();
}
}
int CUvTcpCli::Close() {
if (nullptr == mpTcpCli || nullptr == mpUvLoop || uv_is_closing((uv_handle_t*)mpTcpCli) != 0) {
return 1;
}
mcSendAsyncMutex.Lock();
if (uv_is_active((uv_handle_t*)&mstUvSendAsync) != 0) {
uv_close((uv_handle_t*)&mstUvSendAsync, nullptr);
}
mcSendAsyncMutex.UnLock();
uv_close((uv_handle_t*)mpTcpCli, CUvTcpCli::CloseCb);
CleanSendQueue();
return 0;
}