网络数据收发通用代码

    对于任何一个支持网络通信的应用程序,它都有其自身的应用层通信协议。该协议规定了应用程序发送什么样格式的网络数据或接收到某某数据时回送的数据格式。该协议是由应用层相关人员定制的。

    不同的应用程序有各自不同的网络数据处理模块,这似乎是不可移植的,但网络数据的发送和接收则是独立于具体的应用层协议的。网络数据的发送和接收模块只与底层平台(操作系统)相关,而与应用层协议无关,它们只负责数据收发的稳定性、可靠性,而不管数据的具体含义。这一部分是可以移植的,我们可以编写强大的数据收发类以使其满足任何网络应用程序对于收发数据的需求。这样,当我们下次再编写应用程序的通信模块时则只需要关注数据如何解析,而不用处理数据的收发。

    宏定义文件def.h:

#ifndef __DEF_H__
#define __DEF_H__

#include <stdio.h>

#define BUF_LEN           100
#define TIMEVAL_SEND      6
#define TIMEVAL_RECV      3
#define TIMEVAL_ACCEPT    3
#define TIMEVAL_RECONNECT 5
#define TIMEVAL_THREAD    100000000

#ifndef BOOL
#define BOOL int
#endif

#ifndef TRUE
#define TRUE 1
#endif

#ifndef FALSE
#define FALSE 0
#endif

#define mylog printf

#endif

    客户端数据收发类定义文件(tcp_client.h):

#ifndef __TCP_CLIENT_H__
#define __TCP_CLIENT_H__

#include "def.h"

class CClientLogic;

class CTCPClient
{
 public:
  CTCPClient(const char* ip, int port);

  ~CTCPClient();

  int init();

  int uninit();

  int setLogicObject(CClientLogic* pClientLogic);

  int connectServer();

  int sendData(const char* buf, int len);

  int recvData(char* buf, int len);
 private:
  int offline();

  int online();
 private:
  char m_ip[BUF_LEN];
  int  m_port;
  int  m_sockfd;

  CClientLogic* m_logic;
};

#endif

    客户端数据收发类实现文件(tcp_client.cpp):

#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/select.h>
#include <sys/time.h>
#include <netinet/tcp.h>
#include <errno.h>

#include "client_logic.h"
#include "tcp_client.h"

CTCPClient::CTCPClient(const char* ip, int port)
{
  strncpy(m_ip, ip, BUF_LEN);
  
  m_port   = port;
  m_sockfd = -1;
}

CTCPClient::~CTCPClient()
{
  uninit();
}

int CTCPClient::init()
{
  return 0;
}

int CTCPClient::uninit()
{
  if (m_sockfd > 0)
  {
    close(m_sockfd);
    m_sockfd = -1;
  }
      
  return 0;
}

int CTCPClient::setLogicObject(CClientLogic* pClientLogic)
{
  if (!pClientLogic)
  {
    mylog("tcpclient: client object is null.\n");
    return -1;
  }

  m_logic = pClientLogic;
  return 0;
}

