C++自定义封装socket操作业务类完整实例

所属分类: 软件编程 / C 语言 阅读数: 102
收藏 0 赞 0 分享

本文实例讲述了C++自定义封装socket操作业务类。分享给大家供大家参考,具体如下:

Linux下C++封装socket操作的工具类(自己实现)

socketconnector.h

#ifndef SOCKETCONNECTOR_H
#define SOCKETCONNECTOR_H
#include "global.h"
using namespace std;
class SocketConnector
{
public:
  typedef enum {
    ENormal,
    EOther,
  } SocketState;
public:
  static SocketConnector * getInstance();
  inline SocketState state(){ return m_state; }
  inline void setState(SocketState _state){  m_state = _state;  }
  inline bool isConnected() { return m_isConnected;  }
  inline void setConnected(bool state) { m_isConnected = state; }
  void start();
  inline void setServerIP(string ip){  m_server_ip = ip;}
  inline void setServerPort(int port){ m_server_port = port; }
  int connect_sockfd();
  int onSendMessage(string & message);
private:
  SocketConnector();
  void onConnectToServer(string & ip,int port);
  static void * onReportMessage(void * p);
  static void * onReadMessage(void * p);
  static void * onWriteMessage(void * p);
private:
  SocketState m_state;
  bool m_isConnected;
  int m_sockFd;
  string m_server_ip;
  int m_server_port;
  pthread_t m_report_tid;
  pthread_t m_read_tid;
  pthread_t m_write_tid;
};
#endif // SOCKETCONNECTOR_H

socketconnector.cpp

