服务器无法连接到多个客户端?

发布于 2024-11-06 11:42:57 字数 4008 浏览 2 评论 0原文

问题是它只连接到一个客户端而不是两个。谁能帮我找出原因吗?

服务器:

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

The problem is it only connects to one client instead of two. Can anyone help me figure out why?

Server:

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

Client:

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

蒲公英的约定 2024-11-13 11:42:57

首先,这是一个聊天服务器还是一个“更典型”的服务器?

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

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

此外,大多数协议仅依赖于一个众所周知的端口;服务器按照约定使用一个特定端口,但客户端选择任何开放且空闲的端口。 FTP 也严重依赖客户端上众所周知的端口,因此通过

这不仅仅是学术问题:您的客户端您的服务器都在尝试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 块,它'很难确定。

(当我们在这里时,我想抽出时间来谈谈注释;简单地重新说明代码功能的注释并不是很有用。您会注意到,您的大多数注释实际上都是 < em>错误,指的是错误的 IP 或端口。有些只是不添加任何信息:

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

我知道我们被教导要添加注释,但遗憾的是我们并不总是被教导什么类型。 > 我要添加的两个程序中唯一的评论。建议保留这个,稍微修改一下:

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

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

好的函数名称、变量名称等., 几乎每次都会赢得评论到此结束了:)

现在,更小的问题是:您的线程处理程序正在执行一些这样的任务:

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

第一个选项是对现有代码进行简单重构;它将套接字的创建和销毁保留在线程函数中,但将 循环不变量移出循环。循环内的代码现在仅执行必要的操作。

第二个选项是更彻底的改造:它将套接字创建移至主线程,其中错误处理可能容易得多,并且线程函数仅执行远程对等点需要该线程执行的操作做。 (如果您想从 UDP 更改为 TCP,那么第二个选项是迄今为止更容易更改的选项 — 您的线程代码可能根本不需要任何修改。)

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

First things first: is this a chat server or a 'more typical' server?

If this is a chat server, then you either need to have a list of sockets that are connected to the clients (you can connect UDP sockets using the connect() call, very convenient, and it also helps reduce the chances of spoofed peers) or a list of all the client addresses that you can supply to sendto() or sendmsg().

More 'typical' servers won't try to send messages to any client except the one that most recently made a request: those servers typically don't save anything from the clients, and instead will use recvfrom() or recvmsg() to get the peer's address for use in later sendto() or sendmsg() calls.

Also, most protocols only rely on one well known port; the server uses one specific port by convention, but clients select whatever port is open and free. FTP relies heavily on well-known ports on the client-side as well, and as a result is a gigantic pain to tunnel through Network Address Translation firewalls.

It isn't just academic: both your client and your server are attempting to bind() to port 4444. This means you need at least two IP addresses on a single machine to test, or use virtualization software to run an entirely separate machine on the same hardware, or just have two machines available. It's more work than it needs to be, and there's no reason for the clients to care about their local port numbers:

Server:

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

Client:

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

Poof! These two will never run on the same host without significant tricks. I expect your "it connects to one" is probably just the server or the client connecting to itself, but without some code to fill in those // Error blocks, it'd be tough to tell for sure.

(And while we're here, I'd like to take an aside to talk about comments; comments that simply re-state what the code does aren't very useful. You'll note that most of your comments are in fact wrong, referring to wrong IPs or ports. Some just don't add any information:

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

I know we're taught to add comments, but sadly we're not always taught what kind of comments to add. The only comment in both programs that I'd recommend even keeping would be this one, slightly amended:

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

It isn't obvious from reading the code, and won't be wrong when the port number is read out of an environment variable, command line parameter, configuration file, or registry. (It might be too redundant in a team of people familiar with the sockets API, but might be gold for a programmer not that familiar with the differences between UDP and TCP.)

Good function names, variable names, etc., will win over comments almost every time. End of aside. :)

And now, the more minor nit-picking: your thread handlers are doing some tasks like this:

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

This needless creation, binding, and closing, is all wasted energy, both the computer's energy and (much more importantly) your energy. Consider the following two re-writings:

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

or

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

The first option is a simple refactoring of your existing code; it keeps the socket creation and destruction in the thread function, but moves the loop invariants out of the loop. The code inside the loop now does only what is necessary.

The second option is a more drastic reworking: it moves the socket creation to the main thread, where error-handling is probably much easier, and the thread function only does exactly what the remote peer needs that thread to do. (If you wanted to change from UDP to TCP, the second option would be by far the much easier easier one to change -- your threading code might not need any modifications at all.)

I hope this helps. :)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文