【问题标题】:Server won't connect to more than one client?服务器不会连接到多个客户端?
【发布时间】:2011-08-22 21:51:06
【问题描述】:

问题是它只连接到一个客户端而不是两个。谁能帮我弄清楚为什么?

服务器:

#include <SFML/System.hpp>
#include <SFML/Network.hpp>
#include <iostream>

void sendInfo(void *UserData)
{
    sf::IPAddress* ip = static_cast<sf::IPAddress*>(UserData);
    // Print something...
    while(true){
        // Create the UDP socket
        sf::SocketUDP Socket;

        // Create bytes to send
        char Buffer[] = "sending info.";

        // Send data to "192.168.0.2" on port 4567
        if (Socket.Send(Buffer, sizeof(Buffer), *ip, 4444) != sf::Socket::Done)
        {
            // Error...
        }
    }
}

void receiveInfo(void *userData)
{
    // Print something...
    while(true){
        // Create the UDP socket
        sf::SocketUDP Socket;

        // Bind it (listen) to the port 4567
        if (!Socket.Bind(4444))
        {
            // Error...
        }

        char Buffer[128];
        std::size_t Received;
        sf::IPAddress Sender;
        unsigned short Port;
        if (Socket.Receive(Buffer, sizeof(Buffer), Received, Sender, Port) != sf::Socket::Done)
        {
            // Error...
        }

        // Show the address / port of the sender
        std::cout << Buffer << std::endl;

        Socket.Close();

    }
}

int main()
{
    sf::IPAddress client[2];
    int connected = 0;
    while(connected < 2){
        // Create the UDP socket
        sf::SocketUDP Socket;

        // Bind it (listen) to the port 4567
        if (!Socket.Bind(4444))
        {
            // Error...
        }

        char Buffer[128];
        std::size_t Received;
        sf::IPAddress Sender;
        unsigned short Port;
        if (Socket.Receive(Buffer, sizeof(Buffer), Received, Sender, Port) != sf::Socket::Done)
        {
            // Error...
        }

        // Show the address / port of the sender
        client[connected] = Sender;

        Socket.Close();

        sf::Thread* send = new sf::Thread(&sendInfo, &client[connected]);
        sf::Thread* receive = new sf::Thread(&receiveInfo, &client[connected]);
        // Start it !
        send->Launch();
        receive->Launch();
        connected++;
    }

    while(true){

    }

    return EXIT_SUCCESS;
}

客户:

#include <SFML/System.hpp>
#include <SFML/Network.hpp>
#include <iostream>

void sendInfo(void *UserData)
{
    // Print something...
    while(true){
        // Create the UDP socket
        sf::SocketUDP Socket;

        // Create bytes to send
        char Buffer[] = "client sending info.";

        // Send data to "192.168.0.2" on port 4567
        if (Socket.Send(Buffer, sizeof(Buffer),  "127.0.0.1", 4444) != sf::Socket::Done)
        {
            // Error...
        }
    }
}

void receiveInfo(void *userData)
{
    // Print something...
    while(true){
        // Create the UDP socket
        sf::SocketUDP Socket;

        // Bind it (listen) to the port 4567
        if (!Socket.Bind(4444))
        {
            // Error...
        }

        char Buffer[128];
        std::size_t Received;
        sf::IPAddress Sender;
        unsigned short Port;
        if (Socket.Receive(Buffer, sizeof(Buffer), Received, Sender, Port) != sf::Socket::Done)
        {
            // Error...
        }

        // Show the address / port of the sender
        std::cout << Buffer << std::endl;

        Socket.Close();

    }
}

int main()
{
    // Create the UDP socket
    sf::SocketUDP Socket;

    // Create bytes to send
    char Buffer[] = "Client Joined.";

    // Send data to "192.168.0.2" on port 4567
    if (Socket.Send(Buffer, sizeof(Buffer), "127.0.0.1", 4444) != sf::Socket::Done)
    {
        // Error...
    }

    sf::Thread* send = new sf::Thread(&sendInfo);
    sf::Thread* receive = new sf::Thread(&receiveInfo);
    // Start it !
    send->Launch();
    receive->Launch();


    while(true){

    }

    return EXIT_SUCCESS;
}

