.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的更多相关文章

  1. 一个ACE 架构的 C++ Timer

    .h #ifndef _Timer_Task_ #define _Timer_Task_ #pragma once #include <ace/Task.h> #include <a ...

  2. Python编程-架构、Socket

    一.客户端/服务器架构 1.C/S架构 Client/Server架构,即服务器/客户端架构. 客户端和服务器端的程序不同,用户的程序主要在客户端,服务器端主要提供数据管理.数据共享.数据及系统维护和 ...

  3. [原]一个简单的Linux TCP Client所涉及到的头文件

    今天在Linux环境下写了一个最简单的TCP Client程序,没想到Linux环境下的头文件竟然这么分散,让我这样的菜鸟很是郁闷啊.编译成功的代码如下: #include <iostream& ...

  4. python -socket -client

    socket client 发起连接. 流程为: 创建接口 发起连接 创建接口参数同socket server相同 发起连接的函数为socket.connect(ip,port) 这个地方的ip与po ...

  5. workerman是一个高性能的PHP socket服务器框架

    workerman-chatorkerman是一款纯PHP开发的开源高性能的PHP socket服务器框架.被广泛的用于手机app.手游服务端.网络游戏服务器.聊天室服务器.硬件通讯服务器.智能家居. ...

  6. .Net机试题——编写一个BS架构的多层表结构的信息管理模块

      要求: 编写一个BS架构的多层表结构的信息管理模块,用户体验需要注意.包含错误处理,需要最终能完整的跑起来.页面可以不美化,但是整洁还是必须的.在不能完成详细功能需求的情况下优先保证基本功能. 1 ...

  7. 一个Android 架构师的成长之路

    前言 总所周知,当下流行的编程语言有Java.PHP.C.C++.Python.Go等.其中,稳坐榜首的仍然是Java编程语言,且在以面向对象思想占主导的应用开发中,Java往往成为其代名词.Java ...

  8. Kubernetes实战 - 从零开始搭建微服务 1 - 使用kind构建一个单层架构Node/Express网络应用程序

    使用kind构建一个单层架构Node/Express网络应用程序 Kubernetes实战-从零开始搭建微服务 1 前言 准备写一个Kubernetes实战系列教程,毕竟cnblogs作为国内最早的技 ...

  9. C语言写了一个socket client端,适合windows和linux,用GCC编译运行通过

    ////////////////////////////////////////////////////////////////////////////////* gcc -Wall -o c1 c1 ...

随机推荐

  1. Java实现 LeetCode 385 迷你语法分析器

    385. 迷你语法分析器 给定一个用字符串表示的整数的嵌套列表,实现一个解析它的语法分析器. 列表中的每个元素只可能是整数或整数嵌套列表 提示:你可以假定这些字符串都是格式良好的: 字符串非空 字符串 ...

  2. java实现漏掉的账目明细

    某财务部门结账时发现总金额不对头.很可能是从明细上漏掉了某1笔或几笔.如果已知明细账目清单,能通过编程找到漏掉的是哪1笔或几笔吗? 如果有多种可能,则输出所有可能的情况. 我们规定:用户输入的第一行是 ...

  3. Linux 权限管理-ACL权限

    ACL权限是为了在现有的所有者.所属组.其他人不够使用的情况下使用的,使用它必须保证文件所在的分区支持ACL df -h:查看系统所有分区信息 dumpe2fs -h /dev/vda1,可以查看分区 ...

  4. Linux 用户和用户组管理-用户信息文件

    用户信息文件存在在/etc/passwd中,vi /etc/passwd 其中,有七列以:分隔的信息 第一列表示用户(account),第二列表示密码标志(真正的密码存在在/etc/shadow中), ...

  5. (三)Host头攻击

    01 漏洞描述 为了方便获取网站域名,开发人员一般依赖于请求包中的Host首部字段.例如,在php里用_SERVER["HTTP_HOST"].但是这个Host字段值是不可信赖的( ...

  6. 彻底搞懂 etcd 系列文章(三):etcd 集群运维部署

    0 专辑概述 etcd 是云原生架构中重要的基础组件,由 CNCF 孵化托管.etcd 在微服务和 Kubernates 集群中不仅可以作为服务注册与发现,还可以作为 key-value 存储的中间件 ...

  7. 关于Graph Convolutional Network的初步理解

    为给之后关于图卷积网络的科研做知识积累,这里写一篇关于GCN基本理解的博客.GCN的本质是一个图网络中,特征信息的交互+与传播.这里的图指的不是图片,而是数据结构中的图,图卷积网络的应用非常广泛 ,经 ...

  8. intput子系统

    1.按键驱动程序的第一个版本:day07/04      //内核模块的基本要求   init.h module.h LICENSE      struct cdev btn_cdev;      b ...

  9. C语言视频教程下载(百万年薪程序员录制,免费公开)

    <C/C++语言高性能服务开发基础>您可以自由下载.传播.发布或其它商业用途. 视频文件共13.6G,提供了QQ群文件和百度网盘两种方法,建议采用QQ群文件下载,速度较快. 一.下载方法 ...

  10. postgresql中进行备份和回滚的常用sql语句小结

    最近在项目中需要对已有的部分数据库数据进行备份,通过搜索和实践,把常用的sql以及过程记录如下, 1.常用的备份数据库思路,把需要备份的数据放到一个新表中,这个新表的记录与需要备份的表完全一样,然后备 ...