Чтение блоков, когда нет данных для чтения из сокета - PullRequest
0 голосов
/ 20 мая 2019

Я внедряю приложение сервер / клиент для образовательных целей. Мой сервер открывает сокет и опрашивает его на предмет соединений. Если соединение доступно, оно принимает его и отправляет некоторые данные. Затем он ожидает ввода и снова отправляет некоторые данные.

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

Это не кажется хорошим решением, и, поскольку это образовательный проект, мне было интересно, как бы я сделал его абстрактным (т.е. не заботился о том, сколько раз сервер отправлял мне что-то, и я отправлял что-то обратно. )

До сих пор я пытался зациклить, чтобы получить входные данные сервера, но безуспешно. Сервер дважды пишет в сокет, поэтому клиент должен дважды прочитать, прежде чем пытаться отправить собственное сообщение. Если я в третий раз читаю блоки чтения (что я считаю нормальным поведением).

Я пытался использовать опрос на сокете со стороны клиента для отслеживания событий POLLOUT, но, похоже, он не работает.

int connect(){

    unsigned int backlog = 10;

/*
    struct sockaddr_in {
        short            sin_family;   // e.g. AF_INET
        unsigned short   sin_port;     // e.g. htons(3490)
        struct in_addr   sin_addr;     // see struct in_addr, below
        char             sin_zero[8];  // zero this if you want to
    };

    struct in_addr {
        unsigned long s_addr;  // load with inet_aton()
    };
*/

    struct sockaddr_in server{};

    //Create socket
    listeningSocket = socket(AF_INET, SOCK_STREAM, 0);
    if (listeningSocket == -1) {
        spdlog::critical("Could not create socket");
    }

    spdlog::debug("Socket created.");

    //Prepare the socket for incoming connections
    server.sin_family = AF_INET;
    server.sin_addr.s_addr = INADDR_ANY;
    server.sin_port = htons(PortNumber); // NOLINT(hicpp-signed-bitwise)

    if (bind(listeningSocket, (const struct sockaddr *) &server, sizeof(sockaddr_in)) < 0) {
        spdlog::critical("bind failed. Error");
        exit(-1);
    }

    spdlog::debug("Bind succeeded\n");

    if (!listen(listeningSocket, static_cast<int>(backlog))) {
        return listeningSocket;
    }

    return -1;
}

Обработка сообщения

void* sendMessage(){

    //Get the socket descriptor
    int sock = socket;
    int read_size;
    const char *message;
    char client_message[200];

    //Send some messages to the client
    message = "Greetings! I am your connection handler\n";
    write(sock, message, strlen(message));

    message = "Now type something and i shall apply the caesar cipher to it \n";
    write(sock, message, strlen(message));

    //Receive a message from client
    while ((read_size = recv(sock, client_message, 200, 0)) > 0) {
        //end of string marker
        client_message[read_size] = '\0';

        std::string temp(client_message);
        temp = cipher->operate(temp);

        //Send the message back to client
        write(sock, temp.c_str(), strlen(temp.c_str()));

        //clear the message buffer
        memset(client_message, 0, 200);
    }

    if (read_size == 0) {
        spdlog::debug("Client disconnected");
        fflush(stdout);
    } else if (read_size == -1) {
        spdlog::error("recv failed: {}",errno);
    }

    return nullptr;

}

Что касается стороны клиента:

//Connect to the server 

void connect()
 {
        struct hostent *he;
        struct sockaddr_in their_addr{}; /* connector's address information */

        if ((he=gethostbyname(mHost.c_str())) == nullptr) {  /* get the host info */
            spdlog::error("gethostbyname");
        }

        if ((mSocket = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
            spdlog::error("socket");
            exit(1);
        }

        their_addr.sin_family = AF_INET;      /* host byte order */
        their_addr.sin_port = htons(mPort);    /* short, network byte order */ //NOLINT
        their_addr.sin_addr = *((struct in_addr *)he->h_addr);
        bzero(&(their_addr.sin_zero), 8);     /* zero the rest of the struct */

        if (connect(mSocket, (struct sockaddr *)&their_addr, sizeof(struct sockaddr)) == -1) {
            spdlog::error("connect");
            exit(1);
        }
}

}

И попробуйте отправить сообщение:

void sendMessage(){

#define MAX 100

    if (!sockfd) {
        sockfd = mSocket;
        spdlog::info("Setting socket to {}", sockfd);
    }

    char buff[MAX];
struct pollfd fds[1];
fds[0].fd=sockfd;



    while (( recv(sockfd, buff, 200, 0)) > 0) {

        printf("From Server : %s", buff);
        bzero(buff, sizeof(buff));
    }

    strcpy(buff, "PAPARI");
    write(sockfd, buff, sizeof(buff));
    bzero(buff, sizeof(buff));

    read(sockfd, buff, sizeof(buff));
    printf("From Server : %s", buff);


    close(sockfd);

}

Блокируется после получения клиентом двух сообщений от сервера.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...