2009-12-01 91 views
14

ポート上でrecvfrom()を試行してから16ミリ秒後に、ブロックするソケットをタイムアウトに設定しようとしています。プラットフォームはWindowsです。私は数多くの例をオンラインで見てきましたが、本当にシンプルなように思えます。どんな助けもありがとう!winsock recvfromのタイムアウトを設定する

#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; */ 
+0

SO_RCVTIMEOはあまり移植性がありません - どのプラットフォームを使用していますか? – Dipstick

+8

'select'関数を使用したいと思うかもしれません – laura

+0

ありがとう!ええ、私は選択肢を調べて、それを動作させました! –

答えて

21

私はselect関数を調べました。そして、lauraが言ったように、私はそれをすべきであり、簡単に実際に動作させる必要がありました!ありがとう!

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); 
+0

あなたがあなたのアプリケーションを走らせるたびに1つのパケットだけを送ることを私が理解する。ループの中で何千ものパケットを送信していると仮定すると、このコードはクラッシュする可能性があります。あなたはその問題をどうやって解決しますか? –

+0

これは最高の答えです。もう1つの答え--DWORDとしてのSO_RCVTIMEO - はrecvfromをタイムアウトさせますが、それにはいくつかの問題があります:1)タイムアウトが発生した場合、ソケットはもはや有効な状態にありません。 2)タイムアウトの方法を説明したWindowsのドキュメントを見つけることができませんでした...しかし、あなたのソケットが無効になるので、とにかく新しいものを作る必要があると思います。 –

1

私はWindowsをWSASocket()呼び出しから推測しています。そうならタイムアウトを間違って渡しています。

MSDNによると、SO_RCVTIMEOは、タイムアウトをミリ秒単位で指定するintパラメータを使用します。

+0

また、次のように渡して試してみました。 int ms = 16; if(setsockopt(mHandle、SOL_SOCKET、SO_RCVTIMEO、reinterpret_cast (&ms)、sizeof(int)) return 1; 私はまだ同じ結果を持っています。 –

+0

これは私がSO_RCVTIMEOを受け付けないBSDソケットシステムに必要なものです –

+0

これはまた、 "ブロッキング受信呼び出しがタイムアウトした場合、接続は不確定状態です ソケットがWSASocket関数を使用して作成された場合、dwFlagsパラメータにタイムアウトが正しく機能するようにWSA_FLAG_OVERLAPPED属性が設定されていなければなりません。それは定期的に使用される... – Marki555

10

WINDOWS: タイムアウト値はミリ秒単位でDWORDである、(SETSOCKOPTに渡されたアドレス)のconst char型である*

LINUX: タイムアウト値が(SETSOCKOPTに渡されたstruct timevalに、アドレスでは)constはありますvoid *型

出典:http://forums.codeguru.com/showthread.php?t=353217

13

私はfolloing

01のようにそれを渡すことで、それを試してみました

と実行してください!

+0

こんにちは、ようこそ。コードだけでなく、言葉で答えを説明してください。誰もがそのように学ぶ方が簡単になります。また、あなたは古い質問に答えているので、あなたの答えは他の回答とどう違うのですか? –

関連する問題