我正在编写MUD服务器用于个人学习,很高兴地,我设法将套接字中的内容打包为几个类,并且一切似乎都可以正常工作。服务器监听并接受连接,并且当前从客户端获取文本并将其立即发送回去。
问题是我不太确定该如何处理对accept()的调用,该调用返回的内容不是WSAEWOULDBLOCK或有效的套接字。我是否只是将新的套接字重置为0并返回,也许会出现一条错误消息,指出发生了什么不好的事情?这是我目前正在执行的操作,另外,如果发生20次,我将关闭服务器。
void MUDControlSocket::Poll()
{
// create a new connection here
timeval timeout;
FD_ZERO(&ReadSet);
FD_ZERO(&WriteSet);
FD_ZERO(&ExceptionSet);
TopSocket = GetSocket();
NewSocket = 0;
FD_SET( GetSocket(), &ReadSet );
if( SocketList.size() > 0 )
{
for( sockIter iter = SocketList.begin(); iter != SocketList.end(); ++iter )
{
FD_SET((*iter)->GetSocket(), &ReadSet);
FD_SET((*iter)->GetSocket(), &WriteSet);
FD_SET((*iter)->GetSocket(), &ExceptionSet);
TopSocket = (*iter)->GetSocket();
}
}
if( select( TopSocket+1, &ReadSet, &WriteSet, &ExceptionSet, &timeout ) == SOCKET_ERROR )
{
cout << "Error on select() call: " << SocketErrorType(WSAGetLastError()) << endl;
delete this;
exit(EXIT_FAILURE);
}
// as long as everything is working correctly, this if block should always be entered UNLESS a new connection is accepted
if( (NewSocket = accept(GetSocket(), NULL, NULL) ) == INVALID_SOCKET )
{
if( WSAGetLastError() == WSAEWOULDBLOCK ) // it's not an actual problem. just nothing to connect to yet
return;
NewSocket = 0;
static int count = 0;
cout << "Error on accepting new connection: " << SocketErrorType(WSAGetLastError()) << endl;
if( ++count >= 20 )
done = true;
return;
}
SocketList.push_back(new MUDSocket(NewSocket)); // only happens if accept DOES NOT return a value of INVALID_SOCKET i.e. a new connection was accepted
TopSocket = NewSocket;
NewSocket = 0;
}
TopSocket和NewSocket的类型为SOCKET,并在文件范围内声明。 SocketList是MUDSocket *的std::list,而MUDControlSocket是作为单例从MUDSocket派生的。
如果您需要更多信息,请告诉我,谢谢您的帮助。
最佳答案
首先:不要将套接字设置为0:这对于某些* NIX系统上的套接字来说是有效的fd,这是一个坏习惯。假定唯一无效的套接字fd为-1。以后做其他任何事情都会给您带来真实软件中的实际错误(请相信我:我的经验是使用0作为无效套接字fd的调试代码)。
除此之外,我想说的是一个异常(exception):accept
应该不会失败,除非您用完了资源,这既是异常(exception),也是错误。 C++具有处理此类问题的机制,这是异常(exception)。
顺便说一句:delete this
几乎总是一个很糟糕的主意,在代码中间退出可能使调试变得困难(代替抛出异常),并让调用者在需要时退出),而不是尝试接受带有accept
的套接字,您可以使用select
告诉您是否要接受任何内容-并将特殊情况处理移出该函数,仅在其中进行选择。您可以走得更远,实现一个专门的观察者模式(就像我一个月前在my podcast上所做的那样),不仅练习您的网络代码,而且练习您的设计模式。这也将使您的代码更具可移植性,并在以后可重复使用。
高温超导
关于c++ - 担心处理对accept()的错误调用,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/5465730/