本文共 4455 字,大约阅读时间需要 14 分钟。
streambuf是C++流(iostream)与流实体(文件、标准输入输出等)交互的桥梁
# 文件流fstream <--> filebuf <--> file# 字符串流stringstream <--> stringbuf <--> string
上面的文件流和字符串流是C++标准库已经提供了的,现在我的目标是实现一个使用TCP协议通信的socket流
tstream <--> tcpbuf <--> socket(tcp)
首先来分析一下streambuf的内部实现
术语说明:
streambuf内部持有三个用于get的指针gfirst,gnext,glast
和三个用于put的指针pfirst,pnext,plast
,这些指针分别可以使用eback(),gptr(),egptr()
和pbase(),pptr(),epptr()
函数获得,在代码中需要使用这些函数获取指针,为了方便描述,我直接使用这些指针变量名
下面是其他几个受保护的成员函数的作用
小结:
子类需要override(覆写)几个虚函数来封装具体的流的实现
这些函数有些需要子类实现,来屏蔽不同的流的具体实现,向上提供统一的接口
缓冲区不可用是指gnext(pnext) == NULL或者gnext(pnext) >= glast(plast)
NOTE: 下面的缓冲区指的是用于get操作的缓冲区
return sbumpc() == EOF ? EOF : sgetc()
NOTE: 下面的缓冲区指的是用于put操作的缓冲区
下面就iostream常用的几个函数说明他们的调用关系
\n
我们可以在underflow()函数里重新设置gfirst gnext glast,使得snextc()不会不断的调用uflow(),而可以先读取缓冲区里的数据
[gfirst, glast)
永远是已经从流实体里读到的数据如果他们不为空的话class tcpbuf : public std::streambuf { void initsocklib() {#ifdef WIN32 static bool inited = false; WSADATA wsaData; if (!inited) WSAStartup(MAKEWORD(2, 2), &wsaData);#endif }public: enum { BUFSIZE = 1 << 5 }; tcpbuf(SOCKET s) { initsocklib(); sock = s; } tcpbuf() { initsocklib(); sock = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); } ~tcpbuf() override { close(); } bool connect(char *ip, unsigned short port) { sockaddr_in addr; memset(&addr, 0, sizeof(addr)); addr.sin_addr.s_addr = inet_addr(ip); addr.sin_family = AF_INET; addr.sin_port = ::htons(port); return !::connect(sock, (sockaddr *)&addr, sizeof(addr)); } int close() {#ifdef WIN32 return ::closesocket(sock);#else return ::close(sock);#endif }protected: // Buffered get int underflow() override { auto n = ::recv(sock, buf, BUFSIZE, 0); return n > 0 ? (setg(buf, buf, buf + n), *gptr()) : EOF; } // Unbuffered put int overflow(int c) override { if (c == EOF) return close(); char b = c; return ::send(sock, &b, 1, 0) > 0 ? c : EOF; } std::streamsize xsputn(const char *s, std::streamsize n) override { auto x = ::send(sock, s, n, 0); return x > 0 ? x : 0; } // flush int sync() override {#ifdef WIN32 return 0;#else return flush(sock);#endif // WIN32 } //streamsize showmanyc() override { return 1; }private: SOCKET sock; char buf[BUFSIZE];};class tstream : public std::iostream {public: tstream() : std::iostream(&_buf) {} tstream(SOCKET sock) : _buf(sock), std::iostream(&_buf) {} tstream(char *ip, unsigned short port) : tstream() { connect(ip, port); } bool connect(char *ip, unsigned short port) { return _buf.connect(ip, port); }private: tcpbuf _buf;};
转载地址:http://zyzza.baihongyu.com/