2015-09-08 88 views
0

我寫了一個服務器/客戶端設置,可以來回發送字符串,它的工作原理。現在我試圖從一個不工作的PHP腳本發送數據,所以我試圖解開爲什麼它不起作用。通過套接字發送數據的過程是如何工作的?

這是代碼從客戶端發送的數據,我發送到服務器=「AA」

(介意在代碼中的註釋)

void Client::sendNewMessage(){ 
    qDebug() << "sendNewMessage()"; 

    QString string(messageLineEdit->text()); 

    QByteArray block; 
    QDataStream out(&block, QIODevice::WriteOnly); 
    out.setVersion(QDataStream::Qt_4_0); 
    out << quint16(0) << string; // why is the quint16 appended before the string? 
    out.device()->seek(0); // set current position to 0, why exactly? 
    out << (quint16)(block.size() - sizeof(quint16)); // substract 16bit unsigned int from the total data size? 
                 //Probably something to do with the appending of the quint16 at the beginning. 

    tcpSocket->write(block); 
} 

字符串,這是讀功能服務器:

void TcpServer::readIncomingData(){ 
    QDataStream in(tcpServerConnection); 
    in.setVersion(QDataStream::Qt_4_0); 

    int size = (int) sizeof(quint16); // get packetsize? size = 2 because quint16 is 2 bytes? 
    qDebug() << "size = " << size; 

    // ** OPTIONAL CODE, WORKS WITHOUT ASWELL ** // I got this somewhere from the internet. 
    if (tcpServerConnection->bytesAvailable() < (int)sizeof(quint16)) 
     return; // if size of packet is less than 2, return. 
       // Because there is not enough bytes to correctly read the data? 

    quint16 blockSize = 0; 
    in >> blockSize; // i noticed that after this line executes 
        // tcpServerConnection->bytesAvailable is substracted by 2 
        // and blockSize = 8 instead of 10, because 
        // tcpServerConnection->bytesAvailable starts with 10. 
        // it seems that the socket recognizes that a quint16 was appended 
        // before the actual data, hence the 8 bytes. Is this correct? 

    if (tcpServerConnection->bytesAvailable() < blockSize) 
     return; 

    QString data; 
    in >> data; 
    qDebug() << "data = " << data; 

因此,對於這些問題的主要目的是爲了能夠從PHP腳本到服務器發送數據,所以我甲腎上腺素編輯(並且想要)知道整個過程如何工作。如果有人能在這個黑洞上發現一些光,我會很高興:D

注意服務器和客戶端都是用QTcpSocket和QTcpServer編寫的。

+1

插座是順序I/O設備,並尋求它們是沒有操作。不要在他們身上尋找! –

+1

...但您的代碼中的第一個搜索是有效的。你正在尋找一個緩衝區,而不是套接字:) –

+0

@KubaOber aaah是的,我已經從下面的評論中得到:D謝謝! – CantThinkOfAnything

回答

2

TCP是一個字節流協議,這意味着數據以有序的字節流發送和接收,而不保留任何邏輯消息邊界。在這方面,讀取數據有點像讀取終端設置爲非緩衝模式時的std::cin:您可能會得到用戶輸入的下一個字符,或者10個字符,或者一個完整的行,一行半或下一個4k。關於唯一可以確定的是,您無法獲得比寫入流更多的內容。這是給你的工作了,當你有足夠的數據有意義的過程:這可能是由...

  • 掃描像'\n'一個標記字符,知道輸入的完整的生產線是不同的「邏輯「值得處理的消息

  • 預先將下一個邏輯消息的長度作爲固定長度字段(更容易)或可變長度的文本,後面跟着已知的分隔符,如空格或換行符;這是你的代碼與2字節quint16size

  • 填充每個邏輯消息做一個固定長度

它是那麼必要保持read() ING或recv()操作直到足夠的字節已經爲您讀取以處理下一個邏輯消息。

看來你的QDataStream正在讓你更容易通過read() ing/recv() ing - 可能在後臺線程或者你的應用程序空閒時。它顯然提供了bytesAvailable()作爲它已經從TCP流接收並且在其緩衝區中的字節數。

在客戶端:

QString string(messageLineEdit->text()); 
QByteArray block; 
QDataStream out(&block, QIODevice::WriteOnly); 
out.setVersion(QDataStream::Qt_4_0); 
out << quint16(0) << string; // why is the quint16 appended before the string? 

此寫入的2字節的 「0」 值,接着從string文本。前者實際上爲string保留了空間。

out.device()->seek(0); // set current position to 0, why exactly? 

這跳過字符串,其中2個字節的「0」值上面寫之前回來...

out << (quint16)(block.size() - sizeof(quint16)); // substract 16bit unsigned int from the total data size? 

這將覆蓋上面寫與實際尺寸的「0」值字符串,它通過從block大小中減去2個字節來確定。

在服務器端,它看起來像每次收到更多數據時都要調用該函數,並檢查是否有足夠的數據要解析爲下一條消息。它看起來有點奇怪,好像有足夠的數據來解析size,但整個字符串還沒有被緩衝,然後它返回並且這樣做會丟棄關於blockSize的所有知識,這些知識已經從QDataStream中刪除。相反,它應該記住blockSize某處(例如,在一個類成員變量中),並且下次該函數調用它應該從if (tcpServerConnection->bytesAvailable() < blockSize)繼續。

+0

謝謝你的明確解釋。所以如果我是正確的,在服務器端,「in >> blocksize」只在變量內傳送2位,因爲變量是類型quint16,它是2位。前2位包含8字節的字符串長度,因此blocksize = 8(證實我在調試中看到的內容)。我也沒有意識到,在客戶端,seek(0)將流放在第一個位置,然後用REAL消息的大小覆蓋前兩個字節。 – CantThinkOfAnything

+1

@CantThinkOfAnything:正確的想法,雖然'quint16'是兩個*字節*,而不是位。 'seek(0)'這個東西很愚蠢,因爲字符串的大小必須可以直接寫入文件而沒有這種欺騙。 –

+0

啊的確如此,那是一個錯字。並且用查找位,你說我可以首先附加消息的大小,然後附加字符串,而不是附加空白大小的單位,然後再附加字符串,然後再次實際大小。所以基本上2步而不是3。對不對? – CantThinkOfAnything

相關問題