#include "global.h"
#include "socketconnector.h"
#include "cmessagecenter.h"
#include "cmip_requestparser.h"
#include "csettings.h"
#include "datadef.h"
#include "cstringutils.h"
using namespace std;
static SocketConnector * g_instance = NULL;
/**************************************************************************************************
*  Single Instance.
***************************************************************************************************/
SocketConnector * SocketConnector::getInstance()
{
  if (g_instance == NULL)
  {
    g_instance = new SocketConnector();
  }
  return g_instance;
}
/**************************************************************************************************
*  Consturoctor
***************************************************************************************************/
SocketConnector::SocketConnector()
{
  m_isConnected = false;
  m_state = ENormal;
}
/**************************************************************************************************
*  Connect to Server By Blocking Method.
***************************************************************************************************/
void SocketConnector::onConnectToServer(string & ip,int port){
  cout << __FUNCTION__ << "connecting::[" << ip << " , " << port << "]" << endl;
  struct timeval send_timeout;
  send_timeout.tv_sec = 5;
  send_timeout.tv_usec = 0;
  int keepalive = 1;
  int keepidle = 10;
  int keepinterval = 5;
  int keepcount = 3;
  int value = 0;
  socklen_t len = sizeof(int);
  static struct sockaddr_in server_addr;
  memset(&server_addr, 0, sizeof(server_addr));
  server_addr.sin_family = AF_INET;
  server_addr.sin_port = htons(port);
  server_addr.sin_addr.s_addr = inet_addr(ip.c_str());
  do
  {
    m_sockFd = socket(AF_INET, SOCK_STREAM, 0);
    if ( -1 == m_sockFd )
    {
      sleep(1);
      continue;
    }
  }while(-1 == m_sockFd);
  if(setsockopt(m_sockFd, SOL_SOCKET, SO_SNDTIMEO, &send_timeout, sizeof(send_timeout)) == -1)
  {
    printf("setsockopt SO_SNDTIMEO fail\n");
  }
  if(setsockopt(m_sockFd, SOL_SOCKET, SO_KEEPALIVE, (void *)&keepalive , sizeof(keepalive )) == -1)
  {
    printf("setsockopt SO_KEEPALIVE fail\n");
  }
  if(setsockopt(m_sockFd, SOL_TCP, TCP_KEEPIDLE, (void*)&keepidle , sizeof(keepidle )) == -1)
  {
    printf("setsockopt TCP_KEEPIDLE fail\n");
  }
  if(setsockopt(m_sockFd, SOL_TCP, TCP_KEEPINTVL, (void *)&keepinterval , sizeof(keepinterval )) == -1)
  {
    printf("setsockopt TCP_KEEPINTVL fail\n");
  }
  if(setsockopt(m_sockFd, SOL_TCP, TCP_KEEPCNT, (void *)&keepcount , sizeof(keepcount )) == -1)
  {
    printf("setsockopt TCP_KEEPCNT fail\n");
  }
  getsockopt(m_sockFd, SOL_TCP, TCP_KEEPINTVL, (void *)&value, &len);
  cout << __FUNCTION__ << "sockFd KeepIntval::[" << value << endl;
  while (!m_isConnected)
  {
    if(connect(m_sockFd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) == 0)
    {
      m_isConnected = true;
      break;
    }
    else
    {
      if ( ECONNREFUSED == errno)
      {
        m_isConnected = false;
        sleep(1);
        printf("Reconnect To Server:%s Port:%d\n", m_server_ip.c_str(), m_server_port);
      }
      else
      {
        m_isConnected = false;
        perror("connected() error()");
        exit(-1);
      }
    }
  }
}
/**************************************************************************************************
*  Create Report Thread;
*  Create Read Thread;
*  Create Write Thread;
*  MainThread wait the subThreads exits;
***************************************************************************************************/
void SocketConnector::start()
{
  m_sockFd = connect_sockfd();
  cout << __FUNCTION__ << "Will Create Report|Read|Write Thread." << endl;
  pthread_create(&m_report_tid,NULL, onReportMessage, this);  /* report to cmdmodule*/
  pthread_create(&m_read_tid, NULL, onReadMessage, this);  /* read from cmdmodule*/
  pthread_create(&m_write_tid, NULL, onWriteMessage, this);  /* reply to cmdmodule*/
  pthread_join(m_read_tid,NULL);
  pthread_join(m_write_tid,NULL);
  pthread_join(m_report_tid,NULL);
}
/**************************************************************************************************
*  Used to Get connected socket fd.
*  if connected, return directly.
*  if not connected,try to create connect fd.
***************************************************************************************************/
int SocketConnector::connect_sockfd()
{
  if ( m_isConnected == true)
  {
    cout << __FUNCTION__ << "::Socket is Already Connected." << endl;
    return m_sockFd;
  }
  cout << __FUNCTION__ << "::Will Try to Connect to Server." << endl;
  onConnectToServer(m_server_ip, m_server_port);
  return m_sockFd;
}
/**************************************************************************************************
*  Report Status to CmdModule Thread.
*  every 2s ,report one message to cmdwifi.
***************************************************************************************************/
void * SocketConnector::onReportMessage(void * p)
{
  SocketConnector * connector = (SocketConnector *)(p);
  if ( NULL == p)
  {
    cout << __FUNCTION__ << "onSelectSocket() Error: param [connector] is NULL" << endl;
    return NULL;
  }
  string content;
  int devType = atoi(CSettings::getInstance()->getKuType().c_str());
  int report_interval = atoi(CSettings::getInstance()->getKuReportinterval().c_str());
  string position = CSettings::getInstance()->getKuPosition();
  string local_ip = CSettings::getInstance()->getKuAgentip();
  cout << endl;
  cout << "###################################" << endl;
  cout << "Local-IP::" << local_ip << endl;
  cout << "Ku-CMA-Pos::" << position << endl;
  cout << "Ku-CMA-Type::" << devType << endl;
  cout << "###################################" << endl;
  cout << endl;
  while(true)
  {
    int state = connector->state();
    content = "<status>" + CStringUtils::toString(state) + "</status>";
    content += "<type>" + CStringUtils::toString(devType) + "</type>";
    content += "<site>" + position + "</site>";
    content += "<ip>" + local_ip + "</ip>";
    Response resp(STATUS_REPORT_CMD,0,string(content));
    CMessageCenter::getInstance()->addReply(resp);
    sleep(report_interval);
  }
}
/**************************************************************************************************
*  Read Message from Connection.
*  Then Send Message to MessageCenter Queue.
***************************************************************************************************/
void * SocketConnector::onReadMessage(void * p)
{
  SocketConnector * connector = (SocketConnector *)(p);
  if ( NULL == p)
  {
    cout << __FUNCTION__ << "onSelectSocket() Error: param [connector] is NULL" << endl;
    return NULL;
  }
  int sockFd = connector->connect_sockfd();
  fd_set fds;
  struct timeval timeout={0,0};
  const int BUFFER_LEN = 4*1024;
  static char buffer[BUFFER_LEN]={0};
  while(true)
  {
    FD_ZERO(&fds);
    FD_SET(sockFd,&fds);
    int ret = select(sockFd + 1,&fds,NULL,NULL,&timeout);
    switch (ret) {
      case -1:/*Error process*/
      {
        perror("select()");
        if ( EBADF == errno)
        {
          close(sockFd);
          connector->setConnected(false);
          sleep(1);
          sockFd = connector->connect_sockfd();
          continue;
        }
        if ( EINTR == errno || ENOMEM == errno)
        {
          sleep(1);
          continue;
        }
      }break;
      case 0:
      {
        //cout << "select() timeout! " << endl;
      }break;
      default:
      {
        if(FD_ISSET(sockFd,&fds))
        {
          memset(buffer, 0, BUFFER_LEN);
          int nRead = read(sockFd, buffer, BUFFER_LEN);
          cout << ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>" << endl;
          cout << "From Server Recevied Data::" << string(buffer) << endl;
          cout << "From Server Recevied Length::" << nRead << endl;
          cout << ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>" << endl;
          CRequestParser parser;
          Request req;
          int ret = parser.parseToMessage(buffer,&req);
          if (0 != ret)
          {
            cout << __FUNCTION__ << "Request Format is invalid" << endl;
            continue;
          }
          req.print();
          CMessageCenter::getInstance()->addRequest(req);
        }
      }break;
    }
  }
}
/**************************************************************************************************
*  Write Message to Connection.
*  Then Send Message to MessageCenter Queue.
***************************************************************************************************/
void * SocketConnector::onWriteMessage(void * p)
{
  SocketConnector * connector = (SocketConnector *)(p);
  if ( NULL == p)
  {
    cout << __FUNCTION__ << "onSelectSocket() Error: param [connector] is NULL" << endl;
    return NULL;
  }
  while (true)
  {
      Response msg;
      CMessageCenter::getInstance()->getReplyMsg(msg);
      string data = CMessageEncoder(msg).encode();
      connector->onSendMessage(data);
  }
}
/**************************************************************************************************
*  Send Message By Socket.
***************************************************************************************************/
int SocketConnector::onSendMessage(string & strSend)
{
  if (atoi(CSettings::getInstance()->getDebugMode().c_str()) == 1)
  {
    cout << __FUNCTION__ << "Send To Cmdwifi Data::" << endl;
    cout << strSend << endl;
  }
  int sock = m_sockFd;
  char *pData = &strSend[0];
  int nLen = static_cast<int>(strSend.size());
  int nTotal = nLen;
  int i = 0;
  while(1)
  {
    int nTmp = send(sock, &pData[i], nTotal, 0);
    if (nTmp <= 0)
    {
      close(sock);
      return -1;
    }
    nTotal -= nTmp;
    i += nTmp;
    if (nTotal <= 0)
    {
      break;
    }
  }
  return 0;
}

