QTソケットはすべてのデータを読み取るわけではありません

サティヤ

Qtのソケットからデータを読み取りたい。QBytearrayを使用してデータを保存しています。実際、サーバーは1回のストレッチで4095バイトを送信しますが、QTクライアント側では、アプリケーションの設計上、異なるチャンクで受信しています。

void Dialog::on_pushButton_clicked()
{
socket=new QTcpSocket(this);
socket->connectToHost("172.17.0.1",5000);
if(socket->waitForConnected(-1))
qDebug()<<"Connected";
Read_data();
}

void Dialog::Read_data()
{
QString filename(QString("%1/%2.bin").arg(path,device));
qDebug()<<"filename"<<filename;
QFile fileobj(filename);

int cmd,file_size,percentage_completed;
if(!fileobj.open(QFile::WriteOnly | QFile::Text))
{
    qDebug()<<"Cannot open file for writting";
    return;
}
QTextStream out(&fileobj);
while(1)
{

socket->waitForReadyRead(-1);
byteArray=socket->read(4);
qDebug()<<"size of bytearray"<<byteArray.size();

length=0xffff & ((byteArray[3]<<8)|(0x00ff & byteArray[2]));
int rem;
byteArray=socket->read(length);
while(byteArray.size()!=length)
{    

rem=length-byteArray.size();

byteArray.append( socket->read(rem));

}
fileobj.write(byteArray);
fileobj.flush();
byteArray.clear();
}
}

サーバーコード:

#include<stdio.h>
#include<stdlib.h>
#include<fcntl.h>
#include<sys/ioctl.h>
#include<mtd/mtd-user.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <arpa/inet.h>
#include<math.h>
#include <netinet/tcp.h>
static int msb,lsb,size,listenfd = 0, connfd = 0,len;
main()
{

struct sockaddr_in serv_addr; 
serverlen=sizeof(serv_addr);
listenfd = socket(AF_INET, SOCK_STREAM, 0);
memset(&serv_addr, '0', sizeof(serv_addr)); 
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
serv_addr.sin_port = htons(5000);

if(bind(listenfd,(struct sockaddr*)&serv_addr, sizeof(serv_addr))<0)
{
  perror("\n Error in binding"); 
  exit(1);
}

size=100000;
listen(listenfd, 1);

fd=fopen(new.bin,"r");  
len=4089;

while(1)
{

 buff[0]=25;
 buff[1]=2;
 buff[2]=60;
 buff[3]=47;
 n=fread(buff+4,1,length, fd);
 buff[len+4]=5;
 buff[len+5]='\n';
 if(n>0)
 sent_bytes=send(connfd,buff,n+6,0);
 size =size-len;
 if(size==0)
 break;
 }
 }

localhost(127.0.0.1)でコードを実行すると、データを完全に受信できます。この問題は、別のホストIPに接続した場合にのみ発生します。この点で親切に私を助けてください

編集1:問題は、bytesAvailable()がwaitForReadyRead()がタイムアウトするのを待っている最大バイトを返すときです。bytesAvailable()が予想よりも小さい場合は、正常に機能します。bytesAvailable()は、この動作に悩まされているバッファを割り当てますか?

while(1)
{
while(socket->bytesAvailable()<4)
{
    if (!socket->waitForReadyRead())
    {
        qDebug() << "waitForReadyRead() timed out";
        return;
    }
}
byteArray=socket->read(4);
length=0xffff & ((byteArray[3]<<8)|(0x00ff & byteArray[2]));
int rem_bytes=length+2;
qDebug()<<"bytes available"<<socket->bytesAvailable();
while(socket->bytesAvailable()<=rem_bytes)
{
    qDebug()<<"reading";
    if (!socket->waitForReadyRead(10000))//times out here if bytesAvailable() == rem_bytes but executes well in other cases
    {
        qDebug() << "waitForReadyRead() timed out";
        return;
    }
    qDebug()<<"ready";
    byteArray.append(socket->read(rem_bytes));
    qDebug()<<"size of bytearray"<<byteArray.size();
    if(byteArray.size()==length+2)
    {
        for(int j=0;j<length;j++)
            newarray.append(byteArray[j]);
        fileobj.write(newarray);
        fileobj.flush();
        newarray.clear();
        byteArray.clear();
        break;                  
    }
    else
    {
        rem_bytes -=byteArray.size();
    }

}
Send();
}