【问题讨论】:

  • 您的代码似乎正在使用具有类似 TCP 逻辑的 UDP 套接字。在服务器端,两个客户端应该只有 1 个套接字。我怀疑正在发生错误,但您没有使用“错误...”cmets 诊断任何内容!
  • 为什么每次发送和接收调用使用不同的套接字?

标签: c++ multithreading networking sfml


【解决方案1】:

首先要做的事情:这是一个聊天服务器还是一个“更典型”的服务器?

如果这是一个聊天服务器,那么您需要有一个 连接 到客户端的套接字列表(您可以使用 @987654324 连接 UDP 套接字@call,非常方便,还有助于减少欺骗对等点的机会)或您可以提供给sendto()sendmsg() 的所有客户端地址的列表。

更多“典型”服务器不会尝试向任何客户端发送消息,除了最近发出请求的客户端:这些服务器通常不会从客户端保存任何内容,而是会使用recvfrom()recvmsg() 获取对等体的地址,以供以后使用sendto()sendmsg() 调用。

另外,大多数协议只依赖一个well known port;服务器按惯例使用一个特定端口,但客户端选择任何开放且空闲的端口。 FTP 也严重依赖客户端上的知名端口,因此通过Network Address Translation 防火墙的隧道非常痛苦。

这不仅仅是学术问题:您的客户端您的服务器都在尝试将bind() 连接到端口4444。这意味着您需要在一台机器上至少有两个 IP 地址来进行测试,或者使用虚拟化软件在相同的硬件上运行完全独立的机器,或者只有两台机器可用。这比需要做的工作更多,客户没有理由关心他们的本地端口号:

服务器:

    // Bind it (listen) to the port 4567
    if (!Socket.Bind(4444))
    {
        // Error...
    }

客户:

    // Bind it (listen) to the port 4567
    if (!Socket.Bind(4444))
    {
        // Error...
    }

噗!如果没有重大技巧,这两个永远不会在同一主机上运行。我希望您的“它连接到一个”可能只是连接到自身的服务器或客户端,但是如果没有一些代码来填充那些// Error 块,很难确定.

(当我们在这里的时候,我想顺便谈谈 cmets;简单地重新说明代码的作用的 cmets 并不是很有用。您会注意到,您的大多数 cmets 都是实际上错误,指的是错误的IP或端口。有些只是没有添加任何信息:

    // Create the UDP socket
    sf::SocketUDP Socket;

我知道我们被教导要添加 cmets,但遗憾的是,我们并不总是被教导要添加什么 种类的 cmets。在这两个程序中,我建议甚至保留的唯一评论就是这一条,稍作修改:

    // udp doesn't require listen or accept
    if (!Socket.Bind(4444))

阅读代码不明显,从环境变量、命令行参数、配置文件或注册表中读取端口号也不会出错。 (这可能在熟悉套接字 API 的团队中过于多余,但对于不熟悉 UDP 和 TCP 之间差异的程序员来说可能是黄金。)

好的函数名、变量名等,几乎每次都会战胜cmets。一边结束。 :)

现在,更小的吹毛求疵:你的线程处理程序正在执行一些这样的任务:

while(1) {
    socket s;
    bind s;
    r = recv s;
    print r;
    close s;
}

这种不必要的创建、绑定和关闭都是浪费的能量,包括计算机的能量和(更重要的是)你的能量。考虑以下两个重写:

recv_thread() {
    socket s;
    bind s;
    while (1) {
        r = recv s;
        print r;
    }
    close s;
}

recv_thread(s) {
    while (1) {
        r = recv s;
        print r;
    }
}
/* ... */
socket s;
bind s;
sf::Thread* rt = new sf::Thread(&recv_thread);
rt->Launch(s);

第一个选项是对现有代码的简单重构;它在线程函数中保留套接字的创建和销毁,但将loop invariants 移出循环。循环内的代码现在只做必要的事情。

第二个选项是一个更彻底的改造:它将套接字创建移动到主线程,在那里错误处理可能要容易得多,并且线程函数只做远程对等点需要的事情那个线程要做。 (如果您想从 UDP 更改为 TCP,则第二种选择会更容易更改——您的线程代码可能根本不需要任何修改。)

我希望这会有所帮助。 :)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-08-17
    • 2012-12-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多