Windows 10套接字和MS PPL。服务器和客户端之间的TCP连接在几秒钟后中断

时间:2016-01-09 17:34:14

标签: sockets tcp win-universal-app c++-cx ppl

我的系统:

服务器: Windows 10 Pro 1511 10586.36 Microsoft Visual Studio 2015社区14.0.24720.00更新1

客户端: Windows 10 IoT核心(版本10586)Raspberry Pi 2.

我的错误:

连接成功建立,但在正常工作几秒钟后丢失。所以数据交换实际上有效,但在Release版本中只有几秒钟,在Debug版本中大约需要40-60秒。

我总是得到:

t.get(); // See code below. Cancelled status.
SocketErrorStatus errorStatus = SocketError::GetStatus(e->HResult);//See code below. errorStatus == 0 (which means Unknown error)

我有时会在客户端出现这些错误,有时在服务器端。

我读了MS示例 - https://code.msdn.microsoft.com/windowsapps/StreamSocket-Sample-8c573931。 我还发现了一些使用SocketStream对象实现异步读/写操作的方法 - https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/DataReaderWriter

但我无法实现稳定的工作。 以下是代码。

服务器端:

void NetworkHandler::Connect() {
    listener->Control->KeepAlive = true;
    listener->Control->NoDelay = true;
    listener->Control->QualityOfService = 
    Windows::Networking::Sockets::SocketQualityOfService::LowLatency;
    String^ localHostAddr = ref new String(L"192.168.0.10");
    HostName^ localHost = ref new HostName(localHostAddr);
    String^ localPort = ref new String(L"3001");
    create_task(listener->BindEndpointAsync(localHost,      
    localPort)).then([this, localHost](task<void> previousTask) {
        try {
            // Try getting an exception.
            previousTask.get();
            String^ message = "Listening on address " +
            localHost->CanonicalName;
        }
        catch (Platform::Exception^ exception) {
            String^ message = "Start listening failed with error: " +
            exception->Message;
        }
    });
    listener->ConnectionReceived += ref new
    TypedEventHandler<StreamSocketListener^,
    StreamSocketListenerConnectionReceivedEventArgs^>(this,
    &NetworkHandler::doAccept);
}

void NetworkHandler::doAccept(StreamSocketListener^ listener,
   StreamSocketListenerConnectionReceivedEventArgs^ object) {
   socket = object->Socket;
   reader = ref new DataReader(socket->InputStream);
   reader->InputStreamOptions = InputStreamOptions::Partial;
   writer = ref new DataWriter(socket->OutputStream);
   ifConnected = true;
   doRead();
   doWrite();
}

void NetworkHandler::doRead() {
    task<UINT32>(reader->LoadAsync(sizeof(UINT32))).then([this](UINT32
    size) {
    if (size < sizeof(UINT32)) {
        // The underlying socket was closed before we were able to read
        // the whole data.
        cancel_current_task();
    }
    UINT32 dataLength = reader->ReadUInt32();
    return task<UINT32>(reader->LoadAsync(dataLength)).then([this, 
        dataLength](UINT32 actualDataLength) {
        if (actualDataLength != dataLength) {
            // The underlying socket was closed before we were able to 
            // read the whole data.
            cancel_current_task();
        }
    });
}).then([this](task<void> t) {
    try {
        // Try getting all exceptions from the continuation chain above 
        // this point.
        t.get();
        //read data here
        timer = reader->ReadDouble(); //timer
        altitudeASL = reader->ReadDouble(); //altitudeASL
        roll = reader->ReadDouble(); //roll
        pitch = reader->ReadDouble(); //pitch
        yaw = reader->ReadDouble(); //yaw
        vCas = reader->ReadDouble(); //vcas
        Eng0Rpm = reader->ReadDouble(); 
        Eng1Rpm = reader->ReadDouble();
        Eng2Rpm = reader->ReadDouble();
        Eng3Rpm = reader->ReadDouble();
        doRead();  //call doRead() again after previous call 
        // successfully ended.
    }
    catch (Platform::Exception^ e) {
        // Explicitly close the socket.
        SocketErrorStatus errorStatus =  
        SocketError::GetStatus(e->HResult);
        if (errorStatus != SocketErrorStatus::Unknown) {
            switch (errorStatus) {
                case SocketErrorStatus::HostNotFound: {
                    // If hostname from user, this may indicate bad input
                    // set a flag to ask user to re-enter hostname
                    break;
                }
                case SocketErrorStatus::ConnectionRefused: {
                    // The server might be temporarily busy
                    break;
                }
                case SocketErrorStatus::NetworkIsUnreachable: {
                    // Could be a connectivity issue
                    break;
                }
                case SocketErrorStatus::UnreachableHost: {
                    // Could be a connectivity issue
                    break;
                }
                case SocketErrorStatus::NetworkIsDown: {
                    // Could be a connectivity issue
                    break;
                }
                default: {
                    // Connection failed and no options are available
                    // Try to use cached data if available 
                    // may want to tell user that connect failed
                    break;
                }
            }
        }
        else {
            // got an Hresult that is not mapped to an enum
            // Could be a connectivity issue
        }
        ifConnected = false;
        delete socket;
    }
    catch (task_canceled&) {
        // Do not print anything here - this will usually happen  
        // because user closed the client socket.
        // Explicitly close the socket.
        ifConnected = false;
        delete socket;
    }
});
}

