当前位置:  开发笔记 > 编程语言 > 正文

服务器不会连接到多个客户端?

如何解决《服务器不会连接到多个客户端?》经验,为你挑选了1个好方法。

问题是它只连接到一个客户端而不是两个客户端.任何人都可以帮我找出原因吗?

服务器:

#include 
#include 
#include 

void sendInfo(void *UserData)
{
    sf::IPAddress* ip = static_cast(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 
#include 
#include 

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

sarnold.. 9

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

如果这是一个聊天服务器,那么您需要有一个连接到客户端的套接字列表(您可以使用该connect()呼叫连接UDP套接字,非常方便,还有助于减少欺骗对等体的可能性)或列表您可以提供给或的所有客户端地址.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块,很难确定.

(虽然我们在这里,但我想暂时谈谈评论;仅仅重新陈述代码所做的评论并不是很有用.你会注意到你的大多数评论实际上是错误的,指的是错误的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,第二个选项将更容易更改 - 您的线程代码可能根本不需要任何修改.)

我希望这有帮助.:)



1> sarnold..:

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

如果这是一个聊天服务器,那么您需要有一个连接到客户端的套接字列表(您可以使用该connect()呼叫连接UDP套接字,非常方便,还有助于减少欺骗对等体的可能性)或列表您可以提供给或的所有客户端地址.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块,很难确定.

(虽然我们在这里,但我想暂时谈谈评论;仅仅重新陈述代码所做的评论并不是很有用.你会注意到你的大多数评论实际上是错误的,指的是错误的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,第二个选项将更容易更改 - 您的线程代码可能根本不需要任何修改.)

我希望这有帮助.:)

推荐阅读
刘美娥94662
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有