2013-05-20 6 views
2

QTcpSocket (nntp는 QTcpSocket에 대한 포인터)에서 데이터를 읽는 루프 본문에 다음과 같은 코드 스 니펫이 있습니다. 이 잘못된 동작합니다에서내 코드가 QTcpSocket에서 사용할 수있는 바이트 수를 읽을 수없는 이유는 무엇입니까? 아이디어?

bytesAvailable: 24 
true 
bytesRead: 0 

그리고 내 코드 :

std::vector<char> buffer; 
int bytesAvailable = nntp->bytesAvailable(); 
qDebug() << "bytesAvailable: "<<bytesAvailable; 
if(bytesAvailable <= 0) break; 
buffer.resize(bytesAvailable); 
bytesRead = nntp->read(&buffer[0], bytesAvailable); 
qDebug() << (nntp->state() == QAbstractSocket::ConnectedState); 
qDebug() << "bytesRead: "<<bytesRead; 

간헐적으로,이 다음에 가까운 무언가를 출력합니다. 이것은 나에게 매우 이상하게 보입니다. QTcpSocket이 어떻게 작동하는지 완전히 오해하고있는 것 같습니다. 확실히 bytesAvailable> 0이면 후속 읽기는 bytesAvailable 바이트를 버퍼로 읽을 수 있음을 의미합니다.이 경우 bytesRead는 == bytesAvailable이어야합니다. 또는 나는 무엇인가 놓치고 있냐? 현재의 추측은 어떤 종류의 메모리 손상 일 수 있다는 것입니다.

EDIT : 일부 nntp.errorString() 메시지를 표시하면이 실패 동안 "네트워크 작업 시간이 초과되었습니다"라는 메시지가 표시됩니다. 이게 무슨 뜻인지 조사해야 해 ... (아이디어?)

EDIT 2 : "네트워크 작업 시간 초과"는 읽기 시간 초과를 의미합니다. 코드가 (즉 간헐적으로) 작동해야 할 때, 나는 여전히이 '오류'를 얻습니다.

편집 3 : 위의 코드 스 니펫에 대한 전체 알고리즘 컨텍스트는 at this pastebin link입니다. this newer pastebin link

+0

정말이 구조가 마음에 들지 않습니다 :'& buffer [0]'. 대신,'buffer = nntp-> readAll();'을 시도해보십시오. – Amartel

+0

당신의 제안에 감사드립니다 Amartel하지만 QByteArray로 전환 한 다음 readAll을 수행하고 QByteArray의 크기를 사용하여 읽은 바이트 수를 결정하면 여전히 동일한 문제가 발생합니다 –

답변

3

내가 읽었던 QTcpSocket이 다른 스레드에 속한 문제를 발견했습니다. QIODevice의 버퍼에 따라 바이트를 사용할 수 있었지만이 때문에 읽을 수 없습니다. 따라서

:

* 항상 당신이에서 읽고 싶은 소켓 당신이

이에 도움이 읽기 *을하려는 스레드에 속하는, 그리고 테일러는 위의 제안 보장 , 하나는 QTcpSocket의 신호와 슬롯 인프라 (선호)를 이용할 수 있습니다. 이것은 적절한 스레딩 인프라를 갖추고 있으며 이론 상으로는 훨씬 더 간단 해집니다.

또는

슈퍼주의해야하고

(a)는 사람을 활용 자신의 QThread,이 QThread

에 QTcpSocket가 들어있는 개체,

(B)를 사용하여 이동 이 다른 스레드의 읽기 읽기 루프에서 QTcpSocket의 waitForReadyRead.

이 후자의 방법이 더 어렵 하나는 미래의 읽기 및 쓰기에 다른 스레드로 이동하고 다른 스레드에 의해 처리 된 후, 후, 다른 스레드의 QTcpSocket을 유지하고자하는 경우 때문에, 그것은 다시 이동해야합니다 메인 스레드가 추가 스레드로 이동할 수 있기 전에. - 나에게 그 말을하려고 애쓰는 두통을 준다! 물론 QTcpSocket 작업자 스레드를 동일하게 유지하여 한 번만 이동하거나 QTcpSocket이 필요할 때마다 새로운 QTcpSocket을 간단하게 작성한 다음 자체 QThread로 이동 한 다음 완료되면 즉시 삭제할 수 있습니다 와.

