Как сделать неблокирующий чат с помощью select ()? - PullRequest
0 голосов
/ 03 января 2019

Я хотел создать неблокирующий чат.
Чат может работать так: Клиент1 отправляет сообщение на сервер, затем сервер отправляет его другим Клиентам.

Сервер:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/time.h>

#define PORT 50000
#define TRUE 1
#define FALSE 0

int main() {
    pid_t pid;
    int serverSocket, binding, valrecv, newSocket, client_socket[30], activity, max_clients = 30, max_sd, sd, addrlen;
    struct sockaddr_in serverAddr;
    char buffer[1024];
    fd_set readfds;

    int i;
    for(i=0; i<max_clients; i++) {
        client_socket[i] = 0;
    }

    serverSocket = socket(AF_INET, SOCK_STREAM, 0);
    if(serverSocket < 0) {
        printf("[-] Socket error.\n");
        exit(1);
    }
    printf("[+] Server socket created.\n");

    memset(&serverAddr, '\0', sizeof(serverAddr));

    serverAddr.sin_family = AF_INET;
    serverAddr.sin_port = htons(PORT);
    serverAddr.sin_addr.s_addr = inet_addr("127.0.0.1");

    binding = bind(serverSocket, (struct sockaddr*)&serverAddr, sizeof(serverAddr));
    if(binding < 0) {
        printf("[-] Binding error.\n");
        exit(1);
    }
    printf("[+] Socked binded.\n");

    if(listen(serverSocket, 2) == 0) {
        printf("[+] Listening...\n");
    } else {
        printf("[-] Listening error.\n");
    }

    while(TRUE) {
        FD_ZERO(&readfds);
        FD_SET(serverSocket, &readfds);
        max_sd = serverSocket;

        for(i=0; i<max_clients; i++) {
            sd = client_socket[i];

            if(sd > 0) {
                FD_SET(sd, &readfds);
            }

            if(sd > max_sd) {
                max_sd = sd;
            }
        }

        activity = select(max_sd + 1, &readfds, NULL, NULL, NULL);
        if(activity < 0) {
            printf("[-] Select error.\n");
        }

        if(FD_ISSET(serverSocket, &readfds)) {

            newSocket = accept(serverSocket, (struct sockaddr*)&serverAddr, (socklen_t*)&addrlen);
            if (newSocket < 0) {
                printf("[-] Accept error.\n");
                exit(1);
            }

            printf("New connection, socked fd: %d, ip: %s:%d\n", 
            newSocket, inet_ntoa(serverAddr.sin_addr), ntohs(serverAddr.sin_port));

            if( send(newSocket, "HI", strlen("HI"), 0) != strlen("Current Board") )   
            {   
                perror("send");   
            }   

            for (i = 0; i < max_clients; i++) {   
                if( client_socket[i] == 0 )   
                {   
                    client_socket[i] = newSocket;   
                    printf("Adding to list of sockets as %d\n" , i);   

                    break;   
                }   
            }   
        }

        for (i = 0; i < max_clients; i++)   
        {   
            sd = client_socket[i];   

            if (FD_ISSET( sd , &readfds))   
            {   
                //Check if it was for closing , and also read the  
                //incoming message  
                if ((valrecv = recv( sd , buffer, sizeof(buffer), 0)) == 0)   
                {   
                    //Somebody disconnected , get his details and print  
                    getpeername(sd, (struct sockaddr*)&serverAddr, (socklen_t*)&addrlen);   
                    printf("Host disconnected , ip %s , port %d \n" ,  
                        inet_ntoa(serverAddr.sin_addr) , ntohs(serverAddr.sin_port));   

                    //Close the socket and mark as 0 in list for reuse  
                    close( sd );   
                    client_socket[i] = 0;   
                }   

                //Echo back the message that came in  
                else 
                {   
                    //set the string terminating NULL byte on the end  
                    //of the data read  
                    buffer[valrecv] = '\0';   
                    int j;  
                    for(j=0; j<max_clients; j++) {
                        sd = client_socket[j];

                        send(sd, buffer, strlen(buffer), 0);
                    }   
                }   
            }   
        }

    }

    return 0;
}

Клиент:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#define PORT 50000

int main() {
    int clientSocket, connection;
    struct sockaddr_in serverAddr;
    char buffer[1024];

    clientSocket = socket(AF_INET, SOCK_STREAM, 0);
    if(clientSocket < 0) {
        printf("[-] Socket error.\n");
        exit(1);
    }
    printf("[+] Client socket created.\n");

    memset(&serverAddr, '\0', sizeof(serverAddr));

    serverAddr.sin_family = AF_INET;
    serverAddr.sin_port = htons(PORT);
    serverAddr.sin_addr.s_addr = inet_addr("127.0.0.1");

    connection = connect(clientSocket, (struct sockaddr*) &serverAddr, sizeof(serverAddr));
    if(connection < 0) {
        printf("[-] Connection error.\n");
        exit(1);
    }
    printf("[+] Connected to server.\n");

    while(TRUE) {

        send(clientSocket, "TEST", strlen("TEST"), MSG_DONTWAIT);

        if(recv(clientSocket, buffer, 1024, 0) < 0) {
            printf("[-] Data receiving error.\n");
        } else {
            printf("Server: %s\n", buffer);
        }

    }

    return 0;
}

Клиент не получает сообщение от сервера, пока не отправит сообщение на сервер.Я знаю, что send () блокирует это, но как это решить.Как сделать неблокирующий чат, когда клиенты отправляют сообщение на сервер, а другие клиенты получают это сообщение с сервера?Заранее спасибо.

...