QT client to C server



  • Am un server tcp realizat in C, 100% functional. Am incercat sa fac un client in QT care sa se conecteze la server. Deocamdata nu vreau sa trimit date, doar sa realizez conexiunea, intrucat aplicatia are ca un login unde trebuie introdus IP si PORT. Transferul de date se va realiza ulterior. Problema e ca nu reusesc sa ma conectez la server. Mai jos e codul pentru void Login::on_Login_clicked()
    @
    void Login::on_pushButton_clicked()
    {

    pSocket = new QTcpSocket (this);
    connect (pSocket, SIGNAL(connected()), SLOT(handleConnected()));
    connect (pSocket, SIGNAL(error(QAbstractSocket::SocketError)), SLOT (handleError()));
    pSocket->connectToHost("127.0.0.1", 9000);
    

    }@

    Am modificat codul dupa sfaturile celor de pe forumul principal. Totusi nu reusesc sa.l fac sa mearga. Nu se intampla nimic cand apas pe login.

    Aici e handleConnectul

    @void Login::handleConnected()
    {
    Menu mMenu;
    mMenu.setModal(true);
    mMenu.exec();
    }@

    Teoretic ar trebui sa imi deschida un nou dialog box. Practic, nu face nimic



  • Esti sigur ca serverul este 100% functional ? Din cate vad serverul trebuie sa "asculte" o eventuala conexiune pe portul 9000. Fii sigur ca portul 9000 este pornit. Daca folosesti windows +firewall, trebuie ca programul pt. server sa fie in lista de exceptii a firewallului, SAU poti sa folosesti windows api pt. a trece de firewall. O alta posibila problema in partea de client, vad ca ai un Menu object instance. Ce exact este acest Menu, dialog sau meniu ?



  • Serverul e pornit si asculta la portul 9000 si se afla pe o masina linux. Menu e un dialog care trebuie sa se deschida teoretic dupa ce s-a realizat conexiunea. Am testat deja daca SLOT-ul on_pushButton_clicked() este functional fara partea de networking, si merge.



  • Ok, daca ai acces la codul sursa din server, poti pune un breakpoint dupa listen ? sa vezi daca trece. O alta solutie sa fii sigur ca serverul functioneaza, dupa ce serverul accepta conexiunea, trimite la client un simplu text, sa zicem Salut, si testeaza din orice webbrowser ceva de genul http://localhost:9000 si vezi daca in browser iti apare Salut. Serverul este functional 100% daca in browser apare textul trimis de server.



  • Problema e ca serverul nu trimite decat daca primeste un text intai de la client. Tocmai m-am conectat cu un client C si am trimis un mesaj. Am primit inapoi Hello mesaj. Deci pot spune ca merge. Nu am primit insa nimic cand am scris in browser IPul:9000



  • Un socket poate trimite altui socket oricand orice succesiune de bytes. Fie ca ii "server", fie ca este "client", tot socket este, deci nu este neaparat ca un client sa trimita ceva pt. ca serverul sa rapsunda. Oricum un browser trimite un http get request cand se conecteaza, deci serverul tau trebuie sa primeasca ceva de genul HTTP GET 1.1 ... etc .. etc... check GET protocol. La prima vedere pare ca serverul nu accepta orice conexiune, de aceea cum am zis pune un breakpoint sa vezi unde este neregula.



  • De vina e serverul meu C. Am facut un server in QT si mi se conecteaza. Chestia e ca mie imi trebuie un server scris in stardard C sau C++, deci nu pot folosi qt pentru server



  • Ok, nu cred ca implementarea in C/C++ este problema, deoarece si Qt foloseste tot C sockets. Si eu am implementat un socket server in pure C socket fara nici un alt framework, si merge pe toate cele 3 OS-uri. Pot sa conectez orice browser la server. Nu am testat cu client facut cu Qt, dar in mod normal trebuie sa functioneze, nu prea vad ca sa nu fie in regula.



  • Mai am o problema acum. Dupa ce trec de login, aplicatia mea ofera un meniu cu mai multe posibilitati. In momentul in care dau click pe o optiune, as vrea ca clientul meu sa transmita date serverului prin acelasi socket pe care l-am folosit la login (motivul e ca am foarte multe optiuni si nu stiu cat de eficient e sa fac socket nou de fiecare data). Singura modalitate pe care am reusit sa o implementez consta in

    @ pSocket = new QTcpSocket(this);
    pSocket->connectToHost("127.0.0.1", 1234);
    if (pSocket->waitForConnected())
    {
    char buffer[]="text";
    int len = strlen(buffer);
    buffer[len] = '\n';
    buffer[len+1] = '\0';
    pSocket->write(buffer);
    pSocket->flush();
    }@
    E total ineficient pentru ca imi face conexiuni noi de fiecare data cand transmit date. Am incercat sa imi fac clasa fotbal sa mosteneasca clasa login(unde e socketul), dar nu am avut succes. Vreo idee?



  • bq. Dupa ce trec de login

    Sa inteleg ca ai rezolvat problema ? Daca da, poti sa zici in forum care a fost solutia pentru ca alti useri sa poata vedea ?

    bq. as vrea ca clientul meu sa transmita date serverului prin acelasi socket pe care l-am folosit la login

    Da este posibil sa folosesti aceeasi conexiune daca nu o inchizi, fie in server, fie in client, deci inchide socket (close, shutdown) doar cand clientul se opreste.

    bq. buffer[len+1] = '\0';

    La linia acesta la un moment dat o sa iti crape clientul. De ce nu folosesti Qt sau macar std:: string class ? Alta mica sugestie ii sa scrii prima data marimea sirului pt. ca in server sa stii cate caractere sa citesti.



  • bq. La linia acesta la un moment dat o sa iti crape clientul.

    Sorry, my bad, am fost furat de peisaj :-)
    Nu o sa crape, dar buffer [5] already are valoarea '\0' nu trebuie sa mai scrii manual. La linia 7 faci ca buffer sa aibe valoare 't', 'e', 'x', '\n'. Asta doresti ?



  • Nu e chiar o rezolvare, de vina era serverul meu C asa ca am decis sa fac altul in QT iar acum functioneaza fara sa fac modificari. Partea cu write spre server este pur simbolica pentru moment. Multumesc pentru sesizarea cu 't' 'e' 'x' '\n', nu asta doream sa se intample. Totusi, cum folosesc acelasi socket? Momentan eu am in clasa Login declarat socketul pSocket. Vreau sa il folosesc si in clasele fotbal si tenis, dar primesc eroare de genul pSocket was not declared in this scope. Partea de cod de mai sus este functionala dar eu nu vreau sa se conecteze la host, intrucat asta s-a intamplat deja in login. Vreau doar sa folosesc acelasi socket pentru transmitere de date.



  • Buna, scuze pt. intarziere, am fost f. ocupat zilele acestea.

    bq. Vreau sa il folosesc si in clasele fotbal si tenis, dar primesc eroare de genul pSocket was not declared in this scope.

    Exista mai multe posibilitati, depinde de softul pe care vrei sa il implementezi. Poti deriva clasele fotbal si tenis din login, si o sa ai acces la socketul din login. Poti sa pasezi login object in constructorii de la tenis, fotbal. Poti avea login class ca si singleton pattern, etc ...



  • Din pacate cunostintele mele de OOP sunt reduse, deci as vrea sa imi recomanzi cea mai simpla solutie. Am incercat sa derivez, dar nu mi-a mers.
    Codul arata asa

    @class Footbal : public QDialog, public Login@
    Primesc eroarea:

    'QObject' is an ambiguos base of 'Footbal' - de 4 ori. Si un warning:
    Class Footbal inherits from two QObject subclasses QDialog and Login. This is not supported!

    public QDialog era pus inca din momentul in care am realizat interfata si am creat legaturile on_pushbutton_clicked.



  • Poti sa pasezi Login object in constructor la Footbal class

    @
    class Footbal(const Login& l)
    {
    // here you can access QTcpSocket object din Login class, ceva de genul
    QTcpSocket* socket = l.socket();
    }
    @



  • Am scos-o la capat cu chestia asta. Acum stiu ca mesajele ajung de la client la server si de la server la client. Problema e urmatoarea: eu vreau sa transmit date destul de multe de la server la clienti, inclusiv \n-urile. Pentru a le afisa in client folosesc QMessagebox-uri. Nu am reusit sa primesc in client decat cate un singur rand. Intrebarea mea e: nu poate Messagebox-ul sa suporte randuri multiple? Sau cum pot transmite date mari de la server la client.

    O portiune de cod in care incerc sa transmit date la client:

    @ QByteArray Data = socket->readAll(); // citirea informatiei din socket;
    qDebug() << socketDescriptor << "Data in: " << Data; // scrierea informatiei de la client
    QString Data2;
    Data2 = "\n1 Dinamo\n2 Steaua\n 3Vaslui\n";
    socket->write(Data); //test, sa vad daca merge sa scriu inapoi ce am primit
    socket->flush();
    socket->write(Data2.toUtf8());
    socket->flush();@

    Partea interesanta e ca de fiecare data cand apas butonul respectiv primesc doar pana la \n - apas odata, primesc 1 Dinamo, mai apas odata, primesc 2 Steaua etc.



  • bq. nu poate Messagebox-ul sa suporte randuri multiple?

    QMessageBox suporta randuri multiple, dar nu aici cred ca este problema ta

    Din cate vad trimiti de 2 ori aceleasi date, odata la linia 4 si odata la linia 7
    La client ce primesti daca chemi
    @
    int receivedBytesSize = socket->readAll()->size();
    @

    Ce valoare are "receivedBytesSize" ?



  • @if(pSocket->waitForConnected())
    {
    int recvBS = pSocket->readAll().size();
    qDebug () << recvBS;
    }@
    Ciudat.
    Cand apas prima oara pe butonul respectiv imi scrie 0. Dar daca apas iar imi da 28. Daca mai apas in continuare, tot 28. Deci 28 cred ca e marimea. Dar nu-s lamurit ce inseamna 0 ala intai. Nu as vrea sa am pierderi de date

    Cum pot face sa am mai mult spatiu? Vreau sa trimit chiar poate chiar si 2048 caractere



  • bq. Cand apas prima oara pe butonul respectiv imi scrie 0. Dar daca apas iar imi da 28.

    Poti sa scrii exact ce trimiti de la server ?
    Iar codul de mai sus pune-l intr-un slot connectat la readyRead signal emis de "pSocket"

    bq. Nu as vrea sa am pierderi de date

    Nu o sa ai niciodata pierderi de date. TCP protocol tocmai asta este, garanteaza ca toate packets ajung la destinatie si in ordinea in care sunt trimise.



  • @void Thread::readyRead()
    {
    QByteArray Data = socket->readAll(); // citirea informatiei din socket;
    qDebug() << socketDescriptor << "Data in: " << Data; // scrierea informatiei de la client
    QString Data2;
    Data2 = "\n1 Dinamo\n2 Steaua\n 3Vaslui\n";
    socket->write(Data2.toUtf8());
    socket->flush();
    }@

    asta e functia din server.

    Acum rezolv si cu readyRead-ul in client si postez imediat



  • @connect (pSocket, SIGNAL(readyRead()), SLOT (handleRead()));@

    @void MainWindow::handleRead()
    {
    int recvBS = pSocket->readAll().size();
    qDebug () << recvBS;
    }@

    Am testat si primesc doar 28 in output.



  • In server o sa vreau sa citesc din fisier si sa trimit la client, deci exemplul cu Dinamo Steaua nu e chiar relevant. Totusi, as vrea sa ma asigur ca am sanse de reusita in ceea ce fac. Citire din fisier si trimitere prin socket la client.



  • bq. Am testat si primesc doar 28 in output.

    ... deci functioneaza bine acuma (din cate inteleg)

    bq. In server o sa vreau sa citesc din fisier si sa trimit la client

    Poti sa trimiti date la client citite de oriunde, de pe hdd, din alt socket, din memorie, etc ... poti sa creezi orice pachet de date


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.