服务器使用环形缓冲区处理接收数据

来源:互联网 发布:大数据基金净值 编辑:程序博客网 时间:2024/05/17 00:04

(一).前言
通信过程中,对接收数据,若是网络环境糟糕,会出现多个数据包同时到达;

在recv 读取数据时,一般读取固定长度的数据,可能出现读出下图,读出不完整数据包的情况,若是直接处理,数据不完整,若是忽略,那么下次读取的时候,读到的数据也不完整,出现数据丢失,或数据发送错误的断言;
这里写图片描述

最近研究一些前辈对这种情况的处理方法,就是使用环形缓冲区,写这篇博客记录下;

(二).环形缓冲的介绍链接

http://blog.csdn.net/Aguangg_6655_la/article/details/55806382?locationNum=1&fps=1

(三).实现的源码
1.buf.h

#ifndef _COMM_BUF_H_#define _COMM_BUF_H_#include <sys/mman.h>#include <unistd.h>#include <time.h>#include <sys/types.h>#include <sys/stat.h>#include <errno.h>#include <fcntl.h>#include <stdarg.h>#include <stdio.h>#include <stdlib.h>#include <stdint.h>#include <string.h>#define UNUSED(x) ( (void)(x) )typedef unsigned char u_char;struct buf_s {        u_char         *buf_file;       /*mmap file*/        u_char         *buf_start;      /*内存起始位*/        u_char         *buf_end;        /*内存结束位*/        u_char         *buf_pos;        /*数据起始位*/        size_t         buf_size;       /*缓冲区总大小*/        size_t         buf_len;        /*当前占用空间大小*/};struct buf_s *buf_calloc(size_t size);struct buf_s *buf_mmap(size_t size, const char *file);int buf_append(struct buf_s **buf, u_char *data, size_t len);void buf_reset(struct buf_s *buf);int buf_pull(struct buf_s *buf, u_char *data, size_t len);int buf_del(struct buf_s *buf, size_t len);void buf_free(struct buf_s *buf);#endif

2.buf.c