異なるデータサイズを送信してみましたが、理由がわかりません。私が間違っていた場所を示す解決策を教えてください

RobbieE

あなたの問題は、TCPがどのように機能するかについてのあなたの誤解から生じています。

データが送信者から送信されると、データはパケットに分割され、すべてのデータの送信が完了するまで、各パケットが1つずつ送信されます。パケットが欠落した場合、宛先に到達するか、タイムアウトに達するまで、パケットは再送信されます。

さらに複雑なことに、各パケットは宛先に到着する前にさまざまなルートをたどる場合があります。受信者には、パケットが受信されたことを送信者に確認し、パケットが正しい順序で結合されていることを確認するタスクがあります。

このため、ネットワークルートが長いほど、データの再構築が遅れる可能性が高くなります。これは、ローカルホストネットワークコンピューターのテストで経験したことです

コンピューターのIPスタックは、完全なデータが到着するのを待たずにアプリケーションに渡しますが、パケットが順番に欠落している場合は一時停止します。

たとえば、10個のパケットがあり、パケット4が最後に到着した場合、IPスタックは2つのセットでデータをアプリケーションに渡します:1-2-3、[[4が到着するのを待つ]]、4-5-6-7- 8-9-10。

このため、がwaitForReadyRead()返されるときtrue、すべてのデータが到着したとは期待できません。実際に受信されたバイト数を常に確認する必要があります

コードには、データを待つ場所が2つあります。最初に待つのは、送信されたデータの量を示す4バイトの数値です。4バイトすべてを受信する可能性が高い場合でも、確認することをお勧めします。

while(socket.bytesAvailable() < 4){
    if (!socket.waitForReadyRead()) { // timeout after 30 second, by default
        qDebug() << "waitForReadyRead() timed out";
        return;
    }
}
byteArray=socket->read(4);
qDebug()<<"size of bytearray"<<byteArray.size();

length=0xffff & ((byteArray[3]<<8)|(0x00ff & byteArray[2]));

次に行う必要があるのは、すべてのデータが到着するまで、wait-read-wait-readループを循環し続けることです。そのたびに、まだ受信する予定のバイト数を追跡​​します。

int bytesRemaining = length;

while(socket->bytesAvailable() < bytesRemaining){
    if (!socket->waitForReadyRead()){
        qDebug() "waitForReadyRead() timed out";
        return;
    }

    // calling read() with the bytesRemaining argument will not guarantee
    // that you will receive all the data. It only means that you will 
    // receive AT MOST bytesRemaining bytes.
    byteArray = socket->read(bytesRemaining);

    bytesRemaining -= byteArray.size();

    fileobj.write(byteArray);
    fileobj.flush();
}

とはいえ、メインスレッドでブロッキングAPIを使用しないでください。使用すると、GUIがフリーズする可能性があります。非同期APIを使用するか、ダウンロードを処理するワーカースレッドを作成することをお勧めします(ワーカースレッドでブロッキングAPIを使用します)。

2つの異なるAPIの使用方法の例を確認するには、Fortune Client Exampleとのドキュメントを参照してくださいBlocking Fortune Client Example

編集:申し訳ありませんが、上記のコードには多くの可能性を考慮していないバグがあります。最も重要なのは、すべてのデータがすでに受信されている場合、そしてすべてのデータが最終的に到着したらゲームを終了することです。

次の1行の変更で、それが明確になります。

変化する