기본적으로 첫 번째 신호 및 슬롯 방법을 시도하십시오.

2

에서 나는 다른 버전을 사용하고 가능성이 있기 때문에이 정확한 문제 (발생하지 않은 EDIT 3하지만 여전히 그럼에도 불구하고 같은 문제를 가진 함수의 약간 다른 버전입니다 :

EDIT (4) Qt),하지만 내가 시도 할 것을 권장하는 것은 루프에서 이벤트 중심 접근 방식으로 전환하는 것이다. 루프가 메인 스레드에서 실행되고 있다면 QTcpSocket 클래스가 내부적으로 수행 할 수있는 것처럼 객체가 대기열에있는 신호를 전달할 방법이 없기 때문에 "네트워크 작업 시간이 초과되었습니다"라는 메시지가 나타날 수 있습니다.

connect(nntp, SIGNAL(disconnected()), 
     this, SLOT(onDisconnected())); 
connect(nntp, SIGNAL(readyRead()), 
     this, SLOT(onReadyRead())); 
connect(nntp, SIGNAL(error(QAbstractSocket::SocketError)), 
     this, SLOT(onSocketError(QAbstractSocket::SocketError))); 

을 그리고 onReadyRead에서 기존의 "읽기"코드를 삽입 :

그래서 기본 QTcpSocket 신호의 일부를 연결합니다.

어쩌면 당신의 문제는 관련이 없지만 동료가 작성한 코드에서 비슷한 문제가 발생했다는 것을 알았습니다.

+0

Thanks Taylor - 나는 또한 신호와 슬롯 방식을 선호합니다 나는 미래에이 접근 방식으로 바뀔 수 있습니다. 루프를 선택한 이유는 여러 이스케이프 시퀀스에 따라 토큰 화 된 정해진 양의 형식화 된 데이터를 읽을 수 있어야하기 때문입니다. 루프 내에서 이러한 토큰에 따라 데이터를 파싱하는 것이 상대적으로 쉽고 또한 사용할 수 있어야하는 정확한 순간에 데이터를 파싱하는 것이 상대적으로 쉽습니다. 그렇게 말하면서, 제 접근법은 분명히 버그가있어서 좋습니다와 같은 신호와 슬롯으로 전환해야 할 필요가 있습니다. –

2

QIODevice 내부 버퍼에 대기중인 데이터의 크기와 OS에서보고 한 크기 (예 : ioctl(fd,FIONREAD,&bytesCount)으로 얻을 수있는 Linux)를보고하는 경우 일 수 있습니다.

그 자체로 의미가 있지만 이벤트 루프없이 QTcpSocket에서 해당 바이트를 읽을 수 있으려면 waitForReadyRead()을 자신의 루프에서 호출해야합니다. 그렇지 않으면 커널 버퍼의 데이터가 QIODevice의 버퍼에 들어 가지 않습니다.

소켓에서 읽을 내용이 없을 때 코드를 차단할 수없고 이벤트 구동 구조로 변경하지 않으려면 waitForReadyRead의 작은 값을 사용하십시오. 따라서 실제로는 차단하지 않는 것처럼 행동합니다.

또한 이벤트 루프가없는 소켓에 쓰는 경우에도 waitForBytesWritten()을 호출하는 것을 잊지 마십시오.

+0

Daniel, 고맙습니다. 사실 전체 루프의 컨텍스트에서 waitForReadyRead를 사용합니다. 링크는 원래 게시물의 EDIT 3을 참조하십시오. –

+0

바깥 쪽 루프에서'bytesAvailable()'을 읽는 것만으로 차이가 있는지 알아 보겠습니다. 특히 바깥 쪽 루프가 do..while가 아닌 do..while이기 때문에 특히 그렇습니다 –

+0

감사합니다. Daniel, 나는 당신의 제안 (EDIT 4 링크의 코드를 참조)을 시도했지만 여전히 같은 이슈가있다. –