Сокет в C: клиент не может получить и распечатать массив строк, отправленных с сервера - PullRequest
0 голосов
/ 03 ноября 2018

Я пишу сокетную программу, которая заключается в том, что клиент отправляет массив строк на сервер, сервер получает этот массив и отправляет обратно клиенту. Мой сервер может распечатать массив строк reply [] успешно на стороне сервера. Однако на стороне клиента он не может распечатать результат. Вот мой код

Client.c

#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 <string.h>

#define PORT 4444

int main(int argc, char *argv[]){

    if (argc < 2 || argc > 3)      // Test for correct number of arguments
        printf("Parameter(): <Server Address>");    

    char *servIP = argv[1];        // arg: server IP address (dotted quad)
    int clientSocket, ret;
    struct sockaddr_in serverAddr; // Server address
    char buffer[1024];
    char **reply = malloc(20*sizeof(char *));

    // Create a reliable, stream socket using TCP
    clientSocket = socket(AF_INET, SOCK_STREAM, 0);
    if(clientSocket < 0){
        printf("Error in connection.\n");
        exit(1);
    }
    printf("Client Socket is created.\n");

    // Construct the server address structure
    memset(&serverAddr, '\0', sizeof(serverAddr)); // Zero out structure
    serverAddr.sin_family = AF_INET;               // IPv4 address family
    serverAddr.sin_port = htons(PORT);             // Server port
    // Convert address
    int rtnVal = inet_pton(AF_INET, servIP, &serverAddr.sin_addr.s_addr);
    if (rtnVal == 0)
        printf("inet_pton() failed: invalid address string");
    else if (rtnVal < 0)
        printf("inet_pton() failed");

    // Establish the connection to the sorted server
    ret = connect(clientSocket, (struct sockaddr*)&serverAddr, sizeof(serverAddr));
    if(ret < 0){
        printf("Error in connection.\n");
        exit(1);
    }
    printf("Connected to Server.\n");

    //Read arrays from input file
    FILE *fptr;
    fptr = fopen("client1.inputdat", "r"); //open input file to read
    if (fptr != NULL)
    { 
        int line =0;
        while(fgets(buffer, sizeof(buffer), fptr)) {  //read line by line of the input file
            line++;
            if (line==1) {
                printf("\n");               
                printf("Unsorted array: %s\n", buffer);
                // Send arrays to the server
                send(clientSocket, buffer, strlen(buffer), 0);
                // Receive the sorted arrays back from the server
                if(recv(clientSocket, &reply, 20*sizeof(char *), 0) < 0){
                    printf("Error in receiving data.\n");
                }
                else {
                    int i;
                    printf("Sorted array:");
                    for (i=0; i<20; i++) {
                        reply[i] = malloc(10*sizeof(char));
                        printf("%s ", reply[i]); 
                    }
                }
            }
        }
        fclose(fptr);
    } 
    else {
        printf("File does not exits");
        exit(1);
    }
    return 0;
}

Server.c

#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 4444

int main(){

    int sockfd, ret;
     struct sockaddr_in serverAddr; // Local address

    int newSocket;
    struct sockaddr_in newAddr;

    socklen_t addr_size;

    char buffer[1024];
    pid_t childpid;

    // Create socket for incoming connections
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if(sockfd < 0){
        printf("Error in connection.\n");
        exit(1);
    }
    printf("Server Socket is created.\n");

    // Construct local address structure    
    memset(&serverAddr, '\0', sizeof(serverAddr));        // Zero out structure
    serverAddr.sin_family = AF_INET;                      // IPv4 address family
    serverAddr.sin_port = htons(PORT);                    // Local port
    serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);       // Any incoming interface

    // Bind to the local address
    ret = bind(sockfd, (struct sockaddr*)&serverAddr, sizeof(serverAddr));
    if(ret < 0){
        printf("Error in binding.\n");
        exit(1);
    }
    printf("Bind to port %d\n", 4444);

    // Mark the socket so it will listen for incoming connections 
    if(listen(sockfd, 10) == 0){                 //Maximum outstanding connection requests is 10
        printf("Listening....\n");
    }else{
        printf("Error in binding.\n");
    }


    while(1){
        // Wait for clients to connect
        newSocket = accept(sockfd, (struct sockaddr*)&newAddr, &addr_size);
        if(newSocket < 0){
            exit(1);
        }
        // newSocket is connected to client!
        char newName[INET_ADDRSTRLEN]; // String to contain client address
        if (inet_ntop(AF_INET, &newAddr.sin_addr.s_addr, newName, sizeof(newName)) != NULL)
            printf("Handling client %s/ %d\n", newName, ntohs(newAddr.sin_port));
        else
            printf("Unable to get client address");

        //Handle concurrency by using fork
        if((childpid = fork()) == 0){
            close(sockfd);

            while(1){
                recv(newSocket, buffer, 1024, 0);
                    int i=0;
                    char *array[20];
                    char **reply = malloc(20*sizeof(char *));
                    char *p = strtok(buffer, ",");
                    while (p!=NULL) {
                        array[i++] = p;
                        p = strtok(NULL, ","); //stroke received string into tokens
                    }
                    for (i=0; i<20; i++) {
                        reply[i] = malloc(10*sizeof(char));
                        strcpy(reply[i], array[i]); //input tokens into array
                        printf("%s ", reply[i]);
                    }

                    send(newSocket, reply, 20*sizeof(char *), 0);
                    bzero(reply, sizeof(reply));
                //}
            }
        }

    }    
    close(newSocket);
    return 0;
}