while(socket->bytesAvailable() < bytesRemaining){

while (bytesRemaining > 0) {

この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。

侵害の場合は、連絡してください[email protected]

編集
0

コメントを追加

0

関連記事

分類Dev

QTソケットはすべてのデータを読み取るわけではありません

分類Dev

Spark連続処理モードは、すべてのkafkaトピックパーティションを読み取るわけではありません

分類Dev

POSTメソッドがすべてのデータを送信しているわけではありません

分類Dev

Rはcsvのすべての行を読み取るわけではありません

分類Dev

すべてのアップデートをインストールできるわけではありません(パッケージがありません)

分類Dev

XmlTextReader.Read()はすべての行を読み取るわけではありません

分類Dev

データチャートはすべてのデータを追加するわけではありません

分類Dev

OpenMpはすべてのCPU(デュアルソケット、Windows、Microsoft Visual Studio)を利用しているわけではありません

分類Dev

HTMLPOSTリクエストはすべてのデータを送信するわけではありません

分類Dev

Pentaho:ルックアップ/更新の組み合わせは、ソース内のすべての行を処理するわけではありません

分類Dev

BufferedReaderは、テキストファイルのすべての行を読み取るわけではありません

分類Dev

Rのread.table()がすべての列を読み取ったわけではありません

分類Dev

Deployはすべてのパッケージを生成するわけではありません

分類Dev

nuget.exeはすべてのパッケージを復元するわけではありません

分類Dev

PHPin_arrayはすべてのケースをチェックするわけではありません

分類Dev

jQueryのdata()メソッドがすべてのデータ属性を一覧表示しているわけではありません

分類Dev

Proforma SalesInvoiceは、すべてのテーブルのデータを表示するわけではありません

分類Dev

Seabornx軸はすべてのデータをカバーしているわけではありません

分類Dev

BeautifulSoupはすべてのデータを取得するわけではありません

分類Dev

PythonSeabornはすべてのデータを表示するわけではありません

分類Dev

PythonSeabornはすべてのデータを表示するわけではありません

分類Dev

Windows7はすべての画像EXIFデータを削除するわけではありません

分類Dev

ActiveRecordがすべてのデータベース列を提供しているわけではありません

分類Dev

JQuerydatepickerがすべてのフィールドに読み込まれるわけではありません

分類Dev

FacebookマーケティングAPIインサイトは、範囲内のすべての日のデータを返すわけではありません

分類Dev

C#TCPでデータを読み取ると、必ずしもすべてのデータを読み取るとは限りません

分類Dev

drcパッケージの用量反応曲線プロットはすべてのポイントを示しているわけではありません

分類Dev

didReceiveDataがすべてのデータを取得しているわけではありません

分類Dev

MVC送信がすべてのデータを返しているわけではありません

Related 関連記事

  1. 1

    QTソケットはすべてのデータを読み取るわけではありません

  2. 2

    Spark連続処理モードは、すべてのkafkaトピックパーティションを読み取るわけではありません

  3. 3

    POSTメソッドがすべてのデータを送信しているわけではありません

  4. 4

    Rはcsvのすべての行を読み取るわけではありません

  5. 5

    すべてのアップデートをインストールできるわけではありません(パッケージがありません)

  6. 6

    XmlTextReader.Read()はすべての行を読み取るわけではありません

  7. 7

    データチャートはすべてのデータを追加するわけではありません

  8. 8

    OpenMpはすべてのCPU(デュアルソケット、Windows、Microsoft Visual Studio)を利用しているわけではありません

  9. 9

    HTMLPOSTリクエストはすべてのデータを送信するわけではありません

  10. 10

    Pentaho:ルックアップ/更新の組み合わせは、ソース内のすべての行を処理するわけではありません

  11. 11

    BufferedReaderは、テキストファイルのすべての行を読み取るわけではありません

  12. 12

    Rのread.table()がすべての列を読み取ったわけではありません

  13. 13

    Deployはすべてのパッケージを生成するわけではありません

  14. 14

    nuget.exeはすべてのパッケージを復元するわけではありません

  15. 15

    PHPin_arrayはすべてのケースをチェックするわけではありません

  16. 16

    jQueryのdata()メソッドがすべてのデータ属性を一覧表示しているわけではありません

  17. 17

    Proforma SalesInvoiceは、すべてのテーブルのデータを表示するわけではありません

  18. 18

    Seabornx軸はすべてのデータをカバーしているわけではありません

  19. 19

    BeautifulSoupはすべてのデータを取得するわけではありません

  20. 20

    PythonSeabornはすべてのデータを表示するわけではありません

  21. 21

    PythonSeabornはすべてのデータを表示するわけではありません

  22. 22

    Windows7はすべての画像EXIFデータを削除するわけではありません

  23. 23

    ActiveRecordがすべてのデータベース列を提供しているわけではありません

  24. 24

    JQuerydatepickerがすべてのフィールドに読み込まれるわけではありません

  25. 25

    FacebookマーケティングAPIインサイトは、範囲内のすべての日のデータを返すわけではありません

  26. 26

    C#TCPでデータを読み取ると、必ずしもすべてのデータを読み取るとは限りません

  27. 27

    drcパッケージの用量反応曲線プロットはすべてのポイントを示しているわけではありません

  28. 28

    didReceiveDataがすべてのデータを取得しているわけではありません

  29. 29

    MVC送信がすべてのデータを返しているわけではありません

ホットタグ

アーカイブ