Обработка нескольких пользователей с помощью WinSock - PullRequest
0 голосов
/ 11 мая 2018

Я следую этому руководству , которое показывает, как принимать несколько соединений без использования многопоточности.

Проблема, с которой я сталкиваюсь, заключается в том, что функция accept() всегда возвращает SOCKET_ERROR.

Я хочу, чтобы сервер принимал несколько клиентов.Я хотел бы, чтобы кто-то мог указать мне на то, что я делаю неправильно.

Вот мой код сервера:

#pragma comment(lib, "ws2_32.lib")

#include <WinSock2.h>
#include <stdio.h>
#include <signal.h>
#include <conio.h>
#include <assert.h>
#include <Windows.h>
#include <iostream>

//sockets
#define CLIENT_CON 10
#define CLIENT_DIS 20
#define BF_SZ 100
#define MAX_CONS 5

SOCKET sock, clien;
int PR_CONS = 0;

struct _client
{
    bool con; // Set true if a client is connected
    sockaddr_in addr; // Client info like ip address
    SOCKET cs; // Client socket
    fd_set set; // used to check if there is data in the socket
    int i; // any piece of additional info
};
_client client[10];

int accept(_client*);
int send(_client*, char*,int);
int recv(_client*, char*, int);
void Server_Status(int );
void char_message(char*);
void accept_clients();
void recv_client();

int main() {
    //int res;
    int i = 1;
    int port = 5150;
    SOCKET sock;
    WSADATA ws;
    printf("\t Echo Server (Multiple client support)\n");
    sockaddr_in ser;
    ser.sin_family = AF_INET;
    ser.sin_addr.S_un.S_addr = INADDR_ANY;
    ser.sin_port = htons(port);
    WSAStartup(MAKEWORD(2,2),&ws);

    sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

    setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char*)&i,sizeof(i));
    bind(sock,(SOCKADDR*)&ser, sizeof(ser));
    listen(sock,5);
    printf("listening \n");
    unsigned long b= 1;
    ioctlsocket(sock,FIONBIO,&b);

    for(int i = 0; i < MAX_CONS; i++) {
        client[i].con = false;
    }

    while(true) {
        accept_clients();
        recv_client();
    }       
}

int accept(_client* x) {
     x->i = sizeof(sockaddr_in);
     x->cs = accept(sock, (SOCKADDR*)&x->addr, &x->i);
     if(x->cs != INVALID_SOCKET ) {
         std::cout << x->cs << std::endl;
         x->con = true;
         FD_ZERO(&x->set);
         FD_SET(x->cs,&x->set);
         printf("accepted client");
         return true;
     }
     //printf("failed to accept client");
     return false;
 }

 int send(_client* x, char* buffer, int sz) {
    x->i = send(x->cs, buffer, sz, 0);
    if(x-> i == SOCKET_ERROR || x->i == 0 ) {
        return false;
    }
    return true;
 }

 int recv(_client *x, char* buffer, int sz) {
     if(FD_ISSET(x->cs,&x->set)) {
        x->i = recv(x->cs,buffer,sz, 0);
        if(x->i == 0) {
            return false;
        }
        return true;
     }
     return false;
 }

 void accept_clients() {
     for(int i = 0; i < MAX_CONS;  i++) {           
         if(!client[i].con) {
            if(accept(&client[i])) {
                Server_Status(CLIENT_CON);
            }
        }
    }
}

void Server_Status(int msg) {
    if(msg == CLIENT_CON) {
        PR_CONS++;
        printf("client has connected");
    }
    else if(msg == CLIENT_DIS) {
        PR_CONS--;
        printf("client has disconnected");
    }
    else {
        printf("we got unknown message");
    }
}

void chat_message(char* s) {
    int len = strlen(s);
    for(int i = 0; i< MAX_CONS; i++) {
        if(client[i].con) {
            send(&client[i], s, len);
        }           
    }
}

void recv_client() {
    char buffer[BF_SZ];
    for(int i = 0; i < MAX_CONS; i++) {
        if(client[i].con) {
            if(recv(&client[i],buffer, BF_SZ)) {
                if(buffer[0] == '/') {
                    if(strcmp(buffer, "/server_bang") == 0) {
                        chat_message("** Hi**");
                    }                   
                }
                else {
                    chat_message(buffer);
                }
            }
        }       
    }
}

1 Ответ

0 голосов
/ 11 мая 2018

Проблема, с которой я сталкиваюсь, заключается в том, что функция accept() всегда возвращает SOCKET_ERROR.

Это потому, что вы передаете ей недопустимый дескриптор SOCKET (если вы беспокоилисьчтобы проверить с WSAGetLastError() после получения SOCKET_ERROR, он, скорее всего, вернул бы WSAENOTSOCK).

Причина в том, что ваша функция-обертка accept() вызывает функцию accept() Winsock с глобальная SOCKET переменная с именем sock, но ваша main() функция никогда не инициализирует эту переменную!Вместо этого он инициализирует локальную SOCKET переменную , которая также называется sock.Вам нужно либо:

  • избавиться от локальной sock локальной переменной main(), чтобы main() затем использовал глобальную переменную sock.

  • избавьтесь от глобальной переменной sock, и пусть main() передаст ее локальную переменную sock в качестве входного параметра в вашу функцию accept_clients(), которая затем может передать ее в качестве входного параметра вашемуaccept() функция.

...