QT TCP Network Programming __ Programming

Source: Internet
Author: User
Tags emit
First, introduce TCP: (Transmission Control Protocol Transmission Control Protocol) is a connection-oriented, reliable, byte-throttling based Transport layer communication protocol. In contrast, UDP is an open, connectionless, unreliable Transport layer communication protocol.
below, I do the client and server-side QT implementation at once. My development environment is: QT Creator 5.7.

First look at the effect of the picture:

One: Client-side programming

QT provides a qtcpsocket class that can instantiate a client directly and can be indexed in Help as follows:

The Qtcpsocket class provides a TCP socket. More ...
Header      #include <QTcpSocket> 
qmake       QT = Network
Inherits:   qabstractsocket
Inherited by:   Qsslsocket
From here, we can see that you have to add QT + + network to the. Pro file before you can do network programming, otherwise you will not be able to access the <QTcpSocket> header file.

client Read and write relatively simple, we look at the dock file:
#ifndef mytcpclient_h
#define MYTCPCLIENT_H

#include <QMainWindow>
#include <QTcpSocket>
#include <QHostAddress>
#include <QMessageBox>
namespace Ui {
class mytcpclient;
}

Class Mytcpclient:public Qmainwindow
{
    q_object public

:
    explicit mytcpclient (Qwidget *parent = 0) ;
    ~mytcpclient ();

Private:
    ui::mytcpclient *ui;
    Qtcpsocket *tcpclient;

Private slots:
    //client slot function
    void ReadData ();
    void Readerror (qabstractsocket::socketerror);

    void on_btnconnect_clicked ();
    void on_btnsend_clicked ();
    void on_pushbutton_clicked ();

#endif//Mytcpclient_h
In the window class, we define a private member Qtcpsoket *tcpclient.

1) Initialization of Qtcpsocket
In the constructor, we need to instantiate it first and connect the signal to the slot function:

    Initialize TCP client
    tcpclient = new Qtcpsocket (this);   Instantiation of TcpClient
    Tcpclient->abort ();                 Cancel the original connection connect
    (TcpClient, SIGNAL (Readyread ()), this, SLOT (ReadData ()));
    Connect (tcpclient, SIGNAL (Error (qabstractsocket::socketerror)), \ This
            , SLOT readerror (qabstractsocket:: SocketError)));

2 Establish a connection and disconnect

    Tcpclient->connecttohost (Ui->edtip->text (), Ui->edtport->text (). ToInt ());
    if (tcpclient->waitforconnected (1000))  //Connection succeeds then enters if{}
    {
        ui->btnconnect->settext ("Disconnected");
        Ui->btnsend->setenabled (true);
    
 a) A function that establishes a TCP connection: void Connecttohost (const qhostaddress &address, quint16 port, OpenMode openmode = ReadWrite) is a public function inherited from Qabstractsocket, and it is also a virtual function.
The function is: attempts to make a connection to address on port port. b The function that waits for the TCP connection to succeed: bool waitforconnected (int msecs = 30000) is also a public function inherited from Qabstractsocket, and it is also a virtual function Function: Waits until the socket is connected, up to msecs milliseconds. If the connection has been established, this function returns true; Otherwise it returns false.

In the case where it is returns FALSE, you can call error () to determine the cause of the error. In the above code, EDTIP, Edtport is the two lineeditor on the UI to fill in the server IP and port number.
Btnconnect is the "Connect/Disconnect" button, Btnsend is the button to send data to the server, only after the connection is established, it setenabled. 
 Tcpclient->disconnectfromhost (); if (tcpclient->state () = = qabstractsocket::unconnectedstate \ | | tcpclient->waitfordisconnected (1000
            )//disconnected, enter if{} {ui->btnconnect->settext ("connection");
        Ui->btnsend->setenabled (FALSE); }
