Set a local port to a QTcpSocket



  • Hello,
    I see on the thread "forcing local port number from TcpSocket?
    ":http://www.qtcentre.org/threads/11082-forcing-local-port-number-from-TcpSocket
    that it is possible to force a local port by a local binding of the QTcpSocket descriptor and then set the socket descriptor on the QTcpSocket afterwards using the setSocketDescriptor() function

    I try it but no success ... Could you help me

    @ QTcpSocket s_client;

    // get the handle of the QTcpSocket
    int handle_socket = s_client.socketDescriptor();

    // bind to local interface
    sockaddr_in service;
    service.sin_family = AF_INET;
    service.sin_port = htons(2000);
    service.sin_addr.s_addr = inet_addr("15.0.0.1");
    if(::bind(handle_socket, (SOCKADDR*) &service, sizeof(service)) == SOCKET_ERROR)
    {
    int e = WSAGetLastError();
    qDebug() << "Socket error = " << e;
    closesocket(handle_socket);
    return;
    }
    else
    {
    // set the socket descriptor to QTcpSocket
    s_client.setSocketDescriptor(handle_socket);

    // connect to server host
    s_client.connectToHost("15.0.0.2", 3000);
    }@



  • Hi,
    what means "I try it but no success"?

    Have you an error on bind? What is the error?

    Have you tried to use QAbstractSocket::bind () ??



  • I say "no success" because the bind returns SOCKET_ERROR
    The error is :
    "WSAENOTSOCK 10038 Socket operation on nonsocket. An operation was attempted on something that is not a socket. Either the socket handle parameter did not reference a valid socket, or for select, a member of an fd_set was not valid"

    I do not try QAbstractSocket::bind because it does not exist on Qt 4.6.2.
    I see this on Qt Project documentation
    "Qt 5 also provides better ways to handle TCP socket-based connections and SSL certificates. This means developers can now:
    bind a TCP socket to an IP address before connecting
    Here the code with WSAStartup to get winsock erreor
    "

    So, if I cannot run this code I will intall QT 5

    @QTcpSocket s_client;
    WSADATA wsaData;
    if( WSAStartup( MAKEWORD( 2, 2 ), &wsaData ) == 0)
    {
    // get the handle of the QTcpSocket
    int handle_socket = s_client.socketDescriptor();

    // bind to local interface
    sockaddr_in service;
    service.sin_family = AF_INET;
    service.sin_port = htons(2000);
    service.sin_addr.s_addr = inet_addr("15.0.0.1");
    if(::bind(handle_socket, (SOCKADDR*) &service, sizeof(service)) == SOCKET_ERROR)
    {
    int e = WSAGetLastError();
    qDebug() << "Socket error = " << e;
    closesocket(handle_socket);
    return;
    }
    else
    {
    // set the socket descriptor to QTcpSocket
    s_client.setSocketDescriptor(handle_socket);

    // connect to server host
    s_client.connectToHost("15.0.0.2", 3000);
    }
    }
    }@



  • IMHO the error it this:

    @
    // get the handle of the QTcpSocket
    int handle_socket = s_client.socketDescriptor();
    @

    if you only create a QTcpSocket, the socketDescriptor is invalid, you should do something like

    @
    int handle_socket = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    @



  • Buonasera,
    The ::bind and the s_client.setSocketDescriptor are now ok, but the connection is not established.
    I have the following message:
    QAbstractSocket::connectToHost() called when already looking up or connecting/connected to "15.0.0.2"



  • Hi,

    please, could you post all your working code?



  • Hello,

    with startWithoutBindLocal() function the connection is established
    but with startWithBindLocal() the connection is not etablished.
    I want to realize a connection with startWithBindLocal() because I would like to binding with host port and address.

    Below the working code

    the client side

    client_tcp.h
    @#ifndef CLIENT_TCP_H
    #define CLIENT_TCP_H

    #include <QtGui/QMainWindow>
    #include "ui_client_tcp.h"
    #include <QTcpSocket>
    #include <QTimer>
    #include <Winsock2.h>

    class cclient_tcp : public QMainWindow
    {
    Q_OBJECT

    public:
    cclient_tcp(QWidget *parent = 0, Qt::WFlags flags = 0);
    ~cclient_tcp();

    public slots:
    void estConnecte();
    void estDeconnecte();
    void onTimer();

    private:
    bool startWithBindLocal();
    bool startWithoutBindLocal();

    void stop();
    void writeString(QString texte);

    private:
    Ui::cclient_tcpClass ui;

    QTcpSocket* m_pClient;
    bool m_connected;
    QTimer* m_pTimer;
    };

    #endif // CLIENT_TCP_H
    @
    client_tcp.cpp
    @#include "client_tcp.h"

    cclient_tcp::cclient_tcp(QWidget *parent, Qt::WFlags flags)
    : QMainWindow(parent, flags)
    {
    ui.setupUi(this);
    m_connected = false;
    m_pClient = NULL;
    //startWithoutBindLocal();
    startWithBindLocal();
    }

    cclient_tcp::~cclient_tcp()
    {
    stop();
    }

    bool cclient_tcp::startWithBindLocal()
    /*
    start the tcp connection with a socket local bind
    */
    {
    bool ok=false;
    WSADATA wsaData;
    if( WSAStartup( MAKEWORD( 2, 2 ), &wsaData ) == 0)
    {
    int handle_socket = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

    // bind to local interface
    sockaddr_in service;
    service.sin_family = AF_INET;
    service.sin_port = htons(2000);
    service.sin_addr.s_addr = inet_addr("15.0.0.1");
    if(::bind(handle_socket, (SOCKADDR*) &service, sizeof(service)) == SOCKET_ERROR)
    {
    int e = WSAGetLastError();
    qDebug() << "Socket error = " << e;
    closesocket(handle_socket);
    }
    else
    {
    m_pClient = new QTcpSocket();
    if(m_pClient != NULL)
    {
    // set the socket descriptor to QTcpSocket
    bool ok = m_pClient->setSocketDescriptor(handle_socket);

    connect(m_pClient, SIGNAL(connected()), this, SLOT(estConnecte()));
    connect(m_pClient, SIGNAL(disconnected()), this, SLOT(estDeconnecte()));
    
    m_pTimer = new QTimer(this);
       connect(m_pTimer, SIGNAL(timeout()), this, SLOT(onTimer()));
    m_pTimer->start(1000);
    
    // connect to server host
    m_pClient->connectToHost("15.0.0.2", 3000);
    ok = true;
    

    }
    }
    }
    return ok;
    }

    bool cclient_tcp::startWithoutBindLocal()
    {
    bool ok=false;
    m_pClient = new QTcpSocket();
    if(m_pClient != NULL)
    {
    connect(m_pClient, SIGNAL(connected()), this, SLOT(estConnecte()));
    connect(m_pClient, SIGNAL(disconnected()), this, SLOT(estDeconnecte()));

    m_pTimer = new QTimer(this);
    connect(m_pTimer, SIGNAL(timeout()), this, SLOT(onTimer()));
    m_pTimer->start(1000);

    // connect to server host
    m_pClient->connectToHost("15.0.0.2", 3000);
    ok = true;
    }
    return ok;
    }

    void cclient_tcp::stop()
    {
    if(m_pClient != NULL)
    {
    m_pClient->disconnectFromHost();
    delete m_pClient;
    }
    }

    void cclient_tcp::estConnecte()
    {
    m_connected = true;
    qDebug("client connected");
    }

    void cclient_tcp::estDeconnecte()
    {
    qDebug("client deconnected");
    }

    void cclient_tcp::writeString(QString texte)
    {
    if(m_connected)
    {
    m_pClient->write(texte.toAscii(), texte.length());
    }
    }

    void cclient_tcp::onTimer()
    {
    writeString("test");
    }
    @

    ========================================================
    the server side
    server_tcp.h
    @#ifndef SERVER_TCP_H
    #define SERVER_TCP_H

    #include <QtGui/QMainWindow>
    #include "ui_server_tcp.h"
    #include <QTcpServer>
    #include <QTcpSocket>

    class cserver_tcp : public QMainWindow
    {
    Q_OBJECT

    public:
    cserver_tcp(QWidget *parent = 0, Qt::WFlags flags = 0);
    ~cserver_tcp();

    public slots:
    void acceptConnection();
    void startRead();

    private:
    Ui::cserver_tcpClass ui;
    QTcpServer m_server;
    QTcpSocket* m_pClient;
    };

    #endif // SERVER_TCP_H
    @
    server_tcp.cpp
    @#include "server_tcp.h"

    cserver_tcp::cserver_tcp(QWidget *parent, Qt::WFlags flags)
    : QMainWindow(parent, flags)
    {
    ui.setupUi(this);

    connect(&m_server, SIGNAL(newConnection()), this, SLOT(acceptConnection()));

    bool enListen = m_server.listen(QHostAddress("15.0.0.2"), 3000);
    qDebug() << "listen on 15.0.0.2/3000 = " <<enListen;
    }

    cserver_tcp::~cserver_tcp()
    {

    }

    void cserver_tcp::acceptConnection()
    {
    m_pClient = m_server.nextPendingConnection();

    connect(m_pClient, SIGNAL(readyRead()), this, SLOT(startRead()));
    }

    void cserver_tcp::startRead()
    {
    char buffer[1024] = {0};
    m_pClient->read(buffer, m_pClient->bytesAvailable());
    qDebug(buffer);
    }@



  • Hi,

    as shown "here":http://qt-project.org/doc/qt-4.8/qabstractsocket.html#setSocketDescriptor when you call setSocketDescriptor the socket will be opened by default in ConnectedState you should use QAbstractSocket::UnconnectedState



  • Hi,
    Thanks for your response, but the bind is not Ok because the connection is established on a local random port. It is not 2000.
    @service.sin_port = htons(2000);
    @



  • Hi,

    I think you should establish connection using Winsock API and only after you use setSocketDescriptor()



  • Hi,
    The connection is etablished now with the good local port, but if i launch a second time the application I have the error 10048 (WSAEADDRINUSE) after the ::connect function. I have to wait a timeout before reuse without error.
    Below the code:
    @bool cclient_tcp::startWithBindLocal()
    /*
    start the tcp connection with a socket local bind
    */
    {
    WSADATA wsaData;
    if(WSAStartup( MAKEWORD( 2, 2 ), &wsaData ) == 0)
    {
    m_handle_socket = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

    // bind to local interface
    sockaddr_in service;
    service.sin_family = AF_INET;
    service.sin_port = htons(2000);
    service.sin_addr.s_addr = inet_addr("15.0.0.1");
    if(::bind(m_handle_socket, (SOCKADDR*) &service, sizeof(service)) == SOCKET_ERROR)
    {
    int e = WSAGetLastError();
    qDebug() << "Socket bind error = " << e;
    // closesocket(m_handle_socket);
    WSACleanup();
    return false;
    }
    else
    {
    m_pClient = new QTcpSocket();
    if(m_pClient != NULL)
    {
    connect(m_pClient, SIGNAL(connected()), this, SLOT(estConnecte()));
    connect(m_pClient, SIGNAL(disconnected()), this, SLOT(estDeconnecte()));
    connect(m_pClient, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(erreurSocket()));
    connect(m_pClient, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(socketStateChanged(QAbstractSocket::SocketState)));

    m_pTimer = new QTimer(this);
    connect(m_pTimer, SIGNAL(timeout()), this, SLOT(onTimer()));
    m_pTimer->start(1000);
    
    // connect to server host
    sockaddr_in server_sock;
    server_sock.sin_family = AF_INET;
    server_sock.sin_port = htons(3000);
    server_sock.sin_addr.s_addr = inet_addr("15.0.0.2");
    
    // connect to the server  
    if(::connect(m_handle_socket, (SOCKADDR*) &server_sock, sizeof(server_sock)) == SOCKET_ERROR)
    {
     int e = WSAGetLastError();
     qDebug() << "Socket connect error = " << e;
     //closesocket(m_handle_socket);
     WSACleanup();
     return false;
    }
    
    // set the socket descriptor to QTcpSocket
    bool ok_desc = m_pClient->setSocketDescriptor(m_handle_socket/*, QAbstractSocket::UnconnectedState*/);
    

    // m_pClient->connectToHost("15.0.0.2", 3000);
    return true;
    }
    }
    }
    return false;
    }
    @



  • Hi,

    if you don't close a TCP socket, the address will be released only after some minutes. If you close correctly the socket, the problem will disappear.



  • Hello,
    The stop function in the destructor should close the socket
    because there is no error in this stop function.

    There is only the closing problem at ::connect function in the startWithBindLocal() .
    There is no closing problem with startWithoutBindLocal();

    Below the source code
    tcp_client.h
    @#ifndef CLIENT_TCP_H
    #define CLIENT_TCP_H

    #include <QtGui/QMainWindow>
    #include "ui_client_tcp.h"
    #include <QTcpSocket>
    #include <QTimer>
    #include <Winsock2.h>

    class cclient_tcp : public QMainWindow
    {
    Q_OBJECT

    public:
    cclient_tcp(QWidget *parent = 0, Qt::WFlags flags = 0);
    ~cclient_tcp();

    public slots:
    void estConnecte();
    void estDeconnecte();
    void erreurSocket();
    void socketStateChanged(QAbstractSocket::SocketState state);
    void onTimer();

    private:
    bool startWithBindLocal();
    bool startWithoutBindLocal();

    void stop();
    void writeString(QString texte);

    private:
    Ui::cclient_tcpClass ui;

    QTcpSocket* m_pClient;
    bool m_connected;
    QTimer* m_pTimer;
    SOCKET m_handle_socket;
    };

    #endif // CLIENT_TCP_H

    tcp_client.cpp
    @#include "client_tcp.h"

    cclient_tcp::cclient_tcp(QWidget *parent, Qt::WFlags flags)
    : QMainWindow(parent, flags)
    {
    ui.setupUi(this);
    m_connected = false;
    m_pClient = NULL;
    //startWithoutBindLocal();
    startWithBindLocal();
    }

    cclient_tcp::~cclient_tcp()
    {
    stop();
    }

    bool cclient_tcp::startWithBindLocal()
    /*
    start the tcp connection with a socket local bind
    */
    {
    WSADATA wsaData;
    if(WSAStartup( MAKEWORD( 2, 2 ), &wsaData ) == 0)
    {
    m_handle_socket = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

    // bind to local interface
    sockaddr_in service;
    service.sin_family = AF_INET;
    service.sin_port = htons(2000);
    service.sin_addr.s_addr = inet_addr("15.0.0.1");
    if(::bind(m_handle_socket, (SOCKADDR*) &service, sizeof(service)) == SOCKET_ERROR)
    {
    int e = WSAGetLastError();
    qDebug() << "Socket bind error = " << e;
    // closesocket(m_handle_socket);
    WSACleanup();
    return false;
    }
    else
    {
    m_pClient = new QTcpSocket();
    if(m_pClient != NULL)
    {
    connect(m_pClient, SIGNAL(connected()), this, SLOT(estConnecte()));
    connect(m_pClient, SIGNAL(disconnected()), this, SLOT(estDeconnecte()));
    connect(m_pClient, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(erreurSocket()));
    connect(m_pClient, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(socketStateChanged(QAbstractSocket::SocketState)));

    m_pTimer = new QTimer(this);
    connect(m_pTimer, SIGNAL(timeout()), this, SLOT(onTimer()));
    m_pTimer->start(1000);
    
    // connect to server host
    sockaddr_in server_sock;
    server_sock.sin_family = AF_INET;
    server_sock.sin_port = htons(3000);
    server_sock.sin_addr.s_addr = inet_addr("15.0.0.2");
    
    // connect to the server  
    if(::connect(m_handle_socket, (SOCKADDR*) &server_sock, sizeof(server_sock)) == SOCKET_ERROR)
    {
     int e = WSAGetLastError();
     qDebug() << "Socket connect error = " << e;
     //closesocket(m_handle_socket);
     WSACleanup();
     return false;
    }
    
    // set the socket descriptor to QTcpSocket
    bool ok_desc = m_pClient->setSocketDescriptor(m_handle_socket/*, QAbstractSocket::UnconnectedState*/);
    

    // m_pClient->connectToHost("15.0.0.2", 3000);
    return true;
    }
    }
    }
    return false;
    }

    bool cclient_tcp::startWithoutBindLocal()
    {
    bool ok=false;
    m_pClient = new QTcpSocket();
    if(m_pClient != NULL)
    {
    connect(m_pClient, SIGNAL(connected()), this, SLOT(estConnecte()));
    connect(m_pClient, SIGNAL(disconnected()), this, SLOT(estDeconnecte()));

    m_pTimer = new QTimer(this);
    connect(m_pTimer, SIGNAL(timeout()), this, SLOT(onTimer()));
    m_pTimer->start(1000);

    // connect to server host
    m_pClient->connectToHost("15.0.0.2", 3000);
    ok = true;
    }
    return ok;
    }

    void cclient_tcp::stop()
    {
    if(::closesocket(m_handle_socket) == SOCKET_ERROR)
    {
    int e = WSAGetLastError();
    qDebug() << "Socket close error = " << e;
    }

    if(WSACleanup() == SOCKET_ERROR)
    {
    int e = WSAGetLastError();
    qDebug() << "Socket WSACleanup error = " << e;
    }
    if(m_pClient != NULL)
    {
    m_pClient->disconnectFromHost();
    delete m_pClient;
    }
    }

    void cclient_tcp::estConnecte()
    {
    m_connected = true;
    qDebug("client connected");
    }

    void cclient_tcp::estDeconnecte()
    {
    qDebug("client deconnected");
    }

    void cclient_tcp::erreurSocket()
    {
    qDebug("client socket erreur");
    }

    void cclient_tcp::socketStateChanged(QAbstractSocket::SocketState state)
    {
    qDebug() << "client socket changed, state=" << state;
    if(state == QAbstractSocket::ConnectedState)
    {
    m_connected = true;
    }
    }

    void cclient_tcp::writeString(QString texte)
    {
    if(m_connected)
    {
    m_pClient->write(texte.toAscii(), texte.length());
    }
    }

    void cclient_tcp::onTimer()
    {
    writeString("test");
    }
    @



  • Hi,

    are you sure close works properly?

    However, you can also specify to reuse address in bind; this prevents to have problem when your application exit in no proper way (for example a crash)



  • Hi,
    I think that my application close works properly.
    The reuse address with setsockoptions does not give more results.

    The only way is to change the local port, each time the application reconnects, but I want to keep the same local port.

    The only way to set a local port and a reconnection without timeout is to generate my application with Qt 5, is not it ?


Log in to reply
 

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