Итак, как я могу исправить эту проблему, чтобы клиент мог распечатать ответ массива [], отправленный с сервера? Спасибо, совет

1 Ответ

0 голосов
/ 03 ноября 2018

OK. Ваш код дал понять, что вы не очень хорошо знаете C, гораздо меньше сокетов, но вот новая улучшенная версия, которая, я думаю, будет делать то, что вы хотите. Большинство моих улучшений были освещены в комментариях к исходной публикации. Я не проверял наличие ошибок везде, где это уместно, и во многих других отношениях это далеко от совершенства, но это будет делать то, что вы хотели, без срывов.

Вы отправляли данные, не зная, получили ли вы все, что было передано. Розетки - это потоки. Он отправляет данные, однако находит это наиболее удобным, а не так, как вы предпочитаете. Чтобы решить эту проблему, я потребовал, чтобы мы отправляли \n с каждой передачей. Мы проверяем \n и продолжаем читать данные каждый раз, когда получаем данные с другой стороны. После того, как я отправил множество данных ответа, я отправил один символ \n, чтобы клиент знал, что была получена полная строка. Нам не нужно добавлять \n от клиента, так как fgets оставляет \n в конце буфера.

Вы упомянули сортировку, так что в качестве дополнительного бонуса я добавил qsort, чтобы упорядочить данные. В функции compReply я не просто возвращаю значение непосредственно из strcmp, но помещаю его в int, чтобы при необходимости видеть его в отладчике. Я полагаю, что некоторые компиляторы будут жаловаться, что я делаю strcmp для двух void * переменных. Чтобы быть аккуратным, вы можете разыграть их с (char*)a, прежде чем передать их на strcmp.

Я удалил ваш fork, чтобы облегчить отладку. Извините, это позволит только одно соединение одновременно. Когда я пишу что-то вроде этого, я обычно не разветвляю новый процесс, а имею массив значений newSocket и использую select, чтобы решить, с какого из них читать. (Функцию select можно использовать и с accept.) Опять же, проще отлаживать таким образом.

Функция strtok заменяет найденный символ на ноль и возвращает указатель на начало строки. Я просто хотел удалить ненужные символы, поэтому я использовал его, не удосужившись принять возвращаемое значение. Это также можно было бы сделать с чем-то вроде:

char *p=strchr(buffer,'\n');
if( NULL != p ) *p=0;

Но strtok более лаконичен.

Я разрешил передавать номер порта на сервер, но не смог добавить его к клиенту. Ох, хорошо.

Я проверил сервер до того, как запустил клиент с

telnet 127.0.0.1 4444

и набрал: a,s,d,f,g,h,j,k,l <CR> чтобы вернуть отсортированный список a,d,f,g,h,j,k,l,s, Мне также не нравятся конечные запятые, но я не собираюсь сейчас их убирать.

Сервер:

