網路資料收發通用代碼

來源:互聯網
上載者:User

    對於任何一個支援網路通訊的應用程式,它都有其自身的應用程式層通訊協定。該協議規定了應用程式發送什麼樣格式的網路資料或接收到某某資料時回送的資料格式。該協議是由應用程式層相關人員定製的。

    不同的應用程式有各自不同的網路資料處理模組,這似乎是不可移植的,但網路資料的發送和接收則是獨立於具體的應用程式層協議的。網路資料的發送和接收模組只與底層平台(作業系統)相關,而與應用程式層協議無關,它們只負責資料收發的穩定性、可靠性,而不管資料的具體含義。這一部分是可以移植的,我們可以編寫強大的資料收發類以使其滿足任何網路應用程式對於收發資料的需求。這樣,當我們下次再編寫應用程式的通訊模組時則只需要關注資料如何解析,而不用處理資料的收發。

    宏定義檔案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.og++ -o main main.o client_logic.o tcp_client.o server_logic.o tcp_server.o -lpthreadmain.o:main.cppg++ -c main.cpp -lpthreadclient_logic.o:client_logic.cpp g++ -c client_logic.cpp -lpthreadtcp_client.o:tcp_client.cppg++ -c tcp_client.cpp -lpthreadserver_logic.o:server_logic.cppg++ -c server_logic.cpp -lpthreadtcp_server.o:tcp_server.cppg++ -c tcp_server.cpp -lpthreadclean:rm *.o main

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.