void NetworkHandler::doWrite() {
    writer->WriteUInt32(4 * sizeof(DOUBLE)); //data size in bytes;
    writer->WriteDouble(aileronCmd);  // 1-st double, aileron;
    writer->WriteDouble(elevatorCmd); //2-nd double, elevator;
    writer->WriteDouble(rudderCmd); //3-rd double, rudder;
    writer->WriteDouble(throttleCmd); //4-th double, throttle;

    UINT32 totalMessageSize = sizeof(UINT32) + 4 * sizeof(DOUBLE);
    //total message size

    task<UINT32>(writer->StoreAsync()).then([this, totalMessageSize] 
    (UINT32 writtenBytes) {
    if (writtenBytes != totalMessageSize)
        cancel_current_task();
    }).then([this](task<void> t) {
    try {
        // Try getting all exceptions from the continuation chain above 
        this point.
        t.get();
        doWrite(); //call doWrite() again after previous call
        successfully ended.
    }
    catch (Platform::Exception^ e) {
        // Explicitly close the socket.
        SocketErrorStatus errorStatus =
        SocketError::GetStatus(e->HResult);
        if (errorStatus != SocketErrorStatus::Unknown) {
            switch (errorStatus) {
                case SocketErrorStatus::HostNotFound: {
                    // If hostname from user, this may indicate bad input
                    // set a flag to ask user to re-enter hostname
                    break;
                }
                case SocketErrorStatus::ConnectionRefused: {
                    // The server might be temporarily busy
                    break;
                }
                case SocketErrorStatus::NetworkIsUnreachable: {
                    // Could be a connectivity issue
                    break;
                }
                case SocketErrorStatus::UnreachableHost: {
                    // Could be a connectivity issue
                    break;
                }
                case SocketErrorStatus::NetworkIsDown: {
                    // Could be a connectivity issue
                    break;
                }
                default: {
                    // Connection failed and no options are available
                    // Try to use cached data if available 
                    // may want to tell user that connect failed
                    break;
                }
            }
        }
        else {
            // got an Hresult that is not mapped to an enum
            // Could be a connectivity issue
        }
        ifConnected = false;
        delete socket;
    }
    catch (task_canceled&) {
            // Do not print anything here - this will usually happen
            // because user closed the client socket.
            // Explicitly close the socket.
            ifConnected = false;
            delete socket;
        }
    });
}

客户方:

void SocketBoard::Connect() {
    socket = ref new StreamSocket();
    socket->Control->KeepAlive = true;
    socket->Control->NoDelay = true;
    socket->Control->QualityOfService =  
    Windows::Networking::Sockets::SocketQualityOfService::LowLatency;
    reader = ref new DataReader(socket->InputStream);
    reader->InputStreamOptions = InputStreamOptions::Partial;
    writer = ref new DataWriter(socket->OutputStream);
    String^ remoteHostAddr = ref new String(L"192.168.0.10");
    HostName^ remoteHost = ref new HostName(remoteHostAddr);
    String^ remotePort = ref new String(L"3001");
    create_task(socket->ConnectAsync(remoteHost, remotePort)).get();
    ifConnected = true;
    TimeSpan period;
    period.Duration = 1 * 10000000; // 10,000,000 ticks per second
    ThreadPoolTimer^ PeriodicTimer =
    ThreadPoolTimer::CreatePeriodicTimer(ref new
    TimerElapsedHandler([this](ThreadPoolTimer^ source) {
    timer_sec--;
    if (timer_sec <= 0)
        source->Cancel();
}), period, ref new TimerDestroyedHandler([&](ThreadPoolTimer^ source)  
{}));
   doRead();
   doWrite();
}

SocketBoard::doRead() { //same as Server }
SocketBoard::doWrite() { //same as Server }

我觉得某些东西(内部缓冲区或线程池)被过头了,这会导致异常。

可以请任何人解释一下吗?

1 个答案:

答案 0 :(得分:0)

我删除了

reader->InputStreamOptions = InputStreamOptions::Partial;

现在读/写操作正常工作。当我复制

时犯了错误
if (actualDataLength != dataLength) {
    // The underlying socket was closed before we were able to 
    // read the whole data.
    cancel_current_task();
}
来自MS样本的

(在上面的问题中提到)。因此,当读取为PARTIAL时,将调用cancel_current_task(),因此套接字正在关闭,这实际上会强制相反的点(客户端/服务器)抛出。