希望本文所述对大家C++程序设计有所帮助。

更多精彩内容其他人还在看

用标准c++实现string与各种类型之间的转换

这个类在头文件中定义, < sstream>库定义了三种类:istringstream、ostringstream和stringstream,分别用来进行流的输入、输出和输入输出操作。另外,每个类都有一个对应的宽字符集版本
收藏 0 赞 0 分享

C++如何通过ostringstream实现任意类型转string

再使用整型转string的时候感觉有点棘手,因为itoa不是标准C里面的,而且即便是有itoa,其他类型转string不是很方便。后来去网上找了一下,发现有一个好方法
收藏 0 赞 0 分享

C/C++指针小结

要搞清一个指针需要搞清指针的四方面的内容:指针的类型,指针所指向的类型,指针的值或者叫指针所指向的内存区,还有指针本身所占据的内存区
收藏 0 赞 0 分享

C++ 类的静态成员深入解析

在C++中类的静态成员变量和静态成员函数是个容易出错的地方,本文先通过几个例子来总结静态成员变量和成员函数使用规则,再给出一个实例来加深印象
收藏 0 赞 0 分享

C++类的静态成员初始化详细讲解

通常静态数据成员在类声明中声明,在包含类方法的文件中初始化.初始化时使用作用域操作符来指出静态成员所属的类.但如果静态成员是整型或是枚举型const,则可以在类声明中初始化
收藏 0 赞 0 分享

C++类静态成员与类静态成员函数详解

静态成员不可在类体内进行赋值,因为它是被所有该类的对象所共享的。你在一个对象里给它赋值,其他对象里的该成员也会发生变化。为了避免混乱,所以不可在类体内进行赋值
收藏 0 赞 0 分享

C++中的friend友元函数详细解析

友元可以是一个函数,该函数被称为友元函数;友元也可以是一个类,该类被称为友元类。友元函数的特点是能够访问类中的私有成员的非成员函数。友元函数从语法上看,它与普通函数一样,即在定义上和调用上与普通函数一样
收藏 0 赞 0 分享

static全局变量与普通的全局变量的区别详细解析

以下是对static全局变量与普通的全局变量的区别进行了详细的分析介绍,需要的朋友可以过来参考下,希望对大家有所帮助
收藏 0 赞 0 分享

C++ explicit关键字的应用方法详细讲解

C++ explicit关键字用来修饰类的构造函数,表明该构造函数是显式的,既然有"显式"那么必然就有"隐式",那么什么是显示而什么又是隐式的呢?下面就让我们一起来看看这方面的知识吧
收藏 0 赞 0 分享

教你5分钟轻松搞定内存字节对齐

随便google一下,人家就可以跟你解释的,一大堆的道理,我们没怎么多时间,讨论为何要对齐.直入主题,怎么判断内存对齐规则,sizeof的结果怎么来的,请牢记以下3条原则
收藏 0 赞 0 分享
查看更多