3

Working on Qt Framework .., need to get a solution on given requiremets

I have made one server and 2 clients my PC: IP1, IP2, IP3 are ports.

My server is listening on IP1, port number 9999 I want to send data(datagram) to Server, then server need to respond back to my client. So I can know Client IP address and client port number.

How client IP address and port knows to the server ?, this is required to get the response back to the client.

Note: I am running, server, client1 and client2 on Same PC.

Ashif
  • 1,652
  • 14
  • 30
  • (IP address) is a numerical label assigned to each device.. – Ashif Aug 16 '13 at 20:15
  • so how to do what i want to ? i want many clients and server on 1 PC . shall i give each of them different port number which is possible ? but i want to give each of them a different IP Address . Is that possible ? – Sahil Manchanda Aug 16 '13 at 20:17
  • Client never listening on IP, client connect to the server, for that client mainly required server's ip and listening port. – Ashif Aug 16 '13 at 20:35
  • Do you really have one device with three different network cards? Or did you do some os level magic with network aliases? I am asking since your question is a bit hard to understand. In all cases there is no way to spoof your address on Qt level. – Greenflow Aug 16 '13 at 20:36
  • You don't have to have X network cards, you can have one NIC with multiple IPs on a network. – mark Aug 16 '13 at 20:38
  • @Sahil Manchanda Did you heared about TCP/IP/Socket Please go though link http://home.iitk.ac.in/~chebrolu/ee673-f06/sockets.pdf – Ashif Aug 16 '13 at 20:38
  • 1
    mark... as I said: "some os level magic with network aliases" ;-) – Greenflow Aug 16 '13 at 20:39
  • 1
    @ashif i have done the TCP part with TCP sockets, but im using UDP , and UDP is connectionless . – Sahil Manchanda Aug 16 '13 at 21:16
  • @SahilManchanda I think, you want server to identify about the client1 and client2. This is requoired to send respose back to client1 and client2. You are doing this on same PC( Same IP addreess). Solution is when you writeDatagram toserver( 9999 port), nservere knows IP address and port number of the client, then again server perform writeDatagram to client with IPaddress and port of the client. In your case IP address is same, but port number is playing the role to rout datagram to each client. Hope this makes sense... – Ashif Aug 17 '13 at 14:39

3 Answers3

4
How client IP address and port knows to the server ?, 
     Ans: When datagram is recieved( readyRead signal is emited),  you can use readDatagram API 
     socketServer.readDatagram(buffer.data(),buffer.size(),&sender,&port);
     sender = IPaddress of client
     por  = portNumber of client.

Here is the solution using Qt's QUDPSocket, 1 UDP Sever, with multiple client on same local host, tested it is working. commented the code, wherever necessary

There are two console application( UDPServer and UDPClient )

How to test
    1. Run UDPServer, it will listen on port 9999
    2. Run UDPClient(First instance )
    3. Run UDPClient(second instance )

Result:
    Please check below screenshot

enter image description here

UDPServer Code

> main.cpp

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    UDPServer server;
    return a.exec();
}

> UDPServer.h

  #ifndef UDPSERVER_H
    #define UDPSERVER_H
    #include <QObject>
    #include <QUdpSocket>

    class UDPServer : public QObject
    {
        Q_OBJECT
    public:
        explicit UDPServer(QObject *parent = 0);
        void WriteData( const QString& );

    public slots:
        void readReady();
    private:
        QUdpSocket socketServer;

    };
    #endif // UDPSERVER_H

> UDPServer.cpp

#include "UDPServer.h"
UDPServer::UDPServer(QObject *parent) :QObject(parent),socketServer(this)
{
    qDebug()<<"I am UDP server, listening on 9999";
    // Listen to 9999 port server
    socketServer.bind(QHostAddress::LocalHost,9999 );
    connect(&socketServer,SIGNAL(readyRead()),this,SLOT(readReady()));

}