A a function to disconnect a TCP connection: void Disconnectfromhost () is a public function inherited from Qabstractsocket, and it is also a virtual function. Function: Attempts to close the socket. If there is pending data waiting to being written, Qabstractsocket'll enter closingstate and wait until all data has been W Ritten. Eventually, it'll enter unconnectedstate and emit the disconnected () signal.
b Wait for the TCP disconnect function: bool waitfordisconnected (int msecs = 30000) is also a public function inherited from Qabstractsocket, and it is also a virtual function Function: Waits until the socket has disconnected, up to msecs milliseconds. If the connection has been disconnected, this function returns true; Otherwise it returns false. In the case where it is returns FALSE, you can call error () to determine the cause of the error.

3 Read the data that the server sent over
Readyread () is a signal that Qtcpsocket inherits from the parent class Qiodevice: This signal is emitted once the time new data are every for available He device's ' s current read channel.
Readyread () corresponds to the slot function:

void Mytcpclient::readdata ()
{
    Qbytearray buffer = Tcpclient->readall ();
    if (!buffer.isempty ())
    {
        ui->edtrecv->append (buffer);
    }
}
ReadAll () is a public function inherited from Qiodevice, which can be read directly from the server by Qtcpsocket. I'm here to display the data on the TextEditor control (UI>EDTRECV). This completes the read operation.
error (QABSTRACTSOCKET::SOCKETERROR) is a signal inherited from Qabstractsocket, this signal was emitted after an error occurred. The SocketError parameter describes the type of error that occurred. The slot function that is connected to is defined as:
void Mytcpclient::readerror (Qabstractsocket::socketerror)
{
    tcpclient->disconnectfromhost ();
    Ui->btnconnect->settext (TR ("Connection"));
    Qmessagebox MsgBox;
    Msgbox.settext (TR ("Failed to connect server because%1"). Arg (tcpclient->errorstring ());
Xec ();
}
The function is: When the error occurs, first disconnect the TCP connection, and then use Qmessagebox hint errorstring, that is the reason for the error.

4 sending data to the server

    QString data = Ui->edtsend->toplaintext ();
    if (Data!= "")
    {
        tcpclient->write (data.tolatin1 ()); Qt5 to go except. toascii ()
    }
Define a qstring variable, get the Send data from TextEditor (Edtsend), write () is a public function that Qtcpsocket inherits from Qiodevice, and direct calls can send data to the server. Here is to note: Toascii () to the QT5 is not, here to write ToLatin1 ().

So far, through 4 steps, we have completed the TCP client program development, source download address: Client qt program source code

Two: Server-side programming
Server segment programming is cumbersome compared to clients, because for clients, only one server can be connected. And for the server, it is for multiple connections, how to coordinate the processing of multiple client connections is particularly important.
The problems encountered in programming and the methods to solve them
Problems encountered: Each newly added client, the server assigned to it after a socketdescriptor, will be emit newconnection () signal, but the allocated socketdecriptor did not pass newconnection () Signal delivery, so the user does not get this client ID socketdescriptor. Similarly, each time the server receives a new message, the client emit the Readready () signal, but the readready () signal does not pass socketdescriptor, so that the server side even receives the message, I don't know which client the message was sent from.

Way to solve:
1. Get soketdescriptor by overriding [virtual protected] void Qtcpserver::incomingconnection (Qintptr socketdescriptor). The custom TcpClient class inherits the Qtcpsocket and the obtained soketdescriptor as a class member. The advantage of this method is that it can obtain soketdescriptor and high flexibility. The disadvantage is that you need to override functions, custom classes.
2. In the slot function corresponding to the newconnection () signal, obtain the newly connected client through the Qtcpsocket *qtcpserver::nextpendingconnection () function: Returns the next pending Connection as a connected Qtcpsocket object. Although Soketdescriptor is still not available, the IP and port number of the client can be obtained through the peeraddress () and Peerport () member functions of the Qtcpsocket class, as well as unique identities. Benefits: Code is concise without rewriting functions and custom classes. Disadvantage: Unable to obtain socketdecriptor, flexibility is poor.

This article describes the second method:

QT provides a qtcpserver class that can instantiate a client directly and can be indexed in Help as follows:

The Qtcpserver class provides a tcp-based server. More ...
Header:     #include <QTcpServer> 
qmake:      QT = Network
Inherits:       QObject
From here, we can see that you have to add QT + + network to the. Pro file before you can do network programming, otherwise you will not be able to access the <QTcpServer> header file.

Let's take a look at the dock file:
#ifndef mytcpserver_h
#define MYTCPSERVER_H

#include <QMainWindow>
#include <QTcpServer>
#include <QTcpSocket>
#include <QNetworkInterface>
#include <QMessageBox>
Namespace Ui {
class mytcpserver;
}

Class Mytcpserver:public Qmainwindow
{
    q_object public

:
    explicit Mytcpserver (Qwidget *parent = 0 );
    ~mytcpserver ();

Private:
    ui::mytcpserver *ui;
    Qtcpserver *tcpserver;
    Qlist<qtcpsocket*> TcpClient;
    Qtcpsocket *currentclient;

Private slots:
    void Newconnectionslot ();
    void Disconnectedslot ();
    void ReadData ();

    void on_btnconnect_clicked ();
    void on_btnsend_clicked ();
    void on_btnclear_clicked ();

#endif//Mytcpserver_h
It is worth noting that the server-side variable qtcpserver *tcpserver and client variable qlist<qtcpsocket*> tcpclient need to be defined at the same time as the service side is written. Tcpsocket Qlist stores all clients that are connected to the server. Since Qtcpserver is not a subclass of Qiodevice, there is no member function in the Qtcpserver for read and write operations, and the operation of reading and writing data is entirely up to qtcpsocket processing.

1) Initialization of Qtcpserver

    TCPServer = new Qtcpserver (this);
    Ui->edtip->settext (Qnetworkinterface (). Alladdresses (). at (1). ToString ());   Gets the local IP
    ui->btnconnect->setenabled (true);
    Ui->btnsend->setenabled (false);

    Connect (TCPServer, SIGNAL (Newconnection ()), this, SLOT (Newconnectionslot ()));
Get to the native IP display on lineeditor (Edtip) by Qnetworkinterface (). Alladdresses (). at (1). Described below:
[static] qlist<qhostaddress> qnetworkinterface::alladdresses () This
convenience function Returns all IP addresses found on the host machine. It is equivalent to calling AddressEntries () on "All" objects returned by Allinterfaces () to obtain lists of Qhostaddres s objects then calling Qhostaddress::ip () on every of these.:

newconncetion () signal triggers whenever a new client connects to the server, Newconnectionslot ( ) is the user's slot function, defined as follows:
void Mytcpserver::newconnectionslot ()
{
    currentclient = tcpserver->nextpendingconnection ();
    Tcpclient.append (currentclient);
    Ui->cbxconnection->additem (tr ("%1:%2"). Arg (Currentclient->peeraddress (). toString (). Split (":: FFFF:") [1 ]) \
                                          . Arg (Currentclient->peerport ());
    Connect (currentclient, SIGNAL (Readyread ()), this, SLOT (ReadData ()));
    Connect (currentclient, SIGNAL (Disconnected ()), this, SLOT (Disconnectedslot ()));
Obtain the client information that is connected via Nextpendingconnection (), peeraddress and Peerport are displayed on ComboBox (Cbxconnection), and the client's Readyread () The signal is connected to the server-side custom read data slot function ReadData (). Connect the client's disconnected () signal to the server-side custom slot function Disconnectedslot ().

2) Listening port and canceling listening

     bool OK = Tcpserver->listen (Qhostaddress::any, Ui->edtport->text (). ToInt ());
     if (OK)
     {
         Ui->btnconnect->settext ("Disconnected");
         Ui->btnsend->setenabled (true);
     
A function of the listening port: bool Qtcpserver::listen (const qhostaddress &*address* = Qhostaddress::any, quint16 *port* = 0), The function is: tells the server to listen for incoming connections on address *address* and Port *port*. If Port is 0, a port is chosen automatically. If is Qhostaddress::any, the server would listen on all network interfaces.
Returns true on success; otherwise returns false.
     for (int i=0; i<tcpclient.length (); i++)//Disconnect all connections
     {
         tcpclient[i]->disconnectfromhost ();
         bool OK = tcpclient[i]->waitfordisconnected (1000);
         if (!ok)
         {
             //handling exception
         }
         tcpclient.removeat (i);  Remove from the saved client list
     }
     tcpserver->close ();     No more ports listening
b The function to disconnect the client from the server: Disconnectfromhost () and waitfordisconnected () are described above. After disconnecting, remove the connection from the Qlist tcpclient. Server cancels the Listening function: Tcpserver->close ().
    Because the disconnected signal does not provide socketdescriptor, it is necessary to traverse the search for
    (int i=0; i<tcpclient.length (); i++)
    {
        if ( Tcpclient[i]->state () = = Qabstractsocket::unconnectedstate)
        {
            //delete client information stored in Combox
            ui-> Cbxconnection->removeitem (Ui->cbxconnection->findtext (tr ("%1:%2") \
                                  . Arg (tcpclient[i]-> Peeraddress (). toString (). Split (":: FFFF:") [1]) (
                                  . Arg (Tcpclient[i]->peerport ())));
            Deletes the client information stored in the TcpClient list
             tcpclient[i]->destroyed ();
             Tcpclient.removeat (i);
        }
    }
c If a client disconnects its connection to the server, the disconnected () signal is triggered, but no parameters are passed. So the user needs to traverse the TcpClient list to query each TcpClient state (), and if it is not connected (unconnectedstate), delete the client in Combox and delete the client in the TcpClient list. and destroy ().

3 Read the data that the client sent over

//client data readable signal, corresponding read data slot function void Mytcpserver::readdata () {//Because the readyread signal does not provide SOC Ketdecriptor, so you need to traverse all client for (int i=0; i<tcpclient.length (); i++) {Qbytearray buffer = TcpC
            Lient[i]->readall ();

            if (Buffer.isempty ()) continue;
            Static QString Ip_port, Ip_port_pre;
                                         Ip_port = TR ("[%1:%2]:"). Arg (Tcpclient[i]->peeraddress (). toString (). Split (":: FFFF:") [1]) \

            . Arg (Tcpclient[i]->peerport ()); 

            If the address of this message is different from the last, you need to display the client address of this message if (Ip_port!= ip_port_pre) ui->edtrecv->append (Ip_port);

            Ui->edtrecv->append (buffer);
        Update Ip_port ip_port_pre = Ip_port; }
    }
It should be noted here that although the TcpClient produces the readready () signal, but the readready () signal does not pass any parameters, when facing the multiple-connection client, TCPServer does not know which tcpclient is the data source, So it's going to traverse the TcpClient list to read the data (which is a bit time-consuming, and this workaround 1 doesn't have to be this way).
read operation by tcpclient variable processing: tcpclient[i]->readall ();

4 sending data to the client

    All Connections
    if (ui->cbxconnection->currentindex () = = 0)
    {for
        (int i=0; i<tcpclient.length (); i++)
            Tcpclient[i]->write (Data.tolatin1 ());//qt5 removed. Toascii ()
    }
A The data is sent to all clients that are currently connected, and can be traversed.
    Specifies
    the connection QString ClientIP = Ui->cbxconnection->currenttext (). Split (":") [0];
    int clientport = Ui->cbxconnection->currenttext (). Split (":") [1].toint ();
    for (int i=0; i<tcpclient.length (); i++)
    {
        if (tcpclient[i]->peeraddress (). toString (). Split (":: FFFF:" ) [1]==clientip\
                        && tcpclient[i]->peerport () ==clientport)
        {
            Tcpclient[i]->write ( Data.tolatin1 ());
            Return Ip:port unique, no need to continue retrieving
        }
    }
(b) in ComboBox (cbxconnction) Select the specified connection to send data: match the client through peeraddress and Peerport and send. Write operations are handled by TcpClient variables: Tcpclient[i]->write ().

So far, through 4 steps, we have completed the TCP server program development, source download address: server-side QT program source code

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.