#include "buf.h"/*   建立缓冲区结构,并分配内存 */struct buf_s *buf_calloc(size_t size){        struct buf_s *buf;        buf = (struct buf_s*)calloc(1, sizeof(struct buf_s));        if (buf == NULL) { /*内存分配出错*/                return NULL;        }        buf->buf_start = (u_char *)calloc(1, size);        if (buf->buf_start == NULL) {                free(buf);                return NULL;        }        buf->buf_size = size;        buf->buf_pos = buf->buf_start;        buf->buf_end = buf->buf_start + size;        /*buf_file, buf_len = 0, NULL*/        return buf;}/*   建立缓冲区结构,并分配内存 */#if !defined(_WIN32)struct buf_s *buf_mmap(size_t size, const char *file){        struct buf_s *buf;        void *map;        int fd, i;        /*初始化结构*/        if ((buf = buf_calloc(size)) == NULL) {                buf_free(buf);                return NULL;        }        /*判断mmap文件是否存在*/        if (access(file ,F_OK) == -1) { /*file not exist*/                if ((fd = open(file, O_RDWR|O_CREAT)) == -1) {                        buf_free(buf);                        return NULL;                }                if (write(fd, buf->buf_start, size) == -1) {                        buf_free(buf);                        close(fd);                        return NULL;                }                map = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);                if (map == MAP_FAILED) {                        buf_free(buf);                        free(buf->buf_start);                        close(fd);                        return NULL;                }                close(fd);                free(buf->buf_start);                buf->buf_start = buf->buf_pos = (u_char *)map;                buf->buf_end = buf->buf_start + size;                buf->buf_file = (u_char*)file;               /*need test*/                return buf;        } else {  /*file exist*/                if ((fd = open(file, O_RDWR)) == -1) {                        buf_free(buf);                        return NULL;                }                map = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);                if (map == MAP_FAILED) {                        buf_free(buf);                        free(buf->buf_start);                        close(fd);                        return NULL;                }                free(buf->buf_start);                close(fd);                buf->buf_start = (u_char*)map;                buf->buf_end = buf->buf_start + size;                buf->buf_file = (u_char*)file;                for (i=0; i<(int)size; i++) {            /*找回pos位置*/                        if (buf->buf_start[i] != 0x00) {                                buf->buf_pos = buf->buf_start+i;                                break;                        }                }                for (i=(int)size-1; i>=0; i--) {            /*找回len*/                        if (buf->buf_start[i] != 0x00) {                                buf->buf_len = buf->buf_start + i - buf->buf_pos + 1;                                break;                        }                }                return buf;        }}#endif/*   添加数据进入缓冲区 */int buf_append(struct buf_s **buf, u_char *data, size_t len){        /*缓冲区溢出*/        if (((*buf)->buf_size - (*buf)->buf_len) < len) {                /*初始化结构*/                u_char *new_start = NULL;                size_t new_len = len + (*buf)->buf_len;                /*为buf_size的整数倍*/                new_len = (new_len + (*buf)->buf_size) & (~((*buf)->buf_size - 1));                /*重新分配内存*/                new_start = (u_char*)realloc((*buf)->buf_start, new_len);                if(!new_start){                    return -1;                }                (*buf)->buf_start = new_start;                (*buf)->buf_size = new_len;                   }        /*移动数据*/        //printf("len:%d end:%x pos:%x\n", len, buf->buf_end, buf->buf_pos);        if ((size_t)((*buf)->buf_end - (*buf)->buf_pos) < len) {                memmove((*buf)->buf_start, (*buf)->buf_pos, (*buf)->buf_len);                memset((*buf)->buf_start+(*buf)->buf_len, 0, (*buf)->buf_size-(*buf)->buf_len);                (*buf)->buf_pos = (*buf)->buf_start;        }        /*添加数据*/        memcpy((*buf)->buf_pos+(*buf)->buf_len, data, len);        (*buf)->buf_len += len;        return (*buf)->buf_len;}void buf_reset(struct buf_s *buf){        memset(buf->buf_start, 0, buf->buf_size);        buf->buf_pos = buf->buf_start;        buf->buf_len = 0;}/*   将数据从缓冲区读出来 */int buf_pull(struct buf_s *buf, u_char *data, size_t len){        int ret;        if (buf->buf_len == 0) {                errno = ENODATA;                return -1;        }        if (len >= buf->buf_len) {                memcpy(data, buf->buf_pos, buf->buf_len);                memset(buf->buf_pos, 0, buf->buf_len);                buf->buf_pos = buf->buf_start;                ret = buf->buf_len;                buf->buf_len = 0;                //buf->buf_pos = buf->buf_pos +len;        }else {                memcpy(data, buf->buf_pos, len);                memset(buf->buf_pos, 0, len);                buf->buf_pos = buf->buf_pos +len;                buf->buf_len = buf->buf_len -len;                ret = len;        }        return ret;}/*   将数据从缓冲区删除 */int buf_del(struct buf_s *buf, size_t len){        int ret;        if (buf->buf_len == 0) {                errno = ENODATA;                return -1;        }        if (len >= buf->buf_len) {                memset(buf->buf_pos, 0, buf->buf_len);                buf->buf_pos = buf->buf_start;                ret = buf->buf_len;                buf->buf_len = 0;                //buf->buf_pos = buf->buf_pos +len;        }else {                memset(buf->buf_pos, 0, len);                buf->buf_pos = buf->buf_pos +len;                buf->buf_len = buf->buf_len -len;                ret = len;        }        return ret;}/*   释放内存 */void buf_free(struct buf_s *buf){    if(buf == NULL) {        return;    }    if (buf->buf_file != NULL) {        UNUSED(NULL);#if !defined(_WIN32)        munmap(buf->buf_start, buf->buf_size);#endif    }    else {        if(buf->buf_start)            free(buf->buf_start);    }    free(buf);}

(四).在通信中的使用
RobotManager.h

#ifndef __CROBOTMANAGER_H__#define __CROBOTMANAGER_H__#include "../include/head.h"typedef class RobotList RL;class CRobotManager{public:      CRobotManager();      ~CRobotManager();      void sendDateByTerminal(const char *readBuf);      static void * recvDate(void *arg);      bool startThread();      bool machine_client();      void freeBuffer();      void dispatchRecvPacket();      inline void setRobotList(RL *robot)      {            m_cRobotList = robot;      }private:      pthread_t pth_recv;      int m_nSfd;      bool m_boStartRobot;      RL * m_cRobotList;      struct buf_s *m_pReadBuf;};#endif

RobotManager.cpp

