如何使用select()进行非阻塞聊天?

时间:2019-01-03 19:22:01

标签: c select tcp

我想创建一个非阻塞聊天。
聊天的工作方式如下:Client1向服务器发送一条消息,然后服务器将其发送给其他客户端。

服务器:

#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()会阻止它,但如何解决。如何进行非阻塞聊天,客户端将消息发送到服务器,而其他客户端从服务器获取消息?预先感谢。

0 个答案:

没有答案