服务器使用环形缓冲区处理接收数据
来源:互联网 发布:大数据基金净值 编辑:程序博客网 时间: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;}
阅读全文
0 0
- 服务器使用环形缓冲区处理接收数据
- 关于环形缓冲区的使用
- 服务器公共组件实现 -- 环形缓冲区
- 服务器公共组件实现 -- 环形缓冲区
- 环形缓冲区
- 环形缓冲区
- 环形缓冲区
- 环形缓冲区
- 环形缓冲区
- 环形缓冲区
- 环形缓冲区
- 环形缓冲区
- 环形缓冲区
- 环形缓冲区
- 环形缓冲区
- 环形缓冲区
- 环形缓冲区
- 环形缓冲区
- JSTL标签总结
- ANT 构建工具低调入门
- Android有序广播
- CSS之positon:absolute
- Oracle问题——排名函数(rank与dense_rank)
- 服务器使用环形缓冲区处理接收数据
- JAVA存储数据的五个区域
- Android Studio转换Project成AAR
- @AutoWired与@Resource转载自<叶德华博客>
- MYSQL数据访问工具类DBUtils
- Spring Cloud 微服务框架技术标准分析
- jquery验证两次密码是否一致并阻止表单提交
- java多线程
- 页面跳转和定时刷新