【发布时间】:2019-05-16 01:27:58
【问题描述】:
从哪里开始?开始吧,我猜。
我是套接字编程的新手。我想试一试。 After research,我发现似乎没有标准的 C++ oop 套接字库(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 函数到底有什么问题导致它失败并基本上忽略了我的代码?我确定我做错了什么,但究竟是什么?
【问题讨论】:
-
"Send Failure: " + WSAGetLastError()和"Receive Failure: " + WSAGetLastError()不要做你认为他们做的事。您需要改用"Send Failure: " + std::to_string(WSAGetLastError())和"Receive Failure: " + std::to_string(WSAGetLastError())(或等效项)。另外,在NeworkBuffer::overflow()中调用send()时,需要使用send(socket,&buffer,sizeof(buffer),0);,但如果buffer是Traits::eof(),则根本不要调用send()。 -
但是,您的阅读代码看起来有点不对劲。我建议您查看
std::basic_filebuf和std::basic_stringbuf的实现示例,或者查看第3 方streambuf实现以了解如何将数据读写到外部源/目标。顺便说一句,我知道有std::streambuf的第 3 方套接字实现,你应该去找一个而不是自己写。 -
啊,是的。接得好。我知道
"Send Failure: " + WSAGetLastError()的事情。我只是把它放在一起,并想如果我遇到错误,我会修复它以便我可以阅读。另外,感谢有关Traits::eof()的提示 -
您是否阅读过 cppreference.com 上的
std::streambuf文档? -
是的,我也知道第 3 方。就像我说的,这只是为了好玩。这就是为什么我什至不屑于弄乱 iostream 的原因。我只是在努力学习。感谢您提供有关 filebuf 和 stringbuf 的提示,顺便说一句。
标签: c++ inheritance iostream winsock2