一个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 ...
随机推荐
- Java实现数字密码发生器
在对银行账户等重要权限设置密码的时候,我们常常遇到这样的烦恼:如果为了好记用生日吧,容易被破解,不安全:如果设置不好记的密码,又担心自己也会忘记:如果写在纸上,担心纸张被别人发现或弄丢了- 这个程序的 ...
- 【JAVA习题二十九】809*??=8*??+9*??+1 其中??代表的两位数,8*??的结果为两位数,9*??的结果为3位数。求??代表的两位数,及809*??后的结果。
package erase; public class 八九与问好两位数的乘积和 { public static void main(String[] args) { int m,n;//m十位,n个 ...
- tensorflow2.0学习笔记第二章第一节
2.1预备知识 # 条件判断tf.where(条件语句,真返回A,假返回B) import tensorflow as tf a = tf.constant([1,2,3,1,1]) b = tf.c ...
- Centos7.3 搭建KVM 命令安装VM虚拟机
操作系统:centos7.3 一.安装KVM 1. 验证CPU是否支持KVM:如果结果中有vmx(Intel)或svm(AMD)字样,就说明CPU的支持的. egrep '(vmx|svm)' ...
- 第一章04-Activity中常用的标志位
Activity的LaunchMode Android中提供了四中Activity的启动模式 1. standard 2. singleTop 3. singleTask 4. signleInsta ...
- JVM中堆的介绍
一.堆的概述 一个JVM实例只有一个堆内存,堆也是Java内存管理的核心区域,堆在JVM启动的时候创建,其空间大小也被创建,是JVM中最大的一块内存空间,所有线程共享Java堆,物理上不连续的逻辑上连 ...
- 基于使用ISCSI存储的ibmmq通过heartbeat实现HA方案以及碰到的问题总结
一.背景 ibmmq是一种传统架构的mq产品,运行稳定,有其自身优点,但在高可用(HA)这一块需要使用公司根据自身需求选用高可用(HA)产品,但由于市面HA商业产品较贵,所以使用linux操作系统级的 ...
- Python 图像处理 OpenCV (10):图像处理形态学之顶帽运算与黑帽运算
前文传送门: 「Python 图像处理 OpenCV (1):入门」 「Python 图像处理 OpenCV (2):像素处理与 Numpy 操作以及 Matplotlib 显示图像」 「Python ...
- MyISAM 和 InnoDB 索引结构及其实现原理
数据库索引,是数据库管理系统中一个排序的数据结构,以协助快速查询.更新数据库表中数据. 索引的实现通常使用B_TREE. B_TREE索引加速了数据访问,因为存储引擎不会再去扫描整张表得到需要的数据; ...
- 使用本地shadow socks代理
1,第一种方式 import urllib2 import socks from sockshandler import SocksiPyHandler opener = urllib2.build_ ...