1. Stream 类封装(接口类)
目的:对文件操作/Socket 的读写操作进行一层Stream流式封装,屏蔽他们之间的一些差异,使得它们的操作更加便捷化。
1.1 接口
1.1.1 虚析构函数
1.1.2 close()
/**
* @brief 关闭
*/
virtual void close() = 0;
1.1.3 读系列函数
1.1.3.1 虚接口
/**
* @brief 读取数据
* @param[out] buffer 存放数据的缓冲区
* @param[in] len 期望读取数据长度
* @return
* @retval >0 实际读取的字节数
* @retval 0 对端关闭
* @retval <0 错误
*/
virtual int read(void *buffer, size_t len) = 0;
/**
* @brief 接收到数据后写入ByteArray中
* @param[in] ba 接收数据的ByteArray
* @param[in] len 接收数据长度
* @return
* @retval >0 实际读取的字节数
* @retval 0 对端关闭
* @retval <0 错误
*/
virtual int read(ByteArray::ptr ba, size_t len) = 0;
1.1.3.2 readFixSize()
功能:读取数据,读够指定字节才会返回
/**
* @brief 读取数据,读够指定字节才会返回
* @param[out] buffer 存放数据的缓冲区
* @param[in] len 期望读取数据长度
* @return
* @retval >0 实际读取的字节数
* @retval 0 对端关闭
* @retval <0 错误
*/
virtual int readFixSize(void *buffer, size_t len);
int Stream::readFixSize(void *buffer, size_t len)
{
//剩余应读字节数
size_t left = len;
//缓冲区偏移量
size_t offset = 0;
while(left > 0)
{
size_t ret = read((char*)buffer + offset, left);
if(ret <= 0)
{
return ret;
}
offset += ret;
left -= ret;
}
//返回出已经读完的字节数
return len;
}
1.1.3.3 (重载)readFixSize()
功能:接收到数据后写入ByteArray中,读够指定字节才会返回
/**
* @brief 接收到数据后写入ByteArray中,读够指定字节才会返回
* @param[in] ba 接收数据的ByteArray
* @param[in] len 接收数据长度
* @return
* @retval >0 实际读取的字节数
* @retval 0 对端关闭
* @retval <0 错误
*/
virtual int readFixSize(ByteArray::ptr ba, size_t len);
int Stream::readFixSize(ByteArray::ptr ba, size_t len)
{
//剩余应读字节数
size_t left = len;
while(left > 0)
{
//复用read()函数
size_t ret = read(ba, left);
if(ret <= 0)
{
return ret;
}
left -= ret;
}
//返回出已经读完的字节数
return len;
}
1.1.4 写系列函数
1.1.4.1 虚接口
/**
* @brief 写入数据
* @param[in] buffer 存放数据的缓冲区
* @param[in] len 期望写入数据长度
* @return
* @retval >0 实际写入的字节数
* @retval <0 错误
*/
virtual int write(const void* buffer, size_t len) = 0;
/**
* @brief 拿出ByteArray中数据写入
* @param[out] ba 拿出数据的ByteArray
* @param[in] len 期望写入数据长度
* @return
* @retval >0 实际读取的字节数
* @retval <0 错误
*/
virtual int write(ByteArray::ptr ba, size_t len) = 0;
1.1.4.2 writeFixSize()
功能:写入数据,写入指定字节才会返回
/**
* @brief 写入数据,写入指定字节才会返回
* @param[in] buffer 存放数据的缓冲区
* @param[in] len 期望写入数据长度
* @return
* @retval >0 实际读取的字节数
* @retval <0 错误
*/
virtual int writeFixSize(const void* buffer, size_t len);
int Stream::writeFixSize(const void* buffer, size_t len)
{
//剩余应写入字节数
size_t left = len;
//缓冲区偏移量
size_t offset = 0;
while(left > 0)
{
size_t ret = write((char*)buffer + offset, left);
if(ret <= 0)
{
return ret;
}
offset += ret;
left -= ret;
}
//返回出已经写完的字节数
return len;
}
1.1.4.3 (重载)writeFixSize()
功能:拿出ByteArray中数据写入,写入指定字节才会返回
/**
* @brief 拿出ByteArray中数据写入,写入指定字节才会返回
* @param[out] ba 拿出数据的ByteArray
* @param[in] len 期望写入数据长度
* @return
* @retval >0 实际读取的字节数
* @retval <0 错误
*/
virtual int writeFixSize(ByteArray::ptr ba, size_t len);
int Stream::writeFixSize(ByteArray::ptr ba, size_t len)
{
//剩余应写入字节数
size_t left = len;
while(left > 0)
{
size_t ret = write(ba, left);
if(ret <= 0) //出错就要返回
{
return ret;
}
left -= ret;
}
//返回出已经写完的字节数
return len;
}
2. Socket Stream类封装
目的:封装一套和业务联系紧密的socket接口。和之前socket.h/socket.cpp
封装C API不同,之前为了避免裸用关于socket的接口
· 类关系
2.1 成员变量
class SOcketStream
{
....
....
protected:
//Socket对象智能指针
Socket::ptr m_sock;
//句柄全权管理标志位
bool m_owner;
};
2.2 接口
2.2.1 构造函数
/**
* @brief SocketStream类构造函数
* @param[in] sock 套接字对象智能指针
* @param[in] owner 句柄关闭是否由本类来自动操作
*/
SocketStream(Socket::ptr sock, bool owner = true);
SocketStream::SocketStream(Socket::ptr sock, bool owner)
:m_sock(sock)
,m_owner(owner)
{
}
2.2.2 析构函数
/**
* @brief SocketStream类析构函数 owner=true就close()
*/
~SocketStream();
SocketStream::~SocketStream()
{
if(m_owner && m_sock)
m_sock->close();
}
2.2.3 isConnected()
功能:判断套接字是否处于连接状态
/**
* @brief 套接字是否处于连接状态
* @return true 处于连接
* @return false 处于不连接
*/
bool isConnected() const;
bool SocketStream::isConnected() const
{
return m_sock && m_sock->isConnected();
}
2.2.4 重写接口
2.2.4.1 读系列函数
virtual int read(void *buffer, size_t len) override;
virtual int read(ByteArray::ptr ba, size_t len) override;
1). read(void *buffer, size_t len)
virtual int read(void *buffer, size_t len) override;
int SocketStream::read(void *buffer, size_t len)
{
if(!isConnected())
return -1;
return m_sock->recv(buffer, len);
}
2). read(ByteArray::ptr ba, size_t len)
(难点)
virtual int read(ByteArray::ptr ba, size_t len) override;
int SocketStream::read(ByteArray::ptr ba, size_t len)
{
if(!isConnected())
return -1;
//通过iovec和ByteArray内存空间建立映射
//获取到即将写入的空间
std::vector<struct iovec> iovs;
ba->getWriteBuf(iovs, len);
//接收数据 直接就写入到了指向ByteArray的内存空间中
int ret = m_sock->recv(&iovs[0], iovs.size());
//由于getWriteBuf() 并不会修改内存指针位置 手动修改m_position
if(ret > 0)
{
ba->setPosition(ba->getPosition() + ret);
}
return ret;
}
2.2.4.2 写系列函数
virtual int write(const void* buffer, size_t len) override;
virtual int write(ByteArray::ptr ba, size_t len) override;
1). write(const void* buffer, size_t len)
virtual int write(const void* buffer, size_t len) override;
int SocketStream::write(const void* buffer, size_t len)
{
if(!isConnected())
return -1;
return m_sock->send(buffer, len);
}
2). write(ByteArray::ptr ba, size_t len)
virtual int write(ByteArray::ptr ba, size_t len) override;
int SocketStream::write(ByteArray::ptr ba, size_t len)
{
if(!isConnected())
return -1;
std::vector<struct iovec> iovs;
ba->getReadBuf(iovs, len);
int ret = m_sock->send(&iovs[0], iovs.size());
if(ret > 0)
{
ba->setPosition(ba->getPosition() + ret);
}
return ret;
}
2.2.4.3 close()
virtual void close() override;
void SocketStream::close()
{
if(m_sock && isConnected())
m_sock->close();
}