ポートでrecvfrom()を16ミリ秒試行した後、タイムアウトするようにブロッキングソケットを設定しようとしています。プラットフォームはWindowsです。私はオンラインでたくさんの例を見てきましたが、それを機能させることができないように思えるのは本当に簡単なようです。どんな助けでもいただければ幸いです!
#include <winsock2.h>
#include <string>
#pragma comment(lib, "ws2_32.lib")
#define PORT_NUM 8001
int main(void)
{
std::string localIP;
sockaddr_in localAddr;
sockaddr_in remoteAddr;
hostent* localhost;
char buffer[1024];
WSADATA wsData;
int result = WSAStartup(MAKEWORD(2,2), &wsData); // winsock version 2
localhost = gethostbyname("");
localIP = inet_ntoa(*(in_addr*)*localhost->h_addr_list);
localAddr.sin_family = AF_INET;
localAddr.sin_port = htons(PORT_NUM); // Set Port Number
localAddr.sin_addr.s_addr = inet_addr(localIP.c_str()); // Set IP Address
int mHandle = WSASocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP, NULL, 0, 0);
if(mHandle == INVALID_SOCKET)
return 1;
if(bind(mHandle, (SOCKADDR*)&localAddr, sizeof(localAddr)) == SOCKET_ERROR)
return 1;
timeval tv;
tv.tv_sec = 0;
tv.tv_usec = 1600;
// Set Timeout for recv call
if(setsockopt(mHandle, SOL_SOCKET, SO_RCVTIMEO,
reinterpret_cast<char*>(&tv), sizeof(timeval)))
return 1;
int length = sizeof(remoteAddr);
// <-- Blocks here forever
recvfrom(mHandle, buffer, 1024, 0, (SOCKADDR*)&remoteAddr, &length);
return 0;
}
/* I've also tried passing the time like so:
int ms = 16;
if(setsockopt(mHandle, SOL_SOCKET, SO_RCVTIMEO, reinterpret_cast<char*>(&ms), sizeof(int)))
return 1; */
選択機能を調べたところ、ローラが言ったように、実行する必要があり、実際に簡単に機能するようになりました。ありがとう!
fd_set fds ;
int n ;
struct timeval tv ;
// Set up the file descriptor set.
FD_ZERO(&fds) ;
FD_SET(mHandle, &fds) ;
// Set up the struct timeval for the timeout.
tv.tv_sec = 10 ;
tv.tv_usec = 0 ;
// Wait until timeout or data received.
n = select ( mHandle, &fds, NULL, NULL, &tv ) ;
if ( n == 0)
{
printf("Timeout..\n");
return 0 ;
}
else if( n == -1 )
{
printf("Error..\n");
return 1;
}
int length = sizeof(remoteAddr);
recvfrom(mHandle, buffer, 1024, 0, (SOCKADDR*)&remoteAddr, &length);
次のように渡してみました
int iTimeout = 1600;
iRet = setsockopt( pSapManager->m_cSocket,
SOL_SOCKET,
SO_RCVTIMEO,
/*
reinterpret_cast<char*>(&tv),
sizeof(timeval) );
*/
(const char *)&iTimeout,
sizeof(iTimeout) );
そしてそれを実行します!
WINDOWS:タイムアウト値はミリ秒単位のDWORDであり、setsockopt()に渡されるアドレスはconst char *です。
Linux:タイムアウト値はstruct timevalであり、setsockopt()に渡されるアドレスはconst void *
WSASocket()呼び出しからWindowsを推測しています。その場合、タイムアウトを誤って通過しています。
[〜#〜] msdn [〜#〜] は、SO_RCVTIMEOがタイムアウトをミリ秒単位で指定するintパラメーターを受け取ることを示します。