Улучшите сервер с помощью функции select ()

Я прочитал о select (), а также прочитал много примеров, но не могу понять, когда я смогу его использовать?
Я понял, что могу использовать его в функции accept (), если я хочу, чтобы мало кто подключался к серверу, но это меня смутило.
Мне нужно построить сервер, который получает данные только от 2 клиентов, 1 каждый раз. Первый пользователь отправляет на сервер строку, строка отвечает, а затем второй пользователь отправляет строку.
Может кто-нибудь помочь мне с объединением функции select () в функцию recv ()?
Я добавил свой код 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 10using 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;
}

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 в качестве индекса, хотя, если у вас более двух клиентов, вам, возможно, придется изменить эту концепцию.

Мой код реализует немного политики планирования: если есть данные, доступные от обоих клиентов, он читает с того клиента, с которого он не считывал данные в предыдущий раз. Если вместо этого вы хотите прочитать много данных от одного клиента, а затем много данных от другого, замените строки, содержащие next от

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

Первая версия пытается чередоваться как можно чаще, а вторая пытается прочитать как можно больше данных с одного и того же клиента, прежде чем переключиться на другой.

1

Другие решения


По вопросам рекламы [email protected]