2014-12-29 2 views
0

Я прочитал о select(), а также прочитал много примеров этого, но я не могу понять, когда я могу его использовать? Я понял, что могу использовать его в функции accept(), если я хочу, чтобы несколько человек подключились к серверу, но меня это смутило. Мне нужно создать сервер, который получает данные только от 2 клиентов, 1 каждый раз. Первый пользователь отправляет на сервер строку, строка отвечает, а затем второй пользователь отправляет строку. Может ли кто-нибудь помочь мне с объединением функции select() в функции recv()? Я добавил код server.cpp. Спасибо!Улучшение сервера с помощью функции select()

сервер:

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

Значит, вы написали свой собственный сервер в C (++) и теперь хотите добавить функцию, которую вы не знаете, что она делает, просто для удовольствия? –

+0

@BaummitAugen Я знаю, что он делает, поскольку я сказал, что много читаю об этой функции. Я просто не знаю, как объединить его в моем собственном коде. – Guy

+0

@BaummitAugen Можете ли вы помочь мне вместо того, чтобы пытаться меня обмануть? – Guy

ответ

1

Хорошо, теперь, когда вы исправил свой код, я должен сделать какую-то работу.

Я предлагаю вам удалить этот

user = !user 

и добавить сразу после начала цикла в то время:

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

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

+0

Благодарим вас за помощь! Я все еще немного недопонимаю, я пытаюсь создать шахматную игру. Пользователь вводит команду (то есть E2-C5), тогда сервер проверяет, возможна ли эта строка (правила шахмат), - и затем, если это возможно возвращает плату для обоих пользователей, иначе он возвращает пользователю сообщение об ошибке (через сокет). Можете ли вы мне немного помочь? Я благодарен вам за помощь. – Guy

+0

Во-первых, будьте осторожны - сокеты TCP не соблюдают границы пакетов. Перед анализом убедитесь, что у вас есть полный переход от клиента onc. Вам может потребоваться recv() несколько раз за один ход. Это произойдет редко, но это может произойти. Затем - ну, вы получили ход, вы его проанализировали, а затем, в зависимости от того, действительно ли это, вы можете либо отправить сообщение об ошибке одному клиенту, либо править сначала изменить на одного клиента, а затем на другой. –

+0

Я получаю строку от клиентов в этом формате: XX-YY, поэтому проблем не будет. Я не понял, как я могу отправить конкретному пользователю строку, и как я могу отправить оба клиента? Я читал о указателях чтения и записи, но я не очень понял. – Guy

Смежные вопросы