C++ winsock 错误
Posted
技术标签:
【中文标题】C++ winsock 错误【英文标题】:C++ winsock error 【发布时间】:2010-06-21 12:34:45 【问题描述】:我有一个接受客户端的简单服务器。 客户端连接到服务器。服务器首先会执行以下操作:
-
获取客户端套接字
为客户端创建线程
调用 ::recv();
这里的问题是 recv 返回 -1 WSAGetLastError 返回 WSAENOTSOCK:(非套接字上的套接字操作。)Microsoft:“尝试对不是套接字的东西进行操作。套接字句柄参数未引用有效套接字,或者对于 select,fd_set 的成员无效。”我真的无法弄清楚问题到底是什么。
客户端的套接字仍然有效,客户端剂量的任何接收都会立即返回
谢谢,拉克斯万
【问题讨论】:
您有机会发布一些示例代码吗?这将使我们更容易调试。我猜 grub 应该是 'grab' 的? 是最基本的服务器 SOCKER s = ::accept(lsock,0,0);客户* c= 新客户; c->RunThread();//这里将创建并启动线程 你有没有试过在没有线程的情况下这样做......如果是这样,你能发布一个工作示例吗? 嗯....不,我现在就试试这个 在同一个线程 recv() 工作正常,它停止并等待数据。但是在客户端线程 recv() 将在第一次调用时失败。我检查了套接字,仍然是accept()返回的那个,例如(1839)返回的accept,并且客户端在套接字中具有相同的值 【参考方案1】:我很确定您只是立即关闭新接受的连接的套接字。
您使用了sok
类,该类会在其d'tor(析构函数)处自动关闭套接字。
sok client = listener.Accept();
以下代码从返回的套接字构造sok
对象。它的生命周期受while
循环的花括号限制。
意味着 - 在创建应该从套接字读取的线程后立即关闭它。
附:
你滥用了sok
。根据它在做什么,您必须防止为同一个套接字创建多个这样的对象。
例如,复制 c'tor 必须声明为私有。它在您的代码中是公开的。
此外,使用explicit
关键字声明接受 SOCKET 的 c'tor 也是一个好主意。
结论:思考并回顾您对sok
类的使用情况。
【讨论】:
【参考方案2】:好的,这很容易。
在你的代码中,你有
inline sok Accept()
按值返回sok
。
在这里你将它分配给一个局部变量:
sok client = listener.Accept();
在这个表达式的最后,从 Accept() 返回的临时 sok
被销毁。您可能想在sok::Close()
中放置一个断点或调试打印,以亲眼看看我的意思。
【讨论】:
【参考方案3】:According to MSDN,socket有问题。
试图对不是套接字的东西进行操作。套接字句柄参数没有引用有效的套接字,或者对于 select,fd_set 的成员无效。
你是如何“grub”套接字的——你确定它是有效的吗?尝试检查来自::accept
的返回。如果返回值 == INVALID_SOCKET,那就是你的问题。届时您可以致电WSAGetLastError 尝试找出问题所在。
【讨论】:
是的,我在接受后调用 WSAGetLastError 并且没有错误。从accept()返回的socket是有效的 是的,它是一个有效值,不同于 INVALID_SOCKET。 accept() 不会以任何方式失败。【参考方案4】: void NetworkServer::RunServer()//main server loop
while (flags & server_running)
sok client = listener.Accept();
if (listener && client.IsValid())
if (clients.size >= MaxClients)
client.Close();
continue;
ClientHandler* h = constructor->ConstructClient();
//ConstructClient() is just doing "new ClientHandler()";
h->com_stream.forceConnected(client);
h->id = client_ids.getId();
h->flags = client_active;
h->server = this;
this->HandleNewConnection(h);//nothing..
locker.Enter();
clients.add(h);//add client to the client array
h->threadRun();//stars the thread
locker.Leave();
else
break;
void tcpStream::forceConnected(sok& ss)
server.socket = ss.socket;
connected = true;
class sok
private:
SOCKET socket;
public:
inline sok()
: socket(INVALID_SOCKET)
inline sok(SOCKET s)
: socket(s)
inline sok(const sok & s)
: socket(s.socket)
inline operator bool()const
return (socket != INVALID_SOCKET);
inline ~sok()
Close();
inline bool IsValid()const
return (socket != INVALID_SOCKET);
inline void operator = (const sok & s)
socket = s.socket;
public:
inline void Close()
if (socket != INVALID_SOCKET)
closesocket(socket);
socket = INVALID_SOCKET;
inline sok Accept()
return sok(::accept(socket, 0, 0));
bool tcpClient(NetAddress& adr);
bool tcpServer(wtf::ushort port, wtf::u32 clients = 10);
private:
friend class tcpStream;
;
uint tcpStream::read(void* out, const uint size)
wtf::n32 r = ::recv(server.socket, (char*)out, size, 0);//this failes
//int e = WSAGetLastError();
connected = ((r) != (-1));
return ((uint)r);/**/
【讨论】:
客户端中的com_stream成员是tcpStream类型。 tcpSteam 只是包裹在套接字周围进行读写【参考方案5】:只要确保你向 recv() 函数传递了正确的参数,包括正确的套接字 id(无论如何它是一个“无符号整数”!)。
【讨论】:
以上是关于C++ winsock 错误的主要内容,如果未能解决你的问题,请参考以下文章
带有 winsock 和 std::thread 的 C++ 多线程服务器
C++ WinSock2:连接()调用上的 WSA_INVALID_HANDLE