Как я могу использовать и writefds и readfds для нескольких клиент-серверных коммуникационных программ на языке C? - PullRequest
0 голосов
/ 16 января 2019

В настоящее время я пытаюсь создать несколько клиент-сервер, который позволяет серверу выполнять функции чтения и записи на языке Си. Я могу читать данные с клиента, используя readfds и положить его в качестве параметра в SELECT. Когда я добавил в writefds, клиент не может подключиться к серверу. Я не уверен, что является причиной этого, является ли это правильный метод для передачи и получения данных

Это код для моего сервера

#include <stdio.h>
#include <string.h>   //strlen
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>   //close
#include <arpa/inet.h>    //close
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/time.h> //FD_SET, FD_ISSET, FD_ZERO macros

#define TRUE   1
#define FALSE  0
#define PORT 8080

int main(int argc , char *argv[])
{
    int opt = TRUE;
    int master_socket , addrlen , new_socket , client_socket[30] ,
        max_clients = 2 , activity, i , valread , sd;
    int max_sd;
    struct sockaddr_in address;

    char buffer[1025];  //data buffer of 1K

    fd_set readfds;
    fd_set writefds;


    char *message = "Welcome to Server\r\n";

    //initialise all client_socket[] to 0 so not checked
    for (i = 0; i < max_clients; i++)
    {
        //client_socket[i] = 0;
    }

    //create a master socket
    if( (master_socket = socket(AF_INET , SOCK_STREAM , 0)) == 0)
    {
        perror("socket failed");
        exit(EXIT_FAILURE);
    }

    if( setsockopt(master_socket, SOL_SOCKET, SO_REUSEADDR, (char *)&opt,
          sizeof(opt)) < 0 )
    {
        perror("setsockopt");
        exit(EXIT_FAILURE);
    }

    //type of socket created
    address.sin_family = AF_INET;
    address.sin_addr.s_addr = INADDR_ANY;
    address.sin_port = htons( PORT );

    //bind the socket to localhost port 8888
    if (bind(master_socket, (struct sockaddr *)&address, sizeof(address))<0)
    {
        perror("bind failed");
        exit(EXIT_FAILURE);
    }
    printf("Listener on port %d \n", PORT);

    if (listen(master_socket, 3) < 0)
    {
        perror("listen");
        exit(EXIT_FAILURE);
    }


    addrlen = sizeof(address);
    puts("Waiting for connections ...");

    for(;;)
    {

        //clear the socket set
        FD_ZERO(&readfds);
        FD_ZERO(&writefds);

        //add master socket to set
        FD_SET(master_socket, &readfds);
        FD_SET(master_socket, &writefds);


        max_sd = master_socket;

        //add child sockets to set
        for ( i = 0 ; i < max_clients ; i++)
        {
            //socket descriptor
            sd = client_socket[i];

            //if valid socket descriptor then add to read list
            if(sd > 0)
                FD_SET( sd , &readfds);

            //highest file descriptor number, need it for the select function
            if(sd > max_sd)
                max_sd = sd;
        }

        //wait for an activity on one of the sockets , timeout is NULL ,
        //so wait indefinitely
        activity = select( max_sd + 1 , &readfds , &writefds, NULL , NULL);

        if ((activity < 0) && (errno!=EINTR))
        {
            printf("select error");
        }


        if (FD_ISSET(master_socket, &readfds))
        {
            if ((new_socket = accept(master_socket,
                (struct sockaddr *)&address, (socklen_t*)&addrlen))<0)
            {
                perror("accept");
                exit(EXIT_FAILURE);
            }

            else {

                printf("Connected to socket \n");

            }
            bzero(buffer, 1025);

            int n=0;

            read(new_socket, buffer,       sizeof(buffer));

            printf("From client: %s\t To client: ", buffer);

            bzero(buffer, 1025);

            //add new socket to array of sockets
            for (i = 0; i < max_clients; i++)
            {
                //if position is empty
                if( client_socket[i] == 0 )
                {
                    client_socket[i] = new_socket;
                    printf("Adding to list of sockets as %d\n" , i+1);
                }
            }
        }

        else if(FD_ISSET(master_socket, &readfds)) {

            printf("From client: %s\t To client : ", buffer);
            bzero(buffer, 1025);

            // copy server message in the buffer
            while ((buffer[n++] = getchar()) != '\n')
                                        ;

            write(new_socket, buffer, sizeof(buffer));

        }


        else{
            //else its some IO operation on some other socket
            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 ((valread = read( sd , buffer, 1024)) == 0)
                    {

                        close( sd );
                        client_socket[i] = 0;
                    }

                    //Echo back the message that came in
                    else
                    {


                    }
                }
            }
        }//else

    }

    return 0;
}

Это код для клиента

#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>

#define MAX 1000
#define PORT 8080
#define SA struct sockaddr

void func(int sockfd)
{
    char buff[MAX];
    int n;
    int firstConnect = 1;

    for (;;)
    {

        bzero(buff, sizeof(buff));
        n = 0;

        if(firstConnect==1) {
            printf("Enter the string : ");
            firstConnect = 0;

            while ((buff[n++] = getchar()) != '\n')
                ;
            write(sockfd, buff, sizeof(buff));

        }


        bzero(buff, sizeof(buff));

        read(sockfd, buff, sizeof(buff));

        printf("From Server: %s\t To Server : ", buff);


        while ((buff[n++] = getchar()) != '\n');
        write(sockfd, buff, sizeof(buff));

        if ((strncmp(buff, "exit", 4)) == 0)
        {
            printf("Client Exit...\n");
            break;
        }
    }
}


int main()
{

    printf("CLIENT");
    int sockfd, connfd;
    struct sockaddr_in servaddr, cli;

    // socket create and varification
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd == -1)
    {
        printf("socket creation failed...\n");
        exit(0);
    }
    else
        printf("Socket successfully created..\n");

    bzero(&servaddr, sizeof(servaddr));

    // assign IP, PORT
    servaddr.sin_family = AF_INET;

    // servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");
    servaddr.sin_addr.s_addr = inet_addr("127.8.1.0");

    servaddr.sin_port = htons(PORT);

    // connect the client socket to server socket
    if (connect(sockfd, (SA*)&servaddr, sizeof(servaddr)) != 0)
    {
        printf("connection with the server failed...\n");
        exit(0);
    }
    else
        printf("connected to the server..\n");

    // function for chat
    func(sockfd);

    // close the socket
    close(sockfd);
}

1 Ответ

0 голосов
/ 16 января 2019

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

Также кажется, что вы ожидаете write, чтобы найти конец строки, которую вы отправляете. Этого не происходит. Вы должны указать точную длину данных, которые вы отправляете, а не длину буфера, который содержит данные.

Функции

send/write и recv/read работают с двоичными данными, а не с нулевыми строками и могут отправлять / получать меньше указанного размера или могут возвращать ошибку. Узнайте, как правильно использовать эти функции, не игнорируя возвращаемое значение и обрабатывая ошибки и частичные операции чтения и записи.

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