gpt4 book ai didi

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

转载 作者:太空狗 更新时间:2023-10-29 23:47:21 26 4
gpt4 key购买 nike

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

服务器:

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

最佳答案

第一件事:这是聊天服务器还是“更典型”的服务器?

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

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

此外,大多数协议(protocol)只依赖一个 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 block ,则很难确定。

(虽然我们在这里,但我想抽空谈谈评论;简单地重新陈述代码功能的评论并不是很有用。你会注意到你的大部分评论实际上是错误的, 指的是错误的 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;
}

这种不必要的创建、绑定(bind)和关闭,都是浪费的能量,包括计算机的能量和(更重要的是)你的能量。考虑以下两个重写:
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,则第二个选项将是迄今为止更容易更改的选项——您的线程代码可能根本不需要任何修改。)

我希望这有帮助。 :)

关于c++ - 服务器不会连接到多个客户端?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5957933/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com