C++ 继承自 iostream failbit 集
C++ Inheriting from iostream failbit set
从哪里开始?我想是开始。
我是套接字编程的新手。我想试一试。 After research, I found that it seems that there is no standard C++ oop socket library (there were some third party libraries 这可能是 oop,但我还是决定自己做,因为,好吧,这样更有趣,因为它只是一个个人项目),所以我决定自己做。
我决定将我的新库与 iostream 集成。当然,this probably isn't a good idea usually,但我认为 1) 我有充分的理由这样做,并且 2) 无论如何,这只是一种学术练习。至少学会怎么做也没什么坏处。
因此,I did a little digging想出了这个设计:
class NetworkStream : public std::iostream {
public:
// class network streambuff
// should handle the actual writing
class NetworkBuff : public std::streambuf {
private:
SOCKET socket; // I'm working with winsock2, btw
public:
NetworkBuff(SOCKET s);
protected:
// out
virtual std::streamsize xsputn(const char* buffer, std::streamsize size);
virtual std::streamsize overflow(char buffer);
virtual int underflow();
virtual std::streamsize xsgetn(char* buffer, std::streamsize size);
};
// constructors
NetworkStream(SOCKET socket); // sets up the socket in NetworkBuff
virtual ~NetworkStream();
}; // end network stream
这个 NetworkStream 对象应该处理网络上的实际读写。连接由更高级别的代码维护(我指的是从 NetworkStream 继承的对象)。该代码有效(据我所知,无论如何)并且与我的问题无关,所以我省略了它。我只是提一下,以便您了解我的设计。
无论如何,我的新流对象的实际实现看起来像这样:
// class network streambuff
// should handle the actual writing
//constructor
NetworkStream::NetworkBuff::NetworkBuff(SOCKET s) {
socket = s;
}
// out
std::streamsize NetworkStream::NetworkBuff::xsputn(const char* buffer, std::streamsize size) {
// well, let's send the data
int result = send(socket,buffer,static_cast<int>(size),0);
// if that didn't work, throw an error
if(result == SOCKET_ERROR) throw("Send Failure: " + WSAGetLastError());
// NOTE: I realized after I wrote this that this throw may be useless,
// since I think iostream catches any errors thrown at this level, but
// just in case
// and pass through to streambuff, because, well, it can't hurt
return std::streambuf::xsputn(buffer, size);
}
// basically do the same thing as before...
std::streamsize NetworkStream::NetworkBuff::overflow(char buffer) {
// well, let's send the data
int result = send(socket,buffer,sizeof(buffer),0);
// if that didn't work, throw an error
if(result == SOCKET_ERROR) throw("Send Failure: " + WSAGetLastError());
// and pass through to streambuff, because, well, it can't hurt
return std::streambuf::overflow(buffer);
}
据我所知,这非常有效。我单步调试我的调试器,我的 xsputn()
被调用。所以我可以这样做:
std::string data = "Hello, world!";
networkstream << data;
它被调用了。我认为它发送成功。它没有单步执行我的调试器,结果没有错误。但是,我还没有完全测试它,因为它是我的接收功能不起作用:
std::streamsize NetworkStream::NetworkBuff::xsgetn(char* buffer, std::streamsize size) {
// well, let's read the data
int result = recv(socket,buffer,static_cast<int>(size),0);
// if that didn't work, throw an error
if(result == SOCKET_ERROR) throw("Receive Failure: " + WSAGetLastError());
// Now this I think is wrong, specifically comparing against SOCKET_ERROR.
// That's not my problem, though. My problem is that this function seems to
// never get called, so a wrong comparison doesn't matter yet anyway
// and pass through to streambuff, because, well, it can't hurt
return std::streambuf::xsgetn(buffer, size);
}
// Now this guy, I'm pretty extra sure is probably wrong, but it's what I got. I
// couldn't find a good example of using underflow, so I did my best from the
// research I did find
int NetworkStream::NetworkBuff::underflow() {
// well, let's read the data
int result = recv(socket,gptr(),sizeof(*gptr()),0);
// if that didn't work, throw an error
if(result == SOCKET_ERROR) throw("Recieve Failure: " + WSAGetLastError());
// and pass through to streambuff, because, well, it can't hurt
return std::streambuf::underflow();
}
它编译得很好。但是,当我尝试使用它时:
std::string data = "";
networkstream >> data; // should wait for data on the network
好像什么都没发生过一样。不,实际上,根据我的调试器,它似乎设置了一个失败位,忽略了我实际上重载的函数,并像什么都没发生一样继续执行。
因此,我的问题在一段中是:我的 underflow/xsgetn 函数到底出了什么问题导致它失败并基本上忽略了我的代码?我确定我做错了什么,但具体是什么?
事实证明,我不能就这么过去了。 streambuf 不是这样设计的。
据我所知(如果我错了,请有人纠正我),streambuf 实际上名副其实。它应该是流的缓冲区。
无论如何,对我来说,不清楚的是 streambuf,虽然它应该处理缓冲,但它没有实际的内部方式来保存或处理数据。这就是重载它的全部意义所在。你应该处理缓冲。你不能通过(再说一次,如果我错了,有人会纠正)到 parent。这不是它的设计方式。
您需要(或者我想我需要)很好地实现下溢并正确实现它。幸运的是,经过更多的挖掘,我找到了一个。长话短说,我做了这样的事情:
// Shoutout to http://www.voidcn.com/article/p-vjnlygmc-gy.html where I found out
// how to do this proper
std::streambuf::int_type NetworkStream::NetworkBuff::underflow() {
const int readsize = 30;
// first, check to make sure the buffer is not exausted:
if(gptr() < egptr()) {
return traits_type::to_int_type(*gptr());
}
// Now, let's read...
// btw, inputbuffer is a data member that is a std::string
// clear the buffer
inputbuffer.clear();
inputbuffer.resize(readsize);
// let's read
int bytesread = recv(socket,&inputbuffer[0],static_cast<int>(readsize));
// return the end of file if we read no bytes
if(bytesread == 0) {
return traits_type::eof();
}
// set the pointers for the buffer...
setg(&inputbuffer[0],&inputbuffer[0],&inputbuffer[readsize-1]);
// finally, let's return the data type
return traits_type::to_int_type(*gptr());
}
从哪里开始?我想是开始。
我是套接字编程的新手。我想试一试。 After research, I found that it seems that there is no standard C++ oop socket library (there were some third party libraries 这可能是 oop,但我还是决定自己做,因为,好吧,这样更有趣,因为它只是一个个人项目),所以我决定自己做。
我决定将我的新库与 iostream 集成。当然,this probably isn't a good idea usually,但我认为 1) 我有充分的理由这样做,并且 2) 无论如何,这只是一种学术练习。至少学会怎么做也没什么坏处。
因此,I did a little digging想出了这个设计:
class NetworkStream : public std::iostream {
public:
// class network streambuff
// should handle the actual writing
class NetworkBuff : public std::streambuf {
private:
SOCKET socket; // I'm working with winsock2, btw
public:
NetworkBuff(SOCKET s);
protected:
// out
virtual std::streamsize xsputn(const char* buffer, std::streamsize size);
virtual std::streamsize overflow(char buffer);
virtual int underflow();
virtual std::streamsize xsgetn(char* buffer, std::streamsize size);
};
// constructors
NetworkStream(SOCKET socket); // sets up the socket in NetworkBuff
virtual ~NetworkStream();
}; // end network stream
这个 NetworkStream 对象应该处理网络上的实际读写。连接由更高级别的代码维护(我指的是从 NetworkStream 继承的对象)。该代码有效(据我所知,无论如何)并且与我的问题无关,所以我省略了它。我只是提一下,以便您了解我的设计。
无论如何,我的新流对象的实际实现看起来像这样:
// class network streambuff
// should handle the actual writing
//constructor
NetworkStream::NetworkBuff::NetworkBuff(SOCKET s) {
socket = s;
}
// out
std::streamsize NetworkStream::NetworkBuff::xsputn(const char* buffer, std::streamsize size) {
// well, let's send the data
int result = send(socket,buffer,static_cast<int>(size),0);
// if that didn't work, throw an error
if(result == SOCKET_ERROR) throw("Send Failure: " + WSAGetLastError());
// NOTE: I realized after I wrote this that this throw may be useless,
// since I think iostream catches any errors thrown at this level, but
// just in case
// and pass through to streambuff, because, well, it can't hurt
return std::streambuf::xsputn(buffer, size);
}
// basically do the same thing as before...
std::streamsize NetworkStream::NetworkBuff::overflow(char buffer) {
// well, let's send the data
int result = send(socket,buffer,sizeof(buffer),0);
// if that didn't work, throw an error
if(result == SOCKET_ERROR) throw("Send Failure: " + WSAGetLastError());
// and pass through to streambuff, because, well, it can't hurt
return std::streambuf::overflow(buffer);
}
据我所知,这非常有效。我单步调试我的调试器,我的 xsputn()
被调用。所以我可以这样做:
std::string data = "Hello, world!";
networkstream << data;
它被调用了。我认为它发送成功。它没有单步执行我的调试器,结果没有错误。但是,我还没有完全测试它,因为它是我的接收功能不起作用:
std::streamsize NetworkStream::NetworkBuff::xsgetn(char* buffer, std::streamsize size) {
// well, let's read the data
int result = recv(socket,buffer,static_cast<int>(size),0);
// if that didn't work, throw an error
if(result == SOCKET_ERROR) throw("Receive Failure: " + WSAGetLastError());
// Now this I think is wrong, specifically comparing against SOCKET_ERROR.
// That's not my problem, though. My problem is that this function seems to
// never get called, so a wrong comparison doesn't matter yet anyway
// and pass through to streambuff, because, well, it can't hurt
return std::streambuf::xsgetn(buffer, size);
}
// Now this guy, I'm pretty extra sure is probably wrong, but it's what I got. I
// couldn't find a good example of using underflow, so I did my best from the
// research I did find
int NetworkStream::NetworkBuff::underflow() {
// well, let's read the data
int result = recv(socket,gptr(),sizeof(*gptr()),0);
// if that didn't work, throw an error
if(result == SOCKET_ERROR) throw("Recieve Failure: " + WSAGetLastError());
// and pass through to streambuff, because, well, it can't hurt
return std::streambuf::underflow();
}
它编译得很好。但是,当我尝试使用它时:
std::string data = "";
networkstream >> data; // should wait for data on the network
好像什么都没发生过一样。不,实际上,根据我的调试器,它似乎设置了一个失败位,忽略了我实际上重载的函数,并像什么都没发生一样继续执行。
因此,我的问题在一段中是:我的 underflow/xsgetn 函数到底出了什么问题导致它失败并基本上忽略了我的代码?我确定我做错了什么,但具体是什么?
事实证明,我不能就这么过去了。 streambuf 不是这样设计的。
据我所知(如果我错了,请有人纠正我),streambuf 实际上名副其实。它应该是流的缓冲区。
无论如何,对我来说,不清楚的是 streambuf,虽然它应该处理缓冲,但它没有实际的内部方式来保存或处理数据。这就是重载它的全部意义所在。你应该处理缓冲。你不能通过(再说一次,如果我错了,有人会纠正)到 parent。这不是它的设计方式。
您需要(或者我想我需要)很好地实现下溢并正确实现它。幸运的是,经过更多的挖掘,我找到了一个。长话短说,我做了这样的事情:
// Shoutout to http://www.voidcn.com/article/p-vjnlygmc-gy.html where I found out
// how to do this proper
std::streambuf::int_type NetworkStream::NetworkBuff::underflow() {
const int readsize = 30;
// first, check to make sure the buffer is not exausted:
if(gptr() < egptr()) {
return traits_type::to_int_type(*gptr());
}
// Now, let's read...
// btw, inputbuffer is a data member that is a std::string
// clear the buffer
inputbuffer.clear();
inputbuffer.resize(readsize);
// let's read
int bytesread = recv(socket,&inputbuffer[0],static_cast<int>(readsize));
// return the end of file if we read no bytes
if(bytesread == 0) {
return traits_type::eof();
}
// set the pointers for the buffer...
setg(&inputbuffer[0],&inputbuffer[0],&inputbuffer[readsize-1]);
// finally, let's return the data type
return traits_type::to_int_type(*gptr());
}