Я прочитал о 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;
}
Хорошо, теперь, когда вы исправили свой код, я должен сделать некоторую работу.
Я предлагаю вам удалить это
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;
Первая версия пытается чередоваться как можно чаще, а вторая пытается прочитать как можно больше данных с одного и того же клиента, прежде чем переключиться на другой.