#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 4444
#define BUF_SIZE 1024
static int compReply(const void *a, const void *b)
{
    int ret=strcmp(a,b);
    return(ret);
}
int main(int argc, char *argv[])
{
    int port=4444;
    int sockfd, ret;
    struct sockaddr_in serverAddr; // Local address

    int newSocket;
    struct sockaddr_in newAddr;

    socklen_t addr_size;

    if( argc > 1 ) {
        port=atoi(argv[1]);
        if( port < 1024 ) {
            port=4444;
        }
    }

    // Create socket for incoming connections
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if(sockfd < 0){
        printf("Error in connection.\n");
        exit(1);
    }
    printf("Server Socket is created.\n");

    // Construct local address structure
    memset(&serverAddr, '\0', sizeof(serverAddr));        // Zero out structure
    serverAddr.sin_family = AF_INET;                      // IPv4 address family
    serverAddr.sin_port = htons(PORT);                    // Local port
    serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);       // Any incoming interface

    // Bind to the local address
    ret = bind(sockfd, (struct sockaddr*)&serverAddr, sizeof(serverAddr));
    if(ret < 0){
        printf("Error in binding.\n");
        perror("bind");
        exit(1);
    }
    printf("Bind to port %d\n", port);

    // Mark the socket so it will listen for incoming connections
    if(listen(sockfd, 10) == 0){                 //Maximum outstanding connection requests is 10
        printf("Listening....\n");
    }else{
        printf("Error in listening.\n");
        perror("listen");
    }

    while(1){
        // Wait for clients to connect
        newSocket = accept(sockfd, (struct sockaddr*)&newAddr, &addr_size);
        if(newSocket < 0){
            exit(1);
        }
        // newSocket is connected to client!
        char newName[INET_ADDRSTRLEN]; // String to contain client address
        if (inet_ntop(AF_INET, &newAddr.sin_addr.s_addr, newName, sizeof(newName)) != NULL)
            printf("Handling client %s/ %d\n", newName, ntohs(newAddr.sin_port));
        else
            printf("Unable to get client address");

        while(1){
            char buffer[BUF_SIZE]={0};
            int ret=1;
            int count=0;
            while(NULL == strchr(buffer,'\n') && ret > 0 && count < sizeof(buffer))
            {
                ret=recv(newSocket, &buffer[count], sizeof(buffer)-count, 0);
                count+=ret;
            }
            if( ret <= 0 ) {
                if( ret < 0 ) {
                    printf("Problem with recv: %d\n", ret);
                }
                break;
            }
            printf("recv: %s\n", buffer);
            strtok(buffer,"\n\r"); /* throw away any \r\n */
            if( ret> 0 ) {
                int i=0;
                char reply[20][BUF_SIZE]={0};
                char *p = strtok(buffer, ",");
                while (p!=NULL) {
                    strncpy(reply[i],p,BUF_SIZE);
                    strcat(reply[i],",");
                    p = strtok(NULL, ","); //stroke received string into tokens
                    i++;
                }
                qsort(reply,i,BUF_SIZE,compReply);
                for(int jj=0; jj<i; jj++) {
                    printf("%s ", reply[jj]);
                    ret=send(newSocket, reply[jj], strlen(reply[jj]), 0);
                }
                ret=send(newSocket, "\n", 1, 0);
                printf("\n");
            }
        }

        close(newSocket);
    }
    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>
#include <string.h>

#define PORT 4444
#define BUF_SIZE 1024

int main(int argc, char *argv[])
{
    char servIP[120]="127.0.0.1";

    if( argc > 1 ) {
        strncpy(servIP,argv[1],sizeof(servIP));
    }

    int clientSocket, ret;
    struct sockaddr_in serverAddr; // Server address
    char buffer[BUF_SIZE];

    // Create a reliable, stream socket using TCP
    clientSocket = socket(AF_INET, SOCK_STREAM, 0);
    if(clientSocket < 0){
        printf("Error in connection.\n");
        exit(1);
    }
    printf("Client Socket is created.\n");

    // Construct the server address structure
    memset(&serverAddr, '\0', sizeof(serverAddr)); // Zero out structure
    serverAddr.sin_family = AF_INET;               // IPv4 address family
    serverAddr.sin_port = htons(PORT);             // Server port
    // Convert address
    int rtnVal = inet_pton(AF_INET, servIP, &serverAddr.sin_addr.s_addr);
    if (rtnVal == 0)
        printf("inet_pton() failed: invalid address string");
    else if (rtnVal < 0)
        printf("inet_pton() failed");

    // Establish the connection to the sorted server
    ret = connect(clientSocket, (struct sockaddr*)&serverAddr, sizeof(serverAddr));
    if(ret < 0){
        printf("Error in connection.\n");
        exit(1);
    }
    printf("Connected to Server.\n");

    //Read arrays from input file
    FILE *fptr;
    fptr = fopen("this.csv", "r"); //open input file to read
    if (fptr != NULL) {
        while(fgets(buffer, sizeof(buffer), fptr))    //read line by line of the input file
        {
            char reply[BUF_SIZE]={0};
            char repList[20][BUF_SIZE]={0};
            int count=0;
            int ret=1;
            printf("Unsorted array: %s", buffer);
            // Send array to the server
            send(clientSocket, buffer, strlen(buffer), 0);
            // Receive the sorted arrays back from the server
            while(NULL == strchr(reply,'\n') && ret > 0 && count < sizeof(reply))
            {
                ret=recv(clientSocket, &reply[count],sizeof(reply)-count,0);
                count+=ret;
            }
            if( ret < 0 ) {
                printf("Error in receiving data.\n");
            }
            else {
                int i=0;
                strtok(reply,"\n\r");
                for(char *p=strtok(reply,",");p!=NULL; p=strtok(NULL,","))
                {
                    strncpy(repList[i],p,BUF_SIZE);
                    i++;
                }
                printf("Sorted array:");
                for (int jj=0; jj<i; jj++) {
                    printf("%s ", repList[jj]);
                }
            }
            printf("\n");
        }
        fclose(fptr);
    }
    else {
        printf("File does not exist");
        perror("fopen");
        exit(1);
    }
    return 0;
}

Это должно дать вам кое-что, с чем можно поэкспериментировать. Надеюсь, это поможет.

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