一个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实现 LeetCode 486 预测赢家
486. 预测赢家 给定一个表示分数的非负整数数组. 玩家1从数组任意一端拿取一个分数,随后玩家2继续从剩余数组任意一端拿取分数,然后玩家1拿,--.每次一个玩家只能拿取一个分数,分数被拿取之后不再可 ...
- Java实现 LeetCode 462 最少移动次数使数组元素相等 II
462. 最少移动次数使数组元素相等 II 给定一个非空整数数组,找到使所有数组元素相等所需的最小移动数,其中每次移动可将选定的一个元素加1或减1. 您可以假设数组的长度最多为10000. 例如: 输 ...
- Java实现 LeetCode 543 二叉树的直径
543. 二叉树的直径 给定一棵二叉树,你需要计算它的直径长度.一棵二叉树的直径长度是任意两个结点路径长度中的最大值.这条路径可能穿过根结点. 示例 : 给定二叉树 1 / \ 2 3 / \ 4 5 ...
- Java实现 蓝桥杯VIP 算法训练 拦截导弹
1260:[例9.4]拦截导弹(Noip1999) 时间限制: 1000 ms 内存限制: 65536 KB 提交数: 4063 通过数: 1477 [题目描述] 某国为了防御敌国的导弹袭击,发展出一 ...
- Winform最基础的DBHelper类
PS:我已经忘记了n遍了 class DBHelper { //连接数据库 public static string connstring = @"Data Source=DESKTOP-8 ...
- Java中继承的详细用法
关于上一篇构造方法后的继承方法 构造方法链接 extends是继承的关键字 例: 下面的代码BB和CC就是AA的子类 允许一个父类有多个子类,但不允许一个子类有多个父类 /*final*/ class ...
- 第九届蓝桥杯JavaB组省赛真题
解题代码部分来自网友,如果有不对的地方,欢迎各位大佬评论 题目1.第几天 题目描述 2000年的1月1日,是那一年的第1天. 那么,2000年的5月4日,是那一年的第几天? 注意:需要提交的是一个整数 ...
- python XlsxWriter模块创建aexcel表格
https://blog.csdn.net/qq_41030861/article/details/82148777 安装使用pip install XlsxWriter来安装,Xlsxwriter用 ...
- python IDE pycharm的安装与使用
Python开发最牛逼的IDE——pycharm (其实其它的工具,例如eclipse也可以写,只不过比较麻烦,需要安装很多的插件,所以说pycharm是最牛逼的) pycharm,下载专业版的,不要 ...
- 修改MSSQL的端口地址_TcpPort_数据库安装工具_连载_2
修改MSSQL的端口地址_TcpPort,可在程序中调用,从而修改TcpPort Use master Go ------------------------------ --1)在注册表中查询 Pi ...