gpt4 book ai didi

c++ - 使用 select() 函数改进服务器

转载 作者:行者123 更新时间:2023-11-28 06:30:25 26 4
gpt4 key购买 nike

我阅读了 select() 并阅读了它的许多示例,但我不明白什么时候可以使用它?我知道我可以在 accept() 函数中使用它,以防我希望很少有人连接到服务器,但这让我感到困惑。我需要构建一个只从 2 个客户端接收数据的服务器,每次 1 个。第一个用户向服务器发送一个字符串,该字符串响应,然后第二个用户发送一个字符串。有人可以帮我在 recv() 函数中组合 select() 函数吗?我已经添加了我的 server.cpp 代码。谢谢!

服务器:

#include <iostream>
#include <winsock2.h>
#include <string>
#include <windows.h>
#include <vector>
#pragma comment(lib,"ws2_32.lib")

#define MAX_NUMBER_OF_PLAYERS 1
#define BUFFER_SIZE 1024
#define LIMIT 1

// server side
#define INVALID_MOVE 00
#define PLEASE_ENTER_A_MOVE 15
#define PRINT_BOARD 20
#define END_GAME 30

// client side
#define MOVE 10


using namespace std;

int main()
{
WSADATA WsaDat;
SOCKET clientsock[2];
int minsock = 0;
int numsocks = MAX_NUMBER_OF_PLAYERS;

if (WSAStartup(MAKEWORD(2, 2), &WsaDat) != 0)
{
std::cout << "WSA Initialization failed!\r\n";
WSACleanup();
system("PAUSE");
return 0;
}

SOCKET serverSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (serverSocket == INVALID_SOCKET)
{
std::cout << "Socket creation failed.\r\n";
WSACleanup();
system("PAUSE");
return 0;
}

SOCKADDR_IN serverInf;
serverInf.sin_family = AF_INET;
serverInf.sin_addr.s_addr = INADDR_ANY;
serverInf.sin_port = htons(8888);

if (bind(serverSocket, (SOCKADDR*)(&serverInf), sizeof(serverInf)) == SOCKET_ERROR)
{
std::cout << "Unable to bind socket!\r\n";
WSACleanup();
system("PAUSE");
return 0;
}

listen(serverSocket, 5);



clientsock[0] = accept(serverSocket, NULL, NULL);
cout << "Client 1 has connected." << endl;
clientsock[1] = accept(serverSocket, NULL, NULL);
cout << "Client 2 has connected." << endl;

for (int i = 0; i < 2; i++)
{
cout << "Client " << i+1 << " Has Connected!" << endl;
}

char client1_buffer[BUFFER_SIZE];
char client2_buffer[BUFFER_SIZE];
char* clientBuffer;
// until there isn't a mate.
bool gameRunning = true;
// user represents if it's user1 (0), or user2(1)
bool user = 0;


while (gameRunning)
{
if (!user)
clientBuffer = client1_buffer;
else
clientBuffer = client2_buffer;

int in = recv(clientsock[user], clientBuffer, BUFFER_SIZE, 0);
cout << in << endl;
if (in > 0)
{
// CHECKS
// MOVE COMMAND
// IF worked, send the board to both clients. if current user = 1 ==> do user to 0 | if the user = 0 => do user to 11
// ELSE, send the current client (clientsock[user]) Error message and ask for a command again.
cout << clientBuffer << endl;
cout << " IN RECV";
char* szMessage = "15";
send(clientsock[user], szMessage, sizeof(szMessage), 0);
}
else if (in == 0)
{
// The connection has closed.
// REMEMBER : SAVE THE GAME SITUATION.
}
else
{
printf("recv failed: %d\n", WSAGetLastError());
// SEND ERROR MESSAGE TO BOTH CLIENTS
}

user = !user;
}
// Shutdown our socket
shutdown(serverSocket, SD_SEND);

// Close our socket entirely
closesocket(serverSocket);

WSACleanup();
system("pause");
return 0;
}

最佳答案

好的,现在你已经更正了你的代码,我必须做一些工作。

我建议你删除这个

user = !user

并在 while 循环开始后立即添加:

{
int nfds = 0; // smallest number higher than all socket descriptors
fd_set set; // this contains garbage from the stack, thus ...
FD_ZERO(&set); // first clean it and then add both client sockets:
FD_SET(clientsock[0],&set); if(nfds<=clientsock[0]) nfds=clientsock[0]+1;
FD_SET(clientsock[1],&set); if(nfds<=clientsock[1]) nfds=clientsock[1]+1;
select(nfds,&set,0,0,0); // this uses and changes the content of set
bool next = !user; // next is the other user, and we try to serve it:
if(FD_ISSET(clientsock[next],&set)) user=next;
}

顺便说一下,我喜欢你使用 bool 作为索引的创造性方式,但一旦你有超过 2 个客户,你可能不得不改变这个概念。

我的代码实现了一些调度策略:如果两个客户端都有数据可用,它会从上次未读取数据的那个客户端读取数据。相反,如果您想从一个客户端读取大量数据,然后从另一个客户端读取大量数据,请将包含 next 的行替换为

if(!FD_ISSET(clientsock[user],&set)) user=!user;

第一个版本尝试尽可能频繁地交替,而第二个版本尝试在切换到另一个客户端之前从同一客户端读取尽可能多的数据。

关于c++ - 使用 select() 函数改进服务器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27697155/

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