【问题标题】:UDP Connections on same computer . 1 Server . Multiple Clients同一台计算机上的 UDP 连接。 1 服务器。多个客户
【发布时间】:2013-08-19 08:07:55
【问题描述】:

正在使用 Qt 框架 ..,需要针对给定的需求获得解决方案

我已将一台服务器和 2 个客户端作为我的 PC: IP1、IP2、IP3 是端口。

我的服务器正在侦听 IP1,端口号 9999 我想将数据(数据报)发送到服务器,然后服务器需要回复我的客户端。 所以我可以知道客户端IP地址和客户端端口号。

客户端的 IP 地址和端口如何知道服务器?这是将响应返回给客户端所必需的。

注意:我在同一台 PC 上运行 server、client1 和 client2。

【问题讨论】:

  • (IP 地址)是分配给每个设备的数字标签..
  • 那么如何做我想做的事?我想在 1 台 PC 上有很多客户端和服务器。我应该给他们每个人不同的端口号吗?但我想给他们每个人一个不同的 IP 地址。这可能吗?
  • 客户端从不监听IP,客户端连接到服务器,因为客户端主要需要服务器的IP和监听端口。
  • 标记...正如我所说:“一些带有网络别名的操作系统级魔法”;-)
  • @ashif 我已经使用 TCP 套接字完成了 TCP 部分,但我使用的是 UDP,而 UDP 是无连接的。

标签: c++ qt sockets udp


【解决方案1】:
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.

这是使用 Qt 的 QUDPSocket,1 个 UDP Sever 的解决方案,在同一本地主机上有多个客户端,测试它工作正常。必要时对代码进行注释

有两个控制台应用程序(UDPServer 和 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

UDP服务器代码

> 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 );
}

UDP客户端代码

> 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;    
}

【讨论】:

  • @Sahil Manchanda,我花了几个小时寻找解决方案。请检查答案
  • 你使用 qt 框架是因为 OP 提到了 qt 还是这种方法比使用系统调用 socket()、bind() 创建套接字的标准方法有什么优势?
  • @restart.localhost.localdomain : 提到了 OP 并且用 Qt 更新了标签:),主要是 Qt 框架支持的可移植性是很大的优势,系统调用可以利用轻量级进程正确吗?你能建议如何我在 windows env 上运行你的源代码(已回答),cygwin 是合适的解决方案吗?
  • 是的,从字面上看,当不需要引入 gui 时,我看不到使用 Qt 的理由。我的代码也可以在 Windows 上运行,只需移植一个标头并添加它的 winsock 库
  • 我尝试移植到windows,它需要努力(需要识别标题)
【解决方案2】:

不确定 Qt 框架,但使用普通的套接字命令你 bind 到特定的 IP 和端口。

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) );

【讨论】:

  • 对于 TCP 没有问题,但对于 UDP,我希望服务器知道我的 IP 地址,以便他在同一个地址上响应我。但是当我运行时,所有客户端和服务器都获得相同的 IP 地址。我能以某种方式改变它吗
  • 你在recvfrom得到客户的地址
  • 但如果我有 1 台计算机,则服务器和客户端的 IP 地址相同。那么我如何区分 2
  • 在问题中,您说服务器是 IP1,两个客户端是 IP2 和 IP3……所有不同的地址。如果您只想拥有一个地址,则可以通过使用不同的端口来区分它们。
【解决方案3】:

您将让服务器在您的本地主机 127.0.0.1 上进行侦听,然后每个客户端将在服务器侦听的端口上连接到本地主机(127.0.0.1)。在这里,我将展示它的外观。

服务器代码可能如下所示:

#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;
}

您可以尝试使用终端中的 -vu 选项通过 nc 监听服务器:

me@computer:~# nc -vu localhost 9999

并且应该像这样从服务器获取输出:

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

客户端代码:

#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;
}

同样,当你被解雇时,你应该从服务器获得类似这样的输出:

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

【讨论】:

  • 这都是基于 TCP 的...问题是关于 UDP 的
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-11-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-03-27
  • 1970-01-01
相关资源
最近更新 更多