int CTCPClient::connectServer()
{
  if (m_sockfd > 0)
  {
    offline();
  }

  if ((m_sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
  {
    mylog("tcpclient: create socket failed.\n");
    return -1;
  }

  struct sockaddr_in servaddr;
  memset(&servaddr, 0, sizeof(servaddr));
  servaddr.sin_family      = AF_INET;
  servaddr.sin_addr.s_addr = inet_addr(m_ip);
  servaddr.sin_port        = htons(m_port);
  if (connect(m_sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0)
  {
    close(m_sockfd);
    m_sockfd = -1;
    mylog("tcpclient: can not connect to server.\n");
    return -1;
  }

  /*
   * set socket options
   */
  int     iKeepIdle     = 60;
  int     iKeepInterval = 60;
  int     iKeepCount    = 3; 
  int     iOne          = 1;

  setsockopt(m_sockfd, SOL_SOCKET,  SO_KEEPALIVE,  (const void *)&iOne,          sizeof(int));
  setsockopt(m_sockfd, IPPROTO_TCP, TCP_KEEPIDLE,  (const void *)&iKeepIdle,     sizeof(int));
  setsockopt(m_sockfd, IPPROTO_TCP, TCP_KEEPINTVL, (const void *)&iKeepInterval, sizeof(int));
  setsockopt(m_sockfd, IPPROTO_TCP, TCP_KEEPCNT,   (const void *)&iKeepCount,    sizeof(int));

  online();

  return 0;
}

int CTCPClient::sendData(const char* buf, int len)
{
  if (NULL == buf || len <= 0)
  {
    mylog("tcpclient: data(send) illegal.\n");
    return -1;
  }

  if (m_sockfd < 0)
  {
    mylog("tcpclient: connecttion has not been established, send data faield.\n");
    return -1;
  }

  fd_set set_w;
  struct timeval timeout;

  FD_ZERO(&set_w);
  FD_SET(m_sockfd, &set_w);
  timeout.tv_sec  = TIMEVAL_SEND;
  timeout.tv_usec = 0;

  if (select(m_sockfd + 1, NULL, &set_w, NULL, &timeout) <= 0)
  {
    mylog("tcpclient: network status is busy, failed to send data.\n");
    offline();
    return -1;
  }

  int sendLen = 0;
  if (FD_ISSET(m_sockfd, &set_w))
  {
    sendLen = send(m_sockfd, buf, len, 0);
    if (sendLen < len)
    {
      if (sendLen >= 0)
	mylog("tcpclient: send data less than request.\n");
      else
      {
	if (EMSGSIZE == errno)
	{
	  mylog("tcpclient: buffer to be sent is too large.\n");
	}
	else if (EAGAIN != errno && EWOULDBLOCK != errno)
	{
	  offline();
	  return -1;
	}
      }

      mylog("tcpclient: send data failed.\n");
      return -1;
    }
  }

  return sendLen;
}

int CTCPClient::recvData(char* buf, int len)
{
  if (m_sockfd < 0)
  {
    mylog("tcpclient: connection has not been established.recv data failed.\n");
    return -1;
  }

  fd_set set_r;
  struct timeval timeout;

  FD_ZERO(&set_r);
  FD_SET(m_sockfd, &set_r);
  timeout.tv_sec  = TIMEVAL_RECV;
  timeout.tv_usec = 0;

  int ret = select(m_sockfd + 1, &set_r, NULL, NULL, &timeout);
  if (ret < 0)
  {
    mylog("tcpclient: select failed, recv data failed.\n");
    offline();
    return -1;
  }
  else if (0 == ret)
  {
    return -1;
  }

  if (FD_ISSET(m_sockfd, &set_r))
  {
    int recvLen = recv(m_sockfd, buf, len, 0);
    if (recvLen <= 0)
    {
      if (ETIMEDOUT != errno && EWOULDBLOCK != errno)
      {
	mylog("tcpclient: recv data failed.\n");
	offline();
      }
      
      return -1;
    }
    return recvLen;
  }

  return -1;
}

int CTCPClient::offline()
{
  if (m_sockfd > 0)
  {
    close(m_sockfd);
    m_sockfd = -1;
  }

  if (m_logic)
    m_logic->offline();

  return 0;
}

int CTCPClient::online()
{
  if (m_logic)
    m_logic->online();
}
    服务器端数据收发类定义文件(tcp_server.h):
#ifndef __TCP_SERVER_H__
#define __TCP_SERVER_H__

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#include "def.h"

class CServerLogic;

class CTCPServer
{
 public:
  CTCPServer(int port);

  ~CTCPServer();

  int init();

  int uninit();

  int setLogicObject(CServerLogic* pServerLogic);

  int acceptClient();

  int sendData(const char* buf, int len);

  int recvData(char* buf, int len);

  int getStrAddr(char* ip, int len);
 private:
  int offline();

  int online();
 private:
  int m_port;
  int m_sockfd;

  int                m_clifd;
  struct sockaddr_in m_cliaddr;

  CServerLogic* m_logic;
};

#endif
    服务器端数据收发类实现文件(tcp_server.cpp):
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/select.h>
#include <sys/time.h>
#include <errno.h>

#include "server_logic.h"
#include "tcp_server.h"

CTCPServer::CTCPServer(int port)
{
  m_port   = port;
  m_sockfd = -1;

  m_clifd = -1;
  memset(&m_cliaddr, 0, sizeof(m_cliaddr));
}

CTCPServer::~CTCPServer()
{
  uninit();
}

int CTCPServer::init()
{
  if ((m_sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
  {
    mylog("tcpserver: create socket failed.\n");
    return -1;
  }

  struct sockaddr_in servaddr;
  memset(&servaddr, 0, sizeof(servaddr));
  servaddr.sin_family      = AF_INET;
  servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
  servaddr.sin_port        = htons(m_port);
  if (bind(m_sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0)
  {
    mylog("tcpserver: bind error.\n");
    close(m_sockfd);
    m_sockfd = -1;
    return -1;
  }

  if (listen(m_sockfd, 9) < 0)
  {
    mylog("tcpserver: listen error.\n");
    close(m_sockfd);
    m_sockfd = -1;
    return -1;
  }

  return 0;
}

int CTCPServer::uninit()
{
  if (m_clifd > 0)
  {
    close(m_clifd);
    m_clifd = -1;
  }
  
  if (m_sockfd > 0)
  {
    close(m_sockfd);
    m_sockfd = -1;
  }
  
  return 0;
}

int CTCPServer::setLogicObject(CServerLogic* pServerLogic)
{
  if (!pServerLogic)
  {
    mylog("tcpserver: server logic object is null.\n");
    return -1;
  }

  m_logic = pServerLogic;
  return 0;
}

int CTCPServer::acceptClient()
{
  if (m_sockfd < 0)
  {
    mylog("tcpserver: server socket not created, accept client failed.\n");
    return -1;
  }

  if (m_clifd > 0)
  {
    offline();// disconnect
  }

  fd_set set_r;
  struct timeval timeout;
  FD_ZERO(&set_r);
  FD_SET(m_sockfd, &set_r);
  timeout.tv_sec  = TIMEVAL_ACCEPT;
  timeout.tv_usec = 0;

  if (select(m_sockfd + 1, &set_r, NULL, NULL, &timeout) <= 0)
    return -1;

  if (FD_ISSET(m_sockfd, &set_r))// if socket is ready to accept
  {
    socklen_t clilen = sizeof(m_cliaddr);
    if ((m_clifd = accept(m_sockfd, (struct sockaddr*)&m_cliaddr, &clilen)) < 0)
    {
      mylog("tcpserver: accept error.\n");
      return -1;
    }

    online();// connection is build
    
    return 0;
  }

  return -1;
}

int CTCPServer::sendData(const char* buf, int len)
{
  if (NULL == buf || len <= 0)
  {
    mylog("tcpserver: data(send) illegal.\n");
    return -1;
  }

  if (m_clifd < 0)
  {
    mylog("tcpserver: connecttion has not been established,send data faield.\n");
    return -1;
  }

  fd_set set_w;
  struct timeval timeout;

  FD_ZERO(&set_w);
  FD_SET(m_clifd, &set_w);
  timeout.tv_sec  = TIMEVAL_SEND;
  timeout.tv_usec = 0;

  if (select(m_clifd + 1, NULL, &set_w, NULL, &timeout) <= 0)
  {
    mylog("tcpserver: network status is busy, failed to send data.\n");
    offline();
    return -1;
  }

  int sendLen = 0;
  if (FD_ISSET(m_clifd, &set_w))
  {
    sendLen = send(m_sockfd, buf, len, 0);
    if (sendLen < len)
    {
      if (sendLen >= 0)
	mylog("tcpserver: send data less than request.\n");
      else
      {
	if (EMSGSIZE == errno)
	{
	  mylog("tcpserver: buffer to be sent is too large.\n");
	}
	else if (EAGAIN != errno && EWOULDBLOCK != errno)
	{
	  offline();
	  return -1;
	}
      }

      mylog("tcpserver: send data failed.\n");
      return -1;
    }
  }

  return sendLen;
}

int CTCPServer::recvData(char* buf, int len)
{
  if (m_clifd < 0)
  {
    mylog("tcpserver: connection has not been established, recv data failed.\n");
    return -1;
  }

  fd_set set_r;
  struct timeval timeout;

  FD_ZERO(&set_r);
  FD_SET(m_clifd, &set_r);
  timeout.tv_sec  = TIMEVAL_RECV;
  timeout.tv_usec = 0;

  int ret = select(m_clifd + 1, &set_r, NULL, NULL, &timeout);
  if (ret < 0)
  {
    mylog("tcpserver: select failed, recv data failed.\n");
    offline();
    return -1;
  }
  else if (0 == ret)// timeout
  {
    return -1;
  }

  if (FD_ISSET(m_clifd, &set_r))
  {
    int recvLen = recv(m_clifd, buf, len, 0);
    if (recvLen <= 0)
    {
      if (ETIMEDOUT != errno && EWOULDBLOCK != errno)
      {
	mylog("tcpserver: recv data failed.\n");
	offline();
      }
      
      return -1;
    }
    return recvLen;
  }

  return -1;
}

int CTCPServer::offline()
{
  if (m_clifd > 0)
  {
    close(m_clifd);
    m_clifd = -1;
  }

  if (m_logic)
    m_logic->offline();

  return 0;
}

int CTCPServer::online()
{
  if (m_logic)
    m_logic->online();
}

int CTCPServer::getStrAddr(char* ip, int len)
{
  if (m_clifd < 0)// connection hasn't been established
    return -1;

  strncpy(ip, inet_ntoa(m_cliaddr.sin_addr), len);
  return 0;
}

    即时通讯应用程序客户端逻辑处理类定义(client_logic.h):

#ifndef __CLIENT_LOGIC_H__
#define __CLIENT_LOGiC_H__

#include <pthread.h>
#include <semaphore.h>
#include <iostream>
#include <queue>
#include <cstring>
#include <string>

#include "tcp_client.h"

class CClientLogic:public CTCPClient
{
 public:
  CClientLogic(const char* ip, int port);

  ~CClientLogic();

  int init();

  int uninit();

  int start();

  int stop();

  int online();

  int offline();

  std::queue<std::string>& getDataQue();
 private:
  static void* clientThread(void* args);
 private:
  pthread_t      m_tid;
  pthread_attr_t m_attr;
  sem_t          m_sem;

  BOOL m_runFlag;
  BOOL m_isConnected;

  std::queue<std::string> m_dataQue;
};

#endif
    即时通讯应用程序客户端逻辑处理类实现(client_logic.cpp):
#include <pthread.h>
#include <semaphore.h>

#include "client_logic.h"

CClientLogic::CClientLogic(const char* ip, int port):CTCPClient(ip, port)
{
  m_runFlag     = FALSE;
  m_isConnected = FALSE;
}

CClientLogic::~CClientLogic()
{
}

int CClientLogic::init()
{
  if (CTCPClient::init() != 0)
    return -1;
  
  sem_init(&m_sem, 0, 0);
  pthread_attr_init(&m_attr);
  setLogicObject(this);
  
  return 0;
}

int CClientLogic::uninit()
{
  pthread_attr_destroy(&m_attr);
  sem_destroy(&m_sem);

  if (CTCPClient::uninit() != 0)
    return -1;
  
  return 0;
}

int CClientLogic::start()
{
  if (m_runFlag)
  {
    mylog("client: thread already started.\n");
    return 0;
  }

  m_runFlag = TRUE;
  if(pthread_create(&m_tid, &m_attr, clientThread, this) == 0)
  {
    return 0;
  }
  else
  {
    mylog("client: thread created failed.\n");
    m_runFlag = FALSE;
    return -1;
  }
}

int CClientLogic::stop()
{
  if (!m_runFlag)
  {
    mylog("client: thread was not started.\n");
    return 0;
  }

  m_runFlag = FALSE;
  sem_post(&m_sem);
  pthread_join(m_tid, NULL);
  
  return 0;
}

void* CClientLogic::clientThread(void* args)
{
  CClientLogic* thiz = (CClientLogic*)args;
  struct timespec ts;
  
  while (thiz->m_runFlag)
  {
    if (!thiz->m_dataQue.empty())
    {
      if (thiz->m_isConnected)// connection is established
      {
	std::string str = thiz->m_dataQue.front();
	thiz->m_dataQue.pop();
	thiz->sendData(str.c_str(), str.length());
      }
      else
      {
	if (thiz->connectServer() != 0)
	{
	  ts.tv_sec  = time(NULL) + TIMEVAL_RECONNECT;
	  ts.tv_nsec = 0;
	  sem_timedwait(&thiz->m_sem, &ts);
	  continue;
	}
      }
    }
    
    ts.tv_sec  = time(NULL);
    ts.tv_nsec = TIMEVAL_THREAD;
    sem_timedwait(&thiz->m_sem, &ts);
  }
}

std::queue<std::string>& CClientLogic::getDataQue()
{
  return m_dataQue;
}

int CClientLogic::online()
{
  m_isConnected = TRUE;
  return 0;
}

int CClientLogic::offline()
{
  m_isConnected = FALSE;
  return 0;
}

    即时通讯应用程序服务器端逻辑处理类定义(server_logic.h):

#ifndef __SERVER_LOGIC_H__
#define __SERVER_LOGIC_H__

#include <pthread.h>
#include <semaphore.h>

#include "tcp_server.h"

class CServerLogic:public CTCPServer
{
 public:
  CServerLogic(int port);

  ~CServerLogic();

  int init();

  int uninit();

  int start();

  int stop();

  int online();
  
  int offline();
 private:
  static void* serverThread(void* args);
 private:
  pthread_t      m_tid;
  pthread_attr_t m_attr;
  sem_t          m_sem;

  BOOL m_runFlag;
  BOOL m_isConnected;
};

#endif
    即时通讯应用程序服务器端逻辑处理类实现(server_logic.cpp):
#include <pthread.h>
#include <semaphore.h>

#include "server_logic.h"

CServerLogic::CServerLogic(int port):CTCPServer(port)
{
  m_runFlag     = FALSE;
  m_isConnected = FALSE;
}

CServerLogic::~CServerLogic()
{}

int CServerLogic::init()
{
  if (CTCPServer::init() != 0)
    return -1;

  sem_init(&m_sem, 0, 0);
  pthread_attr_init(&m_attr);
  setLogicObject(this);
  
  return 0;
}

int CServerLogic::uninit()
{
  pthread_attr_destroy(&m_attr);
  sem_destroy(&m_sem);

  if (CTCPServer::uninit() != 0)
    return -1;
  
  return 0;
}

int CServerLogic::online()
{
  m_isConnected = TRUE;
  return 0;
}

int CServerLogic::offline()
{
  m_isConnected = FALSE;
  return 0;
}

int CServerLogic::start()
{
  if (m_runFlag)
  {
    mylog("server: thread already started.\n");
    return 0;
  }

  m_runFlag = TRUE;
  if (pthread_create(&m_tid, &m_attr, serverThread, this) == 0)
  {
    return 0;
  }
  else
  {
    m_runFlag = FALSE;
    return -1;
  }
}  

int CServerLogic::stop()
{
  if (!m_runFlag)
  {
    mylog("server: thread is not running.\n");
    return 0;
  }

  m_runFlag = FALSE;
  sem_post(&m_sem);
  pthread_join(m_tid, NULL);
  
  return 0;
}

void* CServerLogic::serverThread(void* args)
{
  CServerLogic* thiz = (CServerLogic*)args;
  struct timespec ts;
  char recvbuf[BUF_LEN];
  char ipBuf[BUF_LEN] = {0};

  while (thiz->m_runFlag)
  {
    if (thiz->m_isConnected)// connection already established
    {
      int recvLen = thiz->recvData(recvbuf, BUF_LEN - 1);
      if (recvLen > 0)
      {
	recvbuf[recvLen] = '\0';
	thiz->getStrAddr(ipBuf, BUF_LEN);
	printf("%s: %s\n", ipBuf, recvbuf);
      }
    }
    else
    {
      thiz->acceptClient();
    }
    
    ts.tv_sec  = time(NULL);
    ts.tv_nsec = TIMEVAL_THREAD;
    sem_timedwait(&thiz->m_sem, &ts);
  }
}
    main.cpp文件:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string>
#include <iostream>
#include <queue>

#include "server_logic.h"
#include "client_logic.h"

int main(int argc, char* argv[])
{
  char ip[BUF_LEN];
  
  if (argc != 2)
    strncpy(ip, "127.0.0.1", BUF_LEN);
  else
    strncpy(ip, argv[1], BUF_LEN);

  CServerLogic servLogic(8889);
  if (servLogic.init() != 0)
  {
    printf("server init failed.\n");
    return 0;
  }
  servLogic.start();

  CClientLogic cliLogic(ip, 8889);
  cliLogic.init();
  cliLogic.start();

  std::queue<std::string>& que = cliLogic.getDataQue();
  char sendbuf[BUF_LEN];
  while (gets(sendbuf) && strncmp(sendbuf, "end", strlen("end")) != 0 )
  {
    que.push(sendbuf);
  }

  cliLogic.stop();
  cliLogic.uninit();

  servLogic.stop();
  servLogic.uninit();

  return 0;
}
    makefile文件:
main:main.o client_logic.o tcp_client.o server_logic.o tcp_server.o
	g++ -o main main.o client_logic.o tcp_client.o server_logic.o tcp_server.o -lpthread
main.o:main.cpp
	g++ -c main.cpp -lpthread
client_logic.o:client_logic.cpp 
	g++ -c client_logic.cpp -lpthread
tcp_client.o:tcp_client.cpp
	g++ -c tcp_client.cpp -lpthread
server_logic.o:server_logic.cpp
	g++ -c server_logic.cpp -lpthread
tcp_server.o:tcp_server.cpp
	g++ -c tcp_server.cpp -lpthread
clean:
	rm *.o main

#ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN #endif #include #include #include #pragma comment(lib, "ws2_32") // Set the packing to a 1 byte boundary #include // // Define the IPv4 header. Make the version and length field one // character since we can't declare two 4 bit fields without // the compiler aligning them on at least a 1 byte boundary. // typedef struct ip_hdr { unsigned char ip_verlen; // 4-bit IPv4 version // 4-bit header length (in 32-bit words) unsigned char ip_tos; // IP type of service unsigned short ip_totallength; // Total length unsigned short ip_id; // Unique identifier unsigned short ip_offset; // Fragment offset field unsigned char ip_ttl; // Time to live unsigned char ip_protocol; // Protocol(TCP,UDP etc) unsigned short ip_checksum; // IP checksum unsigned int ip_srcaddr; // Source address unsigned int ip_destaddr; // Source address } IPV4_HDR, *PIPV4_HDR, FAR * LPIPV4_HDR; // // Define the UDP header // typedef struct udp_hdr { unsigned short src_portno; // Source port no. unsigned short dst_portno; // Dest. port no. unsigned short udp_length; // Udp packet length unsigned short udp_checksum; // Udp checksum (optional) } UDP_HDR, *PUDP_HDR; // Restore the byte boundary back to the previous value #include // // Function: checksum // // Description: // This function calculates the 16-bit one's complement sum // for the supplied buffer. // USHORT checksum(USHORT *buffer, int size) { unsigned long cksum=0; while (size > 1) { cksum += *buffer++; size -= sizeof(USHORT); } if (size) { cksum += *(UCHAR*)buffer; } cksum = (cksum >> 16) + (cksum & 0xffff); cksum += (cksum >>16); return (USHORT)(~cksum);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值