#include "RobotManager.h"#include "../message/MsgPacket.h"#include <signal.h>#include <errno.h>#include "../buf/buf.h"CRobotManager::CRobotManager(){      pth_recv = 0;      m_nSfd = -1;      m_boStartRobot = false;      m_pReadBuf = NULL;}CRobotManager::~CRobotManager(){      if(pth_recv)            pthread_join(pth_recv, NULL);      freeBuffer();}void CRobotManager::freeBuffer(){      if(m_pReadBuf)      {            buf_free(m_pReadBuf);            m_pReadBuf = NULL;      }}void CRobotManager::dispatchRecvPacket(){      CMsgHead *pPacketHead = NULL;      while(m_pReadBuf->buf_len){            if(m_pReadBuf->buf_len < sizeof(CMsgHead)){                  return;            }            if(m_pReadBuf->buf_len < 0 || m_pReadBuf->buf_len > m_pReadBuf->buf_size)            {                  return;            }            pPacketHead = (CMsgHead *)m_pReadBuf->buf_pos;            if(!pPacketHead)            {                  return;            }            if(pPacketHead && pPacketHead->m_flag != 0xFFFF)            {                  printf("[warning]:packet header:msg.m_head.m_flag != 0xFFFF !!!!!\n");                  u_char *dataPos = m_pReadBuf->buf_pos;                  size_t bufSize = m_pReadBuf->buf_len;                  do{                        if(bufSize < sizeof(CMsgHead))                        {                              buf_del(m_pReadBuf, m_pReadBuf->buf_len);                              printf("can not research packet header, packet droped\n");                              return;                        }                        bufSize++;                        dataPos++;                        pPacketHead = (CMsgHead *)dataPos;                  }while(pPacketHead->m_flag != 0xFFFF);                  size_t moveLen = dataPos - m_pReadBuf->buf_pos;                  buf_del(m_pReadBuf, moveLen);            }            if(pPacketHead->m_msgLen < 0)            {                  if(m_pReadBuf->buf_len < sizeof(CMsgHead))                  {                        buf_reset(m_pReadBuf);                  }else{                        buf_del(m_pReadBuf, sizeof(CMsgHead));                  }                  return;            }            if(m_pReadBuf->buf_len < (pPacketHead->m_msgLen + sizeof(CMsgHead)))            {                  return;            }            int nTotalSize = pPacketHead->m_msgLen + sizeof(CMsgHead);            int nLen = nTotalSize;            nTotalSize = (nTotalSize + 128) & (~(128 - 1));            CMsgPacket msg(nTotalSize);            msg.setPacketHead((char*)m_pReadBuf->buf_pos);            msg.setPacketBody((char*)m_pReadBuf->buf_pos);                Value  readRoot = msg.getReadRoot();            if(!readRoot[RERROR].isNull() || readRoot[RERROR].isBool())            {                  return;            }            int type = readRoot[TYPE].asInt();            switch(type)            {                        case 1001:                        {                                break;                        }                        default:                        {                                break;                        }                }            buf_del(m_pReadBuf, nLen);      }}void *CRobotManager::recvDate(void *arg){     CRobotManager * robotManager = (CRobotManager *)arg;     unsigned char recvBuf[1024];     while(robotManager->m_boStartRobot){          memset(recvBuf, 0, 1024);          int len = recv(robotManager->m_nSfd, recvBuf, 1024, 0);          if(len == 0)          {               close(robotManager->m_nSfd);               robotManager->m_boStartRobot = false;               printf("recv len = 0\n");          }else if(len < 0){               if(errno == EAGAIN || errno == EINTR)                    continue;               close(robotManager->m_nSfd);               robotManager->m_boStartRobot = false;               printf("recv len < 0\n");          }          buf_append(&robotManager->m_pReadBuf, recvBuf, len);          robotManager->dispatchRecvPacket();     }     return NULL;}void CRobotManager::sendDateByTerminal(const char *readBuf){      char sendBuf[1024];        memset(sendBuf, 0, 1024);        CMsgPacket packet(1024);        Value sendRoot;        if(strncmp(readBuf, "1016", 4) == 0)        {                sendRoot[TYPE] = 1016;                sendRoot[UID] = m_nUserId;        }        else if(strncmp(readBuf, "1002", 4) == 0)        {                sendRoot[TYPE] = 1002;                sendRoot["phoneId"] = "A1";                sendRoot["systemType"] = 1;                sendRoot["account"] = "ssh5";                sendRoot["password"] = "application";        }        else        {                printf("please input operate instruction: \n");                return;        }        packet.setSendStrBody(sendRoot);        int len_packet = packet.enpacket(sendBuf);        int write_len = write(m_nSfd, sendBuf, len_packet);        if(write_len < 0)        {            close(m_nSfd);            m_boStartRobot = false;         }}bool CRobotManager::startThread(){      printf("startThread\n");      m_pReadBuf = buf_calloc(16*1024);      if(m_pReadBuf == NULL){            return false;      }      if(pthread_create(&pth_recv, NULL, recvDate, (void*)this) != 0)      {            return false;      }      if(!m_cRobotList->m_cTime.startTime()){            return false;      }      m_cRobotList->m_cTime.setStartHeart(true);      return true;}bool CRobotManager::machine_client(){      struct sockaddr_in m_addr;        int sfd = 0;        if((sfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)        {                printf("machine socket error\n");                return false;        }        bzero(&m_addr, sizeof(struct sockaddr_in));        m_addr.sin_family = AF_INET;        struct hostent *hptr = gethostbyname(MACHINE_IP);        char ip[32];        sprintf(ip, "%s", inet_ntoa(*(struct in_addr *)hptr->h_addr_list[0]));        if(inet_pton(AF_INET, ip, &m_addr.sin_addr)<0)        {                sfd = 0;                return false;        }        m_addr.sin_port = htons(MACHINE_PORT);        if(connect(sfd, (struct sockaddr *)&m_addr, sizeof(m_addr)) < 0)        {                return false;        }      m_nSfd = sfd;      if(!startThread())      {            close(sfd);            return false;      }      m_boStartRobot = true;      return true;}
原创粉丝点击