一个ACE 架构的 Socket Client
.h
/**************************************************************
* Filename: TcpClient.h
* Copyright: Shanghai X Co., Ltd.
*
* Description: TcpClient头文件.
*
* @author: w
* @version 10/28/2016 @Reviser Initial Version
**************************************************************/ #ifndef _TCPCLIENT_
#define _TCPCLIENT_ #include <string>
#include <ace/Svc_Handler.h>
#include <ace/Connector.h>
#include <ace/SOCK_Connector.h>
#include <ace/Task.h> using namespace std; //连接状态改变时回调
typedef void (__stdcall *pfnConnectChangeCallBack)(bool);
//接收到数据时回调
typedef void (__stdcall *pfnReceiveCallBack)(char*, const int); class CTcpClient : public ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_MT_SYNCH>
{
public:
// 是否退出的标识
long m_lStop; public:
// 是否允许重连
bool m_nReconnect;
// 通信超时ms
int m_nCommunicateTimeOut; public:
//typedef ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_MT_SYNCH> Base;
CTcpClient();
virtual ~CTcpClient(); public:
/**
* 设置连接参数.
*
* @param -[in] char* szHost: [主链接地址];
* @param -[in] char* szBackup: [备连接地址];
* @param -[in] int nRemotePort: [目标端口号];
* @param -[in] int nLocalPort: [本地端口号];
* @return int.
* @version 10/28/2016 w Initial Version
*/
virtual long SetConnectParam(char* szHost, char* szBackup, int nRemotePort, int nLocalPort = );
/**
* 首次连接.
*
* @return int.
* @version 10/28/2016 w Initial Version
*/
virtual int Connect(); /**
* 断开连接.
*
* @return int.
* @version 10/28/2016 w Initial Version
*/
virtual int Reconnect();
/**
* 断开连接.
*
* @return int.
* @version 10/28/2016 w Initial Version
*/
virtual int Disconnect(); /**
* 发送数据.
*
* @param -[in,out] char* szSend: [数据]
* @param -[in] char* lSendSize: [大小]
* @param -[in] int nCommunicateTimeOut: [超时ms]
* @return int.
* @version 10/28/2016 w Initial Version
*/
virtual long Send(const char* szSend, long lSendSize, int nCommunicateTimeOut = COMMUNICATE_TIMEOUT); /**
* 接收数据.
*
* @param -[in,out] char* szReceive: [数据]
* @param -[in] long lReceiveSize: [大小]
* @param -[in] int nCommunicateTimeOut: [超时ms]
* @version 10/28/2016 w Initial Version
*/
virtual long Receive(char* szReceive, long lReceiveSize, int nCommunicateTimeOut = COMMUNICATE_TIMEOUT);
//
virtual bool IsConnected() { return m_nIsConnected; }
/**
* 设置连接改变回调函数.
*
* @version 10/28/2016 w Initial Version
*/
void SetOnConnectChangeCallBack(pfnConnectChangeCallBack func);
/**
* 设置数据接收回调函数.
*
* @version 10/28/2016 w Initial Version
*/
void SetOnReceiveCallBack(pfnReceiveCallBack func); public:
/**
* 建立连接时被调用.
*
* @param -[in,out] char* param: [参数]
* @return int.
* @version 10/28/2016 w Initial Version
*/
int open(void* param = ); /**
* 当有输入时该函数被调用.
*
* @param -[in] ACE_HANDLE: [参数]
* @return int.
* @version 10/28/2016 w Initial Version
*/
int handle_input(ACE_HANDLE handle = ACE_INVALID_HANDLE); /**
* 当有输出时该函数被调用.
*
* @param -[in] ACE_HANDLE handle: [参数]
* @return int.
* @version 10/28/2016 w Initial Version
*/
virtual int handle_output(ACE_HANDLE handle = ACE_INVALID_HANDLE); /**
* 当SockHandler从ACE_Reactor中移除时该函数被调用.
*
* @param -[in] ACE_HANDLE handle: [参数]
* @param -[in] ACE_HANDLE closeMask: [参数]
* @return int
* @version 10/28/2016 w Initial Version
*/
int handle_close(ACE_HANDLE handle, ACE_Reactor_Mask closeMask); /**
* 任务的主流程.
* 1.激活事件
*
* @return int.
* @version 10/10/2016 w Initial Version
*/
int svc(); protected:
/**
* 触发连接改变回调函数.
*
* @param -[in] bool nIsConnected: [是否已连接]
*
* @version 10/28/2016 w Initial Version
*/
void OnConnectChange(bool nIsConnected); /**
* 触发数据接收回调函数.
*
* @param -[in,out] char* pszReceive: [接收的数据区]
* @param -[in] const int nReceiveSize: [数据大小]
* @version 10/28/2016 w Initial Version
*/
void OnReceive(char* pszReceive, const int nReceiveSize); protected:
// 是否已经连接
bool m_nIsConnected;
// 当前连接IP地址
string m_strConnectIPAddress;
// 主线连接IP地址
string m_strHostIPAddress;
// 备线连接IP地址
string m_strBackupIPAddress;
// 远程连接端口号
unsigned short m_nRemotePort;
// 本地连接端口号
unsigned short m_nLocalPort; pfnConnectChangeCallBack m_pfnOnConnectChange;
pfnReceiveCallBack m_pfnOnReceive; protected:
// 最后一次连接时间
time_t m_tmLastConnect; private:
/**
* 关闭Socket.
*
* @return int.
* @version 10/28/2016 w Initial Version
*/
int CloseSocket(); };
//typedef ACE_Connector<CTcpClient, ACE_SOCK_CONNECTOR> CONNECTOR; #endif // !_TCPCLIENT_
.cpp
/**************************************************************
* Filename: TcpClient.cpp
* Copyright: Shanghai X Co., Ltd.
*
* Description: TcpClient源文件.
*
* @author: w
* @version 10/28/2016 @Reviser Initial Version
**************************************************************/ #include "TcpClient.h"
#include <iostream>
#include <string> #include <ace/ACE.h>
#include <ace/OS_NS_sys_socket.h>
#include <ace/OS_NS_strings.h> using namespace std; //ctor
CTcpClient::CTcpClient()
{
m_lStop = true;
m_nReconnect = true;
m_nIsConnected = false; m_pfnOnConnectChange = NULL;
m_pfnOnReceive = NULL; m_strConnectIPAddress = "";
m_strHostIPAddress = "";
m_strBackupIPAddress = "";
m_nRemotePort = ;
m_nLocalPort = ; m_tmLastConnect = ;
}
//dctor
CTcpClient::~CTcpClient()
{
m_lStop = true;
wait();
//
close();
m_pfnOnConnectChange = NULL;
m_pfnOnReceive = NULL;
} long CTcpClient::SetConnectParam(char* szHost, char* szBackup, int nRemotePort, int nLocalPort)
{
m_strConnectIPAddress = m_strHostIPAddress = szHost;
m_strBackupIPAddress = szBackup;
m_nRemotePort = nRemotePort;
m_nLocalPort = nLocalPort;
return ;
} void CTcpClient::SetOnConnectChangeCallBack(pfnConnectChangeCallBack func)
{
this->m_pfnOnConnectChange = func;
} void CTcpClient::SetOnReceiveCallBack(pfnReceiveCallBack func)
{
this->m_pfnOnReceive = func;
} void CTcpClient::OnConnectChange(bool nIsConnected)
{
m_nIsConnected = nIsConnected;
if(!m_nIsConnected)
Log(LOGLEVEL_ERROR, "Disconnect from(%s:%d).", m_strConnectIPAddress.c_str(), m_nRemotePort);
else
Log(LOGLEVEL_NOTICE, "Connected to(%s:%d).", m_strConnectIPAddress.c_str(), m_nRemotePort);
//
if(m_pfnOnConnectChange)
m_pfnOnConnectChange(m_nIsConnected);
} void CTcpClient::OnReceive(char* pszReceive, const int nReceiveSize)
{
ACE_Message_Block *pFrame = new ACE_Message_Block(nReceiveSize);
memcpy(pFrame->wr_ptr(), pszReceive, nReceiveSize);
pFrame->wr_ptr(nReceiveSize);
this->putq(pFrame);
/*if(m_pfnOnReceive)
m_pfnOnReceive(pszReceive, nReceiveSize);*/
delete[] pszReceive;
} int CTcpClient::Disconnect()
{
CloseSocket();
OnConnectChange(false);
return ;
} int CTcpClient::CloseSocket()
{
//ACE_OS::shutdown(get_handle(), ACE_SHUTDOWN_BOTH);
//int nRet = ACE_OS::closesocket(m_sockHandler.get_handle());
this->peer().close();
set_handle(ACE_INVALID_HANDLE);
return ;
} int CTcpClient::Reconnect()
{
//已连接
if (IsConnected())
return ;
//未设置重连机制
if(!m_nReconnect)
{
Log(LOGLEVEL_INFO, "Reconnect is disabled.");
return -;
}
//小于超时时间3s不能重连
time_t tmNow;
time(&tmNow);
if(abs(tmNow - m_tmLastConnect) <= CONNECTION_TIMEOUT)
return -;
//清理Socket
CloseSocket();
return Connect();
} int CTcpClient::Connect()
{
//与服务器建立连接
CTcpClient *pSockHandler = this;
//创建连接器
ACE_Connector<CTcpClient, ACE_SOCK_CONNECTOR> connector;
//设置默认连接超时
ACE_Time_Value connTimeOut(CONNECTION_TIMEOUT);
ACE_Synch_Options synch_option(ACE_Synch_Options::USE_TIMEOUT, connTimeOut);
//远程端点
ACE_INET_Addr remoteEP(m_nRemotePort, m_strConnectIPAddress.c_str());
Log(LOGLEVEL_INFO, "Connecting to(%s:%d) ...", remoteEP.get_host_addr(), remoteEP.get_port_number());
//更新当前连接时间戳
time(&m_tmLastConnect);
int nRet = ;
if (m_nLocalPort > )
{
//绑定本地固定端口号
ACE_INET_Addr localEP(m_nLocalPort);
nRet = connector.connect(pSockHandler, remoteEP, synch_option, localEP);
}
else
{
//绑定本地随机端口号
nRet = connector.connect(pSockHandler, remoteEP, synch_option);
}
//连接失败
if(nRet == -)
{
//轮询切换连接主备服务器(存在)
if(!m_strBackupIPAddress.empty() && m_strBackupIPAddress.compare(m_strHostIPAddress) != )
{
m_strConnectIPAddress =
m_strConnectIPAddress.compare(m_strHostIPAddress) == ? m_strBackupIPAddress : m_strHostIPAddress;
}
OnConnectChange(false);
return -;
}
//启动接收事件(OneTime)
if(!nRet && m_lStop)
{
m_lStop = false;
this->activate(THR_NEW_LWP | THR_JOINABLE |THR_INHERIT_SCHED);
}
OnConnectChange(true);
return ;
} int CTcpClient::svc()
{
//接收
while(!m_lStop)
{
ACE_Time_Value tvSleep;
tvSleep.msec(TASK_NAP_TIME_VALUE);
ACE_OS::sleep(tvSleep);
ACE_Time_Value tvWaite(, TASK_NAP_TIME_VALUE);
//BLOCKED
this->reactor()->handle_events(&tvWaite);
}
return ;
} int CTcpClient::open(void* param)
{
return this->reactor()->register_handler(this, ACE_Event_Handler::READ_MASK | ACE_Event_Handler::WRITE_MASK);
//if (Base::open(param) == -1)
//{
// Log(LOGLEVEL_ERROR, "open() Failied.");
// return -1;
//}
//return 0;
} int CTcpClient::handle_input(ACE_HANDLE)
{
char *szBuffer = new char[DEFAULT_BUFFER_SIZE];
//接收数据
ssize_t length = this->peer().recv(szBuffer, DEFAULT_BUFFER_SIZE);
//连接断开接收失败
if(length <= )
{
delete[] szBuffer;
return -;//implicit call handle_close() clear up
}
OnReceive(szBuffer, length);
return ;
} int CTcpClient::handle_close(ACE_HANDLE handle, ACE_Reactor_Mask closeMask)
{
int nRet = ACE_Event_Handler::handle_close(handle, closeMask);
Disconnect();
return nRet;
} int CTcpClient::handle_output(ACE_HANDLE handle /* = ACE_INVALID_HANDLE */)
{
//调用一次
return ;
} long CTcpClient::Receive(char* szReceive, long lReceiveSize, int nCommunicateTimeOut)
{
//Confirmed
//implicit call handle_close() clear up
if(!IsConnected())
return -; ACE_Time_Value tvTimeout(, nCommunicateTimeOut);
//return this->peer().recv((void *)szReceive, lReceiveSize, &tvTimeout);
return this->peer().recv_n((void *)szReceive, lReceiveSize, &tvTimeout);
} long CTcpClient::Send(const char* szSend, long lSendSize, int nCommunicateTimeOut)
{
//Uncertainty
//implicit call handle_close() clear up
if(!IsConnected())
return -; ACE_Time_Value tvTimeout(, nCommunicateTimeOut);
ssize_t length = this->peer().send_n(szSend, lSendSize, &tvTimeout);
return length;
}
一个ACE 架构的 Socket Client的更多相关文章
- 一个ACE 架构的 C++ Timer
.h #ifndef _Timer_Task_ #define _Timer_Task_ #pragma once #include <ace/Task.h> #include <a ...
- Python编程-架构、Socket
一.客户端/服务器架构 1.C/S架构 Client/Server架构,即服务器/客户端架构. 客户端和服务器端的程序不同,用户的程序主要在客户端,服务器端主要提供数据管理.数据共享.数据及系统维护和 ...
- [原]一个简单的Linux TCP Client所涉及到的头文件
今天在Linux环境下写了一个最简单的TCP Client程序,没想到Linux环境下的头文件竟然这么分散,让我这样的菜鸟很是郁闷啊.编译成功的代码如下: #include <iostream& ...
- python -socket -client
socket client 发起连接. 流程为: 创建接口 发起连接 创建接口参数同socket server相同 发起连接的函数为socket.connect(ip,port) 这个地方的ip与po ...
- workerman是一个高性能的PHP socket服务器框架
workerman-chatorkerman是一款纯PHP开发的开源高性能的PHP socket服务器框架.被广泛的用于手机app.手游服务端.网络游戏服务器.聊天室服务器.硬件通讯服务器.智能家居. ...
- .Net机试题——编写一个BS架构的多层表结构的信息管理模块
要求: 编写一个BS架构的多层表结构的信息管理模块,用户体验需要注意.包含错误处理,需要最终能完整的跑起来.页面可以不美化,但是整洁还是必须的.在不能完成详细功能需求的情况下优先保证基本功能. 1 ...
- 一个Android 架构师的成长之路
前言 总所周知,当下流行的编程语言有Java.PHP.C.C++.Python.Go等.其中,稳坐榜首的仍然是Java编程语言,且在以面向对象思想占主导的应用开发中,Java往往成为其代名词.Java ...
- Kubernetes实战 - 从零开始搭建微服务 1 - 使用kind构建一个单层架构Node/Express网络应用程序
使用kind构建一个单层架构Node/Express网络应用程序 Kubernetes实战-从零开始搭建微服务 1 前言 准备写一个Kubernetes实战系列教程,毕竟cnblogs作为国内最早的技 ...
- C语言写了一个socket client端,适合windows和linux,用GCC编译运行通过
////////////////////////////////////////////////////////////////////////////////* gcc -Wall -o c1 c1 ...
随机推荐
- Javascript实现万年历(日历表)
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...
- JavaScript如何调用Python后端服务
本篇文章旨在通过一段JavaScript来演示如何调用python后端服务的,这是我开发的一个构建测试数据的工具. 第一部分:html 代码部分 第二部分:JavaScript代码部分 第三部分:Py ...
- JNI_day02
二级指针 指向指针变量的指针,保存指针的地址 结构体 struct Student //struct Stdent 学生结构体类型 { int id;//成员 char name[20]; int a ...
- jQuery实现拖拽元素
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...
- Linux: ssh命令 远程登录
1.查看SSH客户端版本 使用ssh -V命令可以得到版本号.需要注意的是,Linux一般自带的是OpenSSH; $ ssh -V ssh: SSH Secure Shell 3.2.9.1 (no ...
- 并行处理框架Celery的Web监控管理服务-Flower
安装和使用 使用pip安装Flower: $ pip install flower或 pip install flower -U -i https://pypi.tuna.tsinghua.edu.c ...
- 关于thinkphp5下URL附加参数,无法获取到(?参数)
nginx 配置问题: 修改配置后:
- 匿名实现类&匿名对象
学习过程中经常搞不清匿名类&匿名对象怎么用,今天就把常用的方式总结一遍. 1.创建了非匿名实现类的非匿名对象 //定义USB接口 interface USB{ void inputInofo( ...
- 一起读《Java编程思想》(第四版)
空余时间看<Java编程思想>(第四版)这本书,遇到不懂的知识点就记录在本博客内. 1.复用具体实现 Java代码复用的三种常见方式:继承.组合.代理. 1.继承:使用extends关键字 ...
- python批量发邮件
如果有一天,老板过来给你一个很大的邮箱列表,要你给每个人发邮件,你该如何去做,最简单的就是写一个 python 程序 # coding:utf-8import smtplibfrom email.mi ...