CPackageCpackage是Carlsdk中使用Csocket进行收发数据包的类,对数据包进行了定义,保证数据收发的完整性
此对象主要应对大数据包的收发,以及可能出现的TCP粘包问题。
数据包数据包由包头和包体两部分组成,包头4个字节,包体最大8 * 1024个字节,使用如下两个宏
1 2 #define C_DATA_PACKAGE_HEADER_SIZE 4 #define C_DATA_PACKAGE_MAX_LENGTH (8 * 1024)
C
构造函数构造函数主要申请数据包的缓存空间,一些标志位的初始化赋值
标志位是用来判断缓存空间的使用情况,包括如下几个:
data_package_buffer:缓存空间头指针
unconsumed_buffer:还未使用的缓存空间头指针
read_end:已经读取的缓存空间尾指针
buffer_end:缓存空间的尾指针
1 2 3 4 5 6 7 8 9 10 11 12 13 CPackage::CPackage(std ::shared_ptr <CSocket> socket) { mSock = socket; dataPackageBuffer = new char [C_DATA_PACKAGE_HEADER_SIZE + C_DATA_PACKAGE_MAX_LENGTH]; dataSendBuffer = new char [C_DATA_PACKAGE_HEADER_SIZE + C_DATA_PACKAGE_MAX_LENGTH]; unconsumedBuffer = dataPackageBuffer; readEnd = dataPackageBuffer; bufferEnd = dataPackageBuffer + C_DATA_PACKAGE_HEADER_SIZE + C_DATA_PACKAGE_MAX_LENGTH; }
C
发送数据包发送数据包由两部分组成,构造数据和发送数据,发送数据要保证数据全部发送完成,实现如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 int CPackage::sendBlockData (const char *data, int data_length) { int send_length = 0 ; int data_remaining = 0 ; if (data == nullptr || data_length <= 0 ) { return -1 ; } if (mSock == nullptr ) { return -1 ; } data_remaining = data_length; do { send_length = mSock->send(data, data_remaining); if (send_length < 0 ) { return -1 ; } data_remaining -= send_length; data += send_length; } while (data_remaining > 0 ); return 0 ; }
C
构造数据包,包括包头和包体,包体是传进来的参数,所以只需在发送数据前先发送包头,实现如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 int CPackage::sendDataPackage (const char *data_package, int package_length) { if (data_package == nullptr || package_length <= 0 ) { return -1 ; } memset (dataSendBuffer, 0X00 , C_DATA_PACKAGE_HEADER_SIZE + C_DATA_PACKAGE_MAX_LENGTH); dataSendBuffer[0 ] = (char )((package_length >> 24 ) & 0xFF ); dataSendBuffer[1 ] = (char )((package_length >> 16 ) & 0xFF ); dataSendBuffer[2 ] = (char )((package_length >> 8 ) & 0xFF ); dataSendBuffer[3 ] = (char )(package_length & 0xFF ); memcpy (dataSendBuffer + C_DATA_PACKAGE_HEADER_SIZE,data_package, package_length); if (sendBlockData(dataSendBuffer, package_length + C_DATA_PACKAGE_HEADER_SIZE) != 0 ) { return -1 ; } return 0 ; }
C
接收数据包首先判断缓存空间无数据可读,并初始化缓存空间,接收数据后,再从缓存空间中取出可用数据,这一系列操作主要是解决TCP粘包问题,实现如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 int CPackage::recvDataPackage (char **data_package, int *package_length) { int recv_length = 0 ; if (data_package == nullptr || package_length == nullptr ) { return -1 ; } if (mSock == nullptr ) { return -1 ; } if (getAvailableDataPackage(data_package, package_length) != -1 ) { return 0 ; } if (unconsumedBuffer == dataPackageBuffer && readEnd == bufferEnd) { return -1 ; } if (unconsumedBuffer != dataPackageBuffer) { int move_size = readEnd - unconsumedBuffer; if (move_size > 0 ) { memmove(dataPackageBuffer, unconsumedBuffer, move_size); } else { memset (dataPackageBuffer, 0X00 , C_DATA_PACKAGE_HEADER_SIZE + C_DATA_PACKAGE_MAX_LENGTH); } readEnd = dataPackageBuffer + move_size; unconsumedBuffer = dataPackageBuffer; } recv_length = mSock->recv(readEnd, bufferEnd - readEnd); if (recv_length < 0 ) { if (errno == EAGAIN || errno == EWOULDBLOCK) { *data_package = nullptr ; *package_length = 0 ; return 0 ; } else { *package_length = 0 ; return -1 ; } } else if (recv_length == 0 ) { *package_length = 0 ; return -1 ; } readEnd += recv_length; if (getAvailableDataPackage(data_package, package_length) != 0 ) { *data_package = nullptr ; *package_length = 0 ; } return 0 ; }
C
获取可用数据首先判断缓存空间是否有可读数据,然后根据包头获取指定长度的数据包
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 int CPackage::getAvailableDataPackage (char **data_package, int *package_length) { int data_length = 0 ; if (readEnd < unconsumedBuffer + C_DATA_PACKAGE_HEADER_SIZE) { return -1 ; } data_length = ((unconsumedBuffer[0 ] & 0xff ) << 24 ) | ((unconsumedBuffer[1 ] & 0xff ) << 16 ) | ((unconsumedBuffer[2 ] & 0xff ) << 8 ) | (unconsumedBuffer[3 ] & 0xff ); if (readEnd < unconsumedBuffer + C_DATA_PACKAGE_HEADER_SIZE + data_length) { return -1 ; } *data_package = unconsumedBuffer + C_DATA_PACKAGE_HEADER_SIZE; *package_length = data_length; unconsumedBuffer = unconsumedBuffer + C_DATA_PACKAGE_HEADER_SIZE + data_length; return 0 ; }
C