2012-01-18 13 views
9

Próbuję zaimplementować dwukierunkowy program klient-serwer, w którym klienci i serwery mogą przekazywać między sobą serializowane obiekty. Próbuję to zrobić za pomocą Qt (QTcpSocket i QTcpServer). Zaimplementowałem takie programy w Javie, ale nie mogę wymyślić, jak to zrobić za pomocą Qt. Sprawdziłem przykłady fortune client i fortune server ... ale z tego, co widzę, klient po prostu sygnalizuje serwer, a serwer przesyła mu trochę danych. Potrzebuję, aby klient i serwer wysyłali obiekty tam iz powrotem. Nie szukam kompletnego rozwiązania, szukam tylko wskazówek we właściwym kierunku.Qt dwukierunkowy serwer klienta przy użyciu QTcpSocket i QTcpServer

Napisałem kod, który akceptuje połączenie, ale nie akceptuje danych.

SERWER

ta klasa jest serwer; powinien akceptować połączenie i wyświetlać rozmiar bufora, który jest wysyłany. Jednak to jest wyprowadzanie 0

#include "comms.h" 

Comms::Comms(QString hostIP, quint16 hostPort) 
{ 
    server = new QTcpServer(this); 
    hostAddress.setAddress(hostIP); 
    this->hostPort = hostPort; 


} 

void Comms::attemptConnection(){ 
    connect(server, SIGNAL(newConnection()), this, SLOT(connectionAccepted())); 
    //socket = server->nextPendingConnection(); 
    server->listen(hostAddress,hostPort); 
    //receivedData = socket->readAll(); 
} 

void Comms::connectionAccepted(){ 
    qDebug()<<"Connected"; 
    socket = new QTcpSocket(server->nextPendingConnection()); 

    char* rec = new char[socket->readBufferSize()]; 
    qDebug()<<socket->readBufferSize(); 
} 

CLIENT

Ta klasa jest klient. Powinien przesłać ciąg "hello". Wysyła go z powodzeniem (według mojej wiedzy)

#include "toplevelcomms.h" 
#include "stdio.h" 

TopLevelComms::TopLevelComms(QString hostIP, quint16 hostPort) 
{ 
    tcpSocket = new QTcpSocket(); 
    hostAddress.setAddress(hostIP); 
    this->hostPort = hostPort; 
} 


void TopLevelComms::connect(){ 
    tcpSocket->connectToHost(hostAddress,hostPort,QIODevice::ReadWrite); 
    //tcpSocket->waitForConnected(1); 

    QString string = "Hello"; 
    QByteArray array; 
    array.append(string); 
    qDebug()<<tcpSocket->write(array); 
} 

Proszę mi powiedzieć, co robię źle, albo powiedz mi ogólną logikę ustalenia, co chcę w Qt.

Odpowiedz

9

QTcpSocket jest asynchroniczna domyślnie, więc podczas rozmowy connectToHost i pisać w tym samym kontekście, że nie będzie wysłane, ponieważ gniazdo nie jest połączone. należy zmienić „Klient” Kod:

void TopLevelComms::connect(){ 
    tcpSocket->connectToHost(hostAddress,hostPort,QIODevice::ReadWrite); 
    if(tcpSocket->waitForConnected()) // putting 1 as parameter isn't reasonable, using default 3000ms value 
    { 
     QString string = "Hello"; 
     QByteArray array; 
     array.append(string); 
     qDebug()<<tcpSocket->write(array); 
    } 
    else 
    { 
     qDebug() << "couldn't connect"; 
    } 
} 

Uwaga: można również sprawdzić, czy nie jesteś w stanie słuchać

void Comms::attemptConnection(){ 
    connect(server, SIGNAL(newConnection()), this, SLOT(connectionAccepted())); 
    //socket = server->nextPendingConnection(); 

    if(server->listen(hostAddress,hostPort)) 
    { 
     qDebug() << "Server listening"; 
    } 
    else 
    { 
     qDebug() << "Couldn't listen to port" << server->serverPort() << ":" << server->errorString(); 
    } 
    //receivedData = socket->readAll(); 
} 

i ostatnia rzecz. Zauważ, że QTcpServer :: nextPendingConnection() zwracają QTcpSocket, więc zamiast podejmowania że nowe połączenie utworzyć nową QTcpSocket z nextPendingConnection jako rodzica

void Comms::connectionAccepted(){ 
    qDebug()<<"Connected"; 
    // WRONG! it will use QTcpSocket::QTcpSocket(QObject * parent) 
    //socket = new QTcpSocket(server->nextPendingConnection()); 
    // use simple asign 
    socket = server->nextPendingConnection(); 
    // move reading to slot 
    connect(socket, SIGNAL(readyRead()), this, SLOT(readSocket())); 
} 

teraz ruszymy czytanie oddzielnym gnieździe

void Comms::readSocket() 
{ 
    // note that dynamic size array is incompatible with some compilers 
    // we will use Qt data structure for that 
    //char* rec = new char[socket->readBufferSize()]; 
    qDebug()<<socket->readBufferSize(); 
    // note that QByteArray can be casted to char * and const char * 
    QByteArray data = socket->readAll(); 
} 

muszę przyznać, że jest to dużo błędów, jak na tak małą próbkę kodu. Musisz zdobyć trochę wiedzy na temat połączeń TCP/IP. To są strumienie i nie ma gwarancji, że cały fragment danych dotrze do ciebie natychmiast

+1

Dziękuję bardzo, udało mi się przesłać dane przez gniazdo.Jednak nadal otrzymuję rozmiar bufora 0 z jakiegoś powodu. Każdy pomysł, dlaczego? – PTBG

+0

Z dokumentów "Wielkość bufora odczytu równa 0 (wartość domyślna) oznacza, że ​​bufor nie ma limitu rozmiaru, zapewniając, że żadne dane nie zostaną utracone". W związku z tym nie podaje żadnych informacji na temat rzeczywistej zawartości. Powinieneś użyć 'socket-> size()' lub 'socket-> bytesAvailable()' –

4

Wygląda na to, że masz problem z regulacją czasu. Ponieważ twój klient i serwer są różnymi procesami, nie ma możliwości zagwarantowania, że ​​wykonywana jest całość TopLevelComms::connect() (wraz z transmisją danych sieciowych), zanim funkcja serwera connectionAccepted() spróbuje odczytać z gniazda.

Podejrzewam, że jeśli wykorzystać waitForReadyRead() funkcji QTcpSocket jest, trzeba mieć więcej szczęścia:

void Comms::connectionAccepted(){ 
    qDebug()<<"Connected"; 
    socket = new QTcpSocket(server->nextPendingConnection()); 

    if(socket->waitForReadyRead()) { 
     char* rec = new char[socket->readBufferSize()]; 
     qDebug()<<socket->readBufferSize(); 
    } 
}