0

Windows Sockets で WSAEventSelect I/O モデルを使用していますが、送信操作と受信操作ですべてのデータが送受信されたことをどのように確認できますか?

それがわかった後、データを完全に送信する方法をどのように設計すればよいでしょうか? どんな例でも本当に感謝しています。

これがコードです(私が学んでいる本のサンプルコード):

SOCKET SocketArray [WSA_MAXIMUM_WAIT_EVENTS];
WSAEVENT EventArray [WSA_MAXIMUM_WAIT_EVENTS],
NewEvent;
SOCKADDR_IN InternetAddr;
SOCKET Accept, Listen;
DWORD EventTotal = 0;
DWORD Index, i;
WSANETWORKEVENTS NetworkEvents;


// Set up socket for listening etc...
// .... 

NewEvent = WSACreateEvent();

WSAEventSelect(Listen, NewEvent,
               FD_ACCEPT │ FD_CLOSE);

listen(Listen, 5);

SocketArray[EventTotal] = Listen;
EventArray[EventTotal] = NewEvent;
EventTotal++;

while(TRUE)
{
    // Wait for network events on all sockets
    Index = WSAWaitForMultipleEvents(EventTotal,
        EventArray, FALSE, WSA_INFINITE, FALSE);
    Index = Index - WSA_WAIT_EVENT_0;

    // Iterate through all events to see if more than one is signaled
    for(i=Index; i < EventTotal ;i++
    {
        Index = WSAWaitForMultipleEvents(1, &EventArray[i], TRUE, 1000, 
            FALSE);
        if ((Index == WSA_WAIT_FAILED) ││ (Index == WSA_WAIT_TIMEOUT))
            continue;
        else
        {
            Index = i;
            WSAEnumNetworkEvents(
                SocketArray[Index],
                EventArray[Index], 
                &NetworkEvents);

            // Check for FD_ACCEPT messages     
            if (NetworkEvents.lNetworkEvents & FD_ACCEPT)
            { 
                if (NetworkEvents.iErrorCode[FD_ACCEPT_BIT] != 0)
                {
                    printf("FD_ACCEPT failed with error %d\n", 
                        NetworkEvents.iErrorCode[FD_ACCEPT_BIT]);
                    break;
                }

                // Accept a new connection, and add it to the
                // socket and event lists
                Accept = accept(
                    SocketArray[Index],
                    NULL, NULL);

                NewEvent = WSACreateEvent();

                WSAEventSelect(Accept, NewEvent,
                    FD_READ │  FD_CLOSE);

                EventArray[EventTotal] = NewEvent;
                SocketArray[EventTotal] = Accept;
                EventTotal++;
                printf("Socket %d connected\n", Accept);
            }

            // Process FD_READ notification
            if (NetworkEvents.lNetworkEvents & FD_READ)
            {
                if (NetworkEvents.iErrorCode[FD_READ_BIT] != 0)
                {
                    printf("FD_READ failed with error %d\n", 
                        NetworkEvents.iErrorCode[FD_READ_BIT]);
                    break;
                }

                // Read data from the socket
                recv(SocketArray[Index - WSA_WAIT_EVENT_0],
                    buffer, sizeof(buffer), 0);

                // here I do some processing on the data received
                DoSomething(buffer);

                // now I want to send data
                send(SocketArray[Index - WSA_WAIT_EVENT_0],
                        buffer, sizeof(buffer), 0);
                // how can I be assured that the data is sent completely

            }

            // FD_CLOSE handling here
            // ......
            // ......
        }
    }
}

私が考えたのは、ブール値のフラグを設定して、受信が完了したことを判断し (メッセージの長さが前に付けられます)、そのデータの処理を開始することです。しかし、send()はどうですか? 可能性を教えてください。

**編集:** FD_READ イベント部分を参照してください

4

2 に答える 2

0

recv を実行しているときは、データが受信されたかどうかを判断するために、戻りステータスを保存する必要があります。recv は受信したバイト数を返します。4 番目のパラメーターに 0 の代わりにフラグ MSG_WAITALL を使用して、すべてのメッセージを (バッファー サイズに基づいて) 受信します。ステータス recv が負の値を返した場合は、相手側からの接続が閉じていた、またはその他の問題があったなど、なんらかの性質のエラーが発生しています。

送信に関しては戻り値をステータスとしてもそのまま保存しておく必要がありますが、この場合、すべてのデータを送信してから返すフラグがありません。送信量を決定し、値に基づいてバッファと送信サイズを調整する必要があります。recv と同様に、負の値はエラーが発生したことを示します。

Microsoft の Web サイトでrecvの関数の説明を読み、戻り値とフラグの詳細について送信します。

于 2009-09-02T04:16:08.770 に答える
0

処理しているプロトコル (アプリケーション層) が、受信しようとしているデータの数に関する情報を提供しない限り、受信するデータがないかどうかを判断する唯一の方法は、ピアが切断されたときです。サーバーが単に送信を停止した場合、それが終了したのか、単にビジーなのかを判断できません。終わったら終わり。また、サーバーが終了したために切断されたのか、接続が切断されたために切断されたのかを判断することもできません。

そのため、ほとんどのプロトコルは、送信する前に送信するバイト数をピアに通知するか、データの最後に境界を配置します。

送信については、使用しているバッファに注意する必要があります。するとsend()、バッファに移動します(デフォルトでは64KB)。send()バッファに配置されたバイト数を返します。送信しようとしていたバイト数よりも少ない場合は、次に FD_WRITE イベントを受信したときに再試行するように管理する必要があります。

通知を受け続けない限り、ピアが既に受信したデータの量を確認することはできません (mIRC DDC がそれを行います)。

それがあなたの疑問を解決したかどうかはわかりませんが、役に立てば幸いです:)

于 2009-09-02T04:07:04.593 に答える