void UDPServer::readReady()
{
    QByteArray buffer;
    buffer.resize(socketServer.pendingDatagramSize());
    QHostAddress sender;
    quint16 port;
    socketServer.readDatagram(buffer.data(),buffer.size(),&sender,&port);
    qDebug()<<"Datagram Recieved From";
    qDebug()<<"Client IP" << sender.toString();
    qDebug()<<"Client Port Number " << port;
    qDebug()<<"\n\n";

    // Write to the client,need to specify the client port number.
    QByteArray clientData;
    clientData.append( "data");
    socketServer.writeDatagram( clientData, QHostAddress::LocalHost, port );
}

UDPClient Code

> main.cpp

#include <QtCore/QCoreApplication>
#include "udpclient.h"

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    UDPClient client;
    client.WriteData("What is my IP");    
    return a.exec();
}

> udpclient.h

#ifndef UDPCLIENT_H
#define UDPCLIENT_H

#include <QObject>
#include <QUdpSocket>

class UDPClient : public QObject
{
    Q_OBJECT
public:
    explicit UDPClient(QObject *parent = 0);
    void WriteData( const QString& );
public slots:
    void readReady();

private:
    QUdpSocket clientSocket;

};

#endif // UDPCLIENT_H

> udpclient.cpp

#include "udpclient.h"


UDPClient::UDPClient(QObject *parent) :QObject(parent), clientSocket(this)
{    
    qDebug()<<"I am your client";
    connect(&clientSocket,SIGNAL(readyRead()),this,SLOT(readReady()));
}

void UDPClient::WriteData(const QString& data)
{
    QByteArray clientData;
    clientData.append( data);    
    // write to the port, listening by the server.
    qDebug()<<"Writing datagram to 9999 port";
    clientSocket.writeDatagram(clientData, QHostAddress::LocalHost, 9999 );  

}

void UDPClient::readReady()
{
    // got response from server, so clientSoclet port number can get.
    qDebug()<< "Reacieved response from server through my port(Client port No):" << clientSocket.localPort();  

    QByteArray buffer;    
    buffer.resize(clientSocket.pendingDatagramSize());        

    QHostAddress sender;    
    quint16 port;  
    clientSocket.readDatagram(buffer.data(),buffer.size(),&sender,&port);    
    // To read server IP
    qDebug()<< "Server IP Responded" << sender.toString();
    qDebug()<< "Server Port Number" << port;    
}
Ashif
  • 1,652
  • 14
  • 30
  • @Sahil Manchanda, I spent couple of hours to find solution. Please check the answer – Ashif Aug 17 '13 at 13:26
  • did you use qt framework just because OP mentioned qt or are there any advantages of this approach over standard way of creating sockets with syscalls socket(), bind() ? – 4pie0 Aug 17 '13 at 16:33
  • @restart.localhost.localdomain : OP mentioned and tag was updated with Qt:), Mainly Portability supported by Qt framework is big advantage, syscall can take advantages of lightweight process correct ?can you suggest how can i run your source code(answerd) on windows env, is cygwin is suitable solutionor that ? – Ashif Aug 17 '13 at 17:47
  • yes, literally when there is no need to introduce gui, I don't see a reason to use Qt. my code can be run on windows too, just port a headers and add its winsock lib – 4pie0 Aug 17 '13 at 17:54
  • I tried to port to windows, it requires effort( Need to identify headers ) – Ashif Aug 19 '13 at 17:27
  • @Sahil Manchanda hope this answer makes sense for your requirement. – Ashif Aug 19 '13 at 17:31
0

Not sure about Qt Framework, but using normal socket commands you bind to a particular IP and port.

handle = socket( AF_INET, SOCK_DGRAM, 0 );

// my local computer
struct sockaddr_in addr_loc;
memset( &addr_loc, 0, sizeof(addr_loc) );
addr_loc.sin_family = AF_INET;
addr_loc.sin_port = htons( localPort );
addr_loc.sin_addr.s_addr = htonl( localAddr );
bind( handle, (struct sockaddr*)&addr_loc, sizeof(addr_loc) );

