【发布时间】:2014-05-30 22:01:41
【问题描述】:
已解决
错误是假设 UDP 和 TCP 具有相同的连接和初始化结构。在这里我得到了更多关于它的信息:
http://bit.kuas.edu.tw/~csshieh/teach/np/winsock/
希望对遇到我这种情况的每个人都有帮助
问题
我正在尝试编写一个使用 UDP 套接字的库。之前我用的是TCP IP socket,写的很成功,后来我决定把这几个模板化,泛化一下。
为了确保模板化的安全,我创建了一个枚举
enum eSocketType { eTCP = SOCK_STREAM, eUDP = SOCK_DGRAM };
套接字是使用套接字类上的静态成员创建的,该成员已模板化并接收这种枚举。
模板化套接字适用于 eTCP。但是当我使用 eDCP 时,绑定过程失败,我收到错误 10045,这意味着“不支持该操作”,如 MSDN support中的 sais
对象类型不支持尝试的操作 参考。通常这发生在一个套接字描述符到一个套接字时 无法支持此操作的正在尝试接受连接 一个数据报套接字。
简化帖子
这里是初始化代码的总结(这是我在编辑帖子之前描述的类的初始化过程(即“OLD POST”小节之后)):
int iResult = getaddrinfo(NULL, mPort.c_str(), &mHints, &mResult);
if ( iResult != 0 ) {
exit(-1);
}
mSocketOwn = socket(mResult->ai_family, mResult->ai_socktype, mResult->ai_protocol);
if (mSocketOwn == INVALID_SOCKET) {
freeaddrinfo(mResult);
exit(-1);
}
#ifdef __linux__
int yes = 1;
iResult = setsockopt(mSocketOwn, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int));
#endif
#ifdef _WIN32
bool bOptVal = TRUE;
int bOptLen = sizeof(bool);
iResult = setsockopt(mSocketOwn, SOL_SOCKET, SO_REUSEADDR, (char *) bOptVal, bOptLen);
#endif
iResult = bind( mSocketOwn, mResult->ai_addr, mResult->ai_addrlen); // <-- Here fails
if (iResult == SOCKET_ERROR) {
// Here I get the error 10045 if a read the last error
closeSocket();
exit(-1);
}
freeaddrinfo(mResult);
旧帖
在复制/粘贴代码之前是结构:
有一个 Socket 类,它具有虚拟成员和受保护的构造函数。该类还具有分别创建 ServerSocket 和 ClientSocket 类的静态成员。静态成员与前一个枚举具有第一级模板。 ServerSocket 和 ClientSocket 继承自 Socket 并被模板化(因为初始化依赖于该模板)。希望这个介绍能让代码更容易理解……我们开始吧:
套接字接口:
class Socket{
public:
int sendData(std::string _data);
std::string receiveData();
protected:
Socket() {};
virtual int initializeSocket() = 0;
virtual int connectSocket() = 0;
virtual int closeSocket() = 0;
int getLastError();
public: // static members: Factory, etc
template<eSocketType type_>
static ClientSocket<type_>* createClientSocket(std::string _ip, std::string _port);
template<eSocketType type_>
static ServerSocket<type_>* createServerSocket(std::string _port);
protected:
#if defined(_WIN32)
WSADATA mWsaData;
#endif
SOCKET mSocketOut;
addrinfo *mResult, mHints;
}; // class Socket
ServerSocket 接口:
模板
class ServerSocket: public Socket{
public:
ServerSocket(const std::string _port);
int listenClient();
SOCKET acceptClient();
protected:
int initializeSocket();
int connectSocket();
int closeSocket();
private:
SOCKET mSocketOwn;
std::string mPort;
}; // class ServerSocket
我省略了客户端,因为错误开始创建服务器。 基本上,ServerSocket 构造函数调用了这里的 InitiallizeSocket 和 ConnectSocket 方法:
template<eSocketType type_>
int ServerSocket<type_>::initializeSocket(){
// Resolve the server address and port
std::cout << "Getting address info";
int iResult = getaddrinfo(NULL, mPort.c_str(), &mHints, &mResult);
if ( iResult != 0 ) {
std::cout << "getaddrinfo failed with error: " << iResult << std::endl;
#if defined (_WIN32)
WSACleanup();
#endif
return 1;
}
std::cout << "----> Got address info" << std::endl;
// Create a SOCKET for connecting to server
std::cout << "Creating server socket";
mSocketOwn = socket(mResult->ai_family, mResult->ai_socktype, mResult->ai_protocol);
if (mSocketOwn == INVALID_SOCKET) {
std::cout << "Socket failed. Error was: " << getLastError() << std::endl;
freeaddrinfo(mResult);
return 1;
}
std::cout << "----> Socket created" << std::endl;
return 0;
}
//-----------------------------------------------------------------------------
template<eSocketType type_>
int ServerSocket<type_>::connectSocket(){
// Setup the TCP listening socket
int iResult = 0;
#ifdef __linux__
int yes = 1;
iResult = setsockopt(mSocketOwn, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int));
#endif
#ifdef _WIN32
bool bOptVal = TRUE;
int bOptLen = sizeof(bool);
iResult = setsockopt(mSocketOwn, SOL_SOCKET, SO_REUSEADDR, (char *) bOptVal, bOptLen);
#endif
std::cout << "Binding to port";
iResult = bind( mSocketOwn, mResult->ai_addr, mResult->ai_addrlen);
if (iResult == SOCKET_ERROR) {
std::cout << "Bind failed" << std::endl;
std::cout << "Error was: " << getLastError() << std::endl;
freeaddrinfo(mResult);
closeSocket();
return 1;
}
std::cout << "----> Binded to port" << std::endl;
freeaddrinfo(mResult);
return 0;
}
套接字已正确初始化,但在 connectSocket 方法中尝试绑定它时失败并出现 10045 错误。 正如我所说,TCP/IP 套接字工作正常,没有错误出现。我阅读了一些关于 UDP 套接字的教程,但找不到任何“遗漏的步骤”......有人知道发生了什么吗?
提前谢谢,如果需要更多信息,请告诉我,我会添加它。 巴勃罗 R.S.
【问题讨论】:
-
您需要将此代码简化为一个打开 UDP 套接字的小应用程序。一旦可行,您就可以做所有花哨的模板工作。不知道为什么需要对其进行模板化,但这是一个不同的问题
-
好的,我将对其进行编辑以简化代码。将其模板化的原因是在编译时定义套接字而不是运行时(没有其他原因)。
-
不要编辑以简化。使用固定参数硬编码的套接字函数调用和绑定函数调用制作一个更简单的程序。
-
mResult只是一个errorFlag,在if语句中插入函数可以省略
-
IMO,这将许多几乎不相关的职责放在一个类中。尽管它目前是为客户端而不是服务器用户编写的,但我不久前在an answer on CR 中展示了我认为更简洁的方法。如果我站在你的立场上,我可能会使用至少与此类似的东西作为起点。