Sockets 切换回阻塞套接字后无法连接到套接字
有两个套接字服务器,一个是主服务器,它并不总是打开,另一个是备份服务器 我的程序将尝试使用非阻塞连接连接主服务器(以便可以应用超时val),如果失败,它将使用阻塞连接连接备份服务器 但是,第二个connect函数在大多数情况下将返回“无效参数”错误代码:Sockets 切换回阻塞套接字后无法连接到套接字,sockets,nonblocking,Sockets,Nonblocking,有两个套接字服务器,一个是主服务器,它并不总是打开,另一个是备份服务器 我的程序将尝试使用非阻塞连接连接主服务器(以便可以应用超时val),如果失败,它将使用阻塞连接连接备份服务器 但是,第二个connect函数在大多数情况下将返回“无效参数”错误代码: #define SERVER_URL "example.com" #define SERVER_PORT_PRIMARY "1234" #define SERVER_PORT_BACKUP "5678" struct addrinfo *re
#define SERVER_URL "example.com"
#define SERVER_PORT_PRIMARY "1234"
#define SERVER_PORT_BACKUP "5678"
struct addrinfo *result = NULL;
struct addrinfo hints;
ZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
if (getaddrinfo(SERVER_URL , SERVER_PORT_PRIMARY , &hints, &result) != 0) {
WSACleanup();
return;
}
SOCKET socketClient = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (socketClient == SOCKET_ERROR){
WSACleanup();
return;
}
//set the socket in non-blocking
unsigned long iMode = 1;
iResult = ioctlsocket(socketClient, FIONBIO, &iMode);
if (iResult != NO_ERROR){
closesocket(socketClient);
WSACleanup();
return;
}
if (connect(socketClient, result->ai_addr, (int)result->ai_addrlen) == SOCKET_ERROR){
if (WSAGetLastError() != WSAEWOULDBLOCK){
closesocket(socketClient);
WSACleanup();
return;
}
}
//switch it back to blocking socket
iMode = 0;
iResult = ioctlsocket(socketClient, FIONBIO, &iMode);
if (iResult != NO_ERROR){
closesocket(socketClient);
WSACleanup();
return;
}
fd_set Write, Err;
FD_ZERO(&Write);
FD_ZERO(&Err);
FD_SET(socketClient, &Write);
FD_SET(socketClient, &Err);
TIMEVAL Timeout;
Timeout.tv_sec = 10;
Timeout.tv_usec = 0;
select(0, NULL, &Write, &Err, &Timeout);
if (FD_ISSET(socketClient, &Write) == false){
//unable to connect to primary server within 10s, try to connect backup server
ZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
if (getaddrinfo(SERVER_URL , SERVER_PORT_BACKUP, &hints, &result) != 0) {
closesocket(socketClient);
WSACleanup();
return;
}
iResult = connect(socketClient, result->ai_addr, (int)result->ai_addrlen);
if (iResult == SOCKET_ERROR){
int a = WSAGetLastError(); ///<----Problem here, a == WSAEINVAL (Invalid argument)
closesocket(socketClient);
WSACleanup();
return;
}
}
#定义服务器URL“example.com”
#定义服务器\端口\主“1234”
#定义服务器端口备份“5678”
struct addrinfo*result=NULL;
结构addrinfo提示;
零内存(&提示,sizeof(提示));
hits.ai_family=AF_INET;
hits.ai_socktype=SOCK_流;
hits.ai_protocol=IPPROTO_TCP;
if(getaddrinfo(服务器URL、服务器端口主、提示和结果)!=0){
WSACleanup();
返回;
}
SOCKET socketClient=SOCKET(AF_INET、SOCK流、IPPROTO_TCP);
if(socketClient==SOCKET\u错误){
WSACleanup();
返回;
}
//将插座设置为非阻塞状态
无符号长iMode=1;
iResult=ioctlsocket(socketClient、FIONBIO和iMode);
如果(iResult!=无错误){
closesocket(socketClient);
WSACleanup();
返回;
}
if(connect(socketClient,result->ai_addr,(int)result->ai_addrlen)=套接字错误){
如果(WSAGetLastError()!=WSAEWOULDBLOCK){
closesocket(socketClient);
WSACleanup();
返回;
}
}
//将其切换回阻塞插座
iMode=0;
iResult=ioctlsocket(socketClient、FIONBIO和iMode);
如果(iResult!=无错误){
closesocket(socketClient);
WSACleanup();
返回;
}
fd_设置写入,错误;
FD_零(写入和写入);
FD_零(&Err);
FD_集(socketClient,&Write);
FD_集(socketClient和Err);
TIMEVAL超时;
Timeout.tv_sec=10;
Timeout.tv_usec=0;
选择(0、空、写、错误和超时);
if(FD_ISSET(socketClient,&Write)==false){
//无法在10秒内连接到主服务器,请尝试连接备份服务器
零内存(&提示,sizeof(提示));
hits.ai_family=AF_INET;
hits.ai_socktype=SOCK_流;
hits.ai_protocol=IPPROTO_TCP;
if(getaddrinfo(服务器URL、服务器端口备份、提示和结果)!=0){
closesocket(socketClient);
WSACleanup();
返回;
}
iResult=connect(socketClient,result->ai_addr,(int)result->ai_addrlen);
if(iResult==SOCKET\u错误){
int a=WSAGetLastError();//当connect()
仍在忙着连接时,您必须使套接字处于非阻塞模式。仅当connect()
返回WSAEWOULDBLOCK
时调用select()
,并且需要检查select()的返回值
也一样。您还泄漏了由getaddrinfo()返回的内存。
请尝试类似以下内容:
int connectTo(SOCKET s, const char *host, const char *port)
{
struct addrinfo *result = NULL;
struct addrinfo hints;
ZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
int ret = getaddrinfo(host, port, &hints, &result);
if (ret != 0) {
return ret;
}
if (connect(socketClient, result->ai_addr, result->ai_addrlen) != SOCKET_ERROR) {
freeaddrinfo(result);
return 0;
}
ret = WSAGetLastError();
freeaddrinfo(result);
if (ret != WSAEWOULDBLOCK) {
return ret;
}
fd_set Write, Err;
FD_ZERO(&Write);
FD_ZERO(&Err);
FD_SET(s, &Write);
FD_SET(s, &Err);
TIMEVAL Timeout;
Timeout.tv_sec = 10;
Timeout.tv_usec = 0;
ret = select(0, NULL, &Write, &Err, &Timeout);
if (ret == SOCKET_ERROR) {
return WSAGetLastError();
}
if (ret == 0) {
return WSAETIMEDOUT;
}
if (FD_ISSET(s, &Err)) {
u_long err;
if (getsockopt(s, SOL_SOCKET, SO_ERROR, (char*)&err, sizeof(err)) == SOCKET_ERROR) {
return WSAGetLastError();
}
return (int) err;
}
return 0;
}
然后你可以这样做:
#define SERVER_URL "example.com"
#define SERVER_PORT_PRIMARY "1234"
#define SERVER_PORT_BACKUP "5678"
SOCKET socketClient = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (socketClient == SOCKET_ERROR) {
WSACleanup();
return;
}
//set the socket in non-blocking
u_long iMode = 1;
iResult = ioctlsocket(socketClient, FIONBIO, &iMode);
if (iResult == SOCKET_ERROR) {
closesocket(socketClient);
WSACleanup();
return;
}
if (connectTo(socketClient, SERVER_URL, SERVER_PORT_PRIMARY) != 0) {
if (connectTo(socketClient, SERVER_URL, SERVER_PORT_BACKUP) != 0) {
closesocket(socketClient);
WSACleanup();
return;
}
}
//switch it back to blocking socket
iMode = 0;
iResult = ioctlsocket(socketClient, FIONBIO, &iMode);
if (iResult == SOCKET_ERROR) {
closesocket(socketClient);
WSACleanup();
return;
}
// communicate with the server as needed ...