// the remote location
struct sockaddr_in addr_rem;
memset( &addr_rem, 0, sizeof(addr_rem) );
addr_rem.sin_family = AF_INET;
addr_rem.sin_port = htons( remotePort );
addr_rem.sin_addr.s_addr = htonl( remoteAddr );
sendto( handle, packetData, packetLength, 0, (struct sockaddr *)&addr_rem, sizeof(addr_rem) );
mark
  • 5,269
  • 2
  • 21
  • 34
  • for TCP there is no problem , but for UDP , i want the server to know my IP address so that he responds to me on the same address . but when i run , all clients and server get same ip address . can i somehow change that – Sahil Manchanda Aug 16 '13 at 21:17
  • 1
    you get the client's address in the `recvfrom` – mark Aug 16 '13 at 21:18
  • 1
    but if i have 1 computer , the server and client are having same ip address . so how can i differentiate between 2 – Sahil Manchanda Aug 16 '13 at 21:33
  • 1
    In the question you said the server was IP1 and the two clients were IP2 and IP3... all different addresses. If you want to have only a single address, you can differentiate them by utilizing different ports. – mark Aug 16 '13 at 21:40
0

you will have server listening on your localhost, 127.0.0.1, and then each client will connect to localhost(127.0.0.1) on the port that server is listening on. Here I will show how it might looks.

server code might looks like this:

#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netdb.h>

int main() {
    struct addrinfo hints, *res;
    int sockfd;
    int byte_count;
    socklen_t fromlen;
    struct sockaddr_storage addr;
    char buf[512];
    char ipstr[INET6_ADDRSTRLEN];

    // get host info, make socket, bind it to port 9999
    memset(&hints, 0, sizeof hints);
    hints.ai_family = AF_UNSPEC; // use IPv4 or IPv6, whichever
    hints.ai_socktype = SOCK_DGRAM;
    hints.ai_flags = AI_PASSIVE;
    getaddrinfo(NULL, "9999", &hints, &res);
    sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
    bind(sockfd, res->ai_addr, res->ai_addrlen);

    // no need to accept(), just recvfrom():
    fromlen = sizeof addr;
    byte_count = recvfrom(sockfd, buf, sizeof buf, 0, (sockaddr*)&addr, &fromlen);

    printf("recv()'d %d bytes of data in buf\n", byte_count);
    printf("from IP address %s\n",
            inet_ntop(addr.ss_family,
            (const void*)(&((struct sockaddr_in *) &addr)->sin_addr), ipstr, sizeof ipstr));

    return 0;
}

you can try that server is listening via nc with -vu option in terminal:

me@computer:~# nc -vu localhost 9999

and should get output from server like this:

recv()'d 29 bytes of data in buf
from IP address 127.0.0.1

client code:

#define DEST_PORT 9999
#define DEST_IP "127.0.0.1"

int main(int argc, char** argv) {
    char *secret_message = "The Cheese is in The Toaster";

    int dgram_socket;
    struct sockaddr_in dest_addr;

    // now with UDP datagram sockets:
    // datagram sockets and recvfrom()
    dest_addr.sin_family = AF_INET;
    /* short, network byte order */
    dest_addr.sin_port = htons(DEST_PORT);
    dest_addr.sin_addr.s_addr = inet_addr(DEST_IP);

    /* zero the rest of the struct */
    memset(&(dest_addr.sin_zero), 0, 8);

    dgram_socket = socket(dest_addr.sin_family, SOCK_DGRAM, 0);


    // send secret message normally:
    sendto(dgram_socket, secret_message, strlen(secret_message) + 1, 0,
            (struct sockaddr*) &dest_addr, sizeof dest_addr);

    return 0;
}

again, when fired you should get output from server similar to this:

recv()'d 29 bytes of data in buf
from IP address 127.0.0.1
4pie0
  • 29,204
  • 9
  • 82
  • 118