Функция Recv () портит другие части моего кода - PullRequest
0 голосов
/ 03 мая 2020

Я пытаюсь выполнить cat | grep, используя настройку клиентского сервера, работает следующим образом: клиент отправляет слово для поиска с использованием grep, сервер выполняет cat | grep, отправляет результаты клиенту, но, похоже, функция recv() испортить мой код

В чем проблема?

Добавление функции recv() делает другие части моего кода не работающими, каждый puts() работает до puts("test5");, где мой код застревает в выполнении помещение функции recv() в качестве комментария делает код работоспособным.

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

Вот соответствующая клиентская часть:

#include <stdio.h> 
#include <sys/socket.h> 
#include <arpa/inet.h> 
#include <unistd.h> 
#include <string.h> 
#include <stdlib.h>
#include<errno.h>

#define PORT 8080

int main(int argc, char const *argv[]) 
{ 
    int sock = 0, valread; 
    struct sockaddr_in serv_addr; 
    int buffer[1024];
    char buffer2[1024]={0};
    if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) 
    { 
        printf("\n Socket creation error \n"); 
        return -1; 
     } 

    serv_addr.sin_family = AF_INET; 
    serv_addr.sin_port = htons(PORT);        

    if(inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr)<=0)  
    { 
        perror("Invalid address \n"); 
        return -1; 
    } 

    if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) 
    { 
        perror("Connection Failed \n"); 
        return -1; 
    } 

    int i, array[argc], countsize=0;
    if(argc>=2)
    {
        for(i=1; i<argc; i++)
        {
            int number=atoi(argv[i]);
            array[i-1]=number;
            countsize++;
        }

        if(send(sock, array, countsize*sizeof(int), 0)<0)
        {
            printf("Error in send! %s\n", strerror(errno));
           return -1; 
        }

        if(argc>=2)
        {
             int i=0;
             for(int i=0; i<argc; i++) 
            {
                if(atoi(argv[i])==6)
                {
                    puts("Please enter the name/word you want to search for in the history file: ");
                    char word[30];
                    fgets(word, 30, stdin); 
                    if(send(sock, &word , 30, 0)<0)
                        printf("Error in send! %s\n", strerror(errno));

                    valread = read( sock , buffer2, 1024); 
                    puts("The result cat|grep is:");
                    printf("%s\n", buffer2);
                }
            }  
        }
    }      
    return 0; 
} 

Вот основной метод сервера:

#include <stdio.h> 
#include <unistd.h> 
#include <sys/socket.h> 
#include <stdlib.h> 
#include <netinet/in.h> 
#include <string.h> 
#include<errno.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdbool.h>
#include <sys/wait.h>
#include<time.h> 
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <pthread.h>
#include <arpa/inet.h> 

#define PORT 8080
void *catgrep(void *);

int main() 
{ 
    int server_fd, new_socket;
    struct sockaddr_in address; 
    int opt = 1; 
    int addrlen = sizeof(address); 
    char buffer2[1024]={0};

    if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) 
    { 
        perror("socket failed"); 
        exit(EXIT_FAILURE); 
    }        

    if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR , &opt, sizeof(opt))) 
    { 
        perror("setsockopt"); 
        exit(EXIT_FAILURE); 
    } 
    address.sin_family = AF_INET; 
    address.sin_addr.s_addr = INADDR_ANY; 
    address.sin_port = htons( PORT );       

    if (bind(server_fd, (struct sockaddr *)&address, sizeof(address))<0) 
    { 
        perror("bind failed"); 
        exit(EXIT_FAILURE); 
    } 

    while (1)
    {
        if (listen(server_fd, 20) < 0) 
        { 
            perror("listen"); 
            exit(EXIT_FAILURE); 
        } 
        if ((new_socket = accept(server_fd, (struct sockaddr *)&address,(socklen_t*)&addrlen))<0) 
        { 
            perror("accept"); 
            exit(EXIT_FAILURE); 
        } 

        int arguments[10]={0};
        int n = recv(new_socket, arguments ,1024*sizeof(int),0);
    int j;

        int argumentsize=n/sizeof(int);
        for(j=0; j<argumentsize;j++)
        {
            if(arguments[j]==6)
            {
                pthread_t th5;
                pthread_attr_t attr5;
                pthread_attr_init(&attr5);

                if(pthread_create(&th5,&attr5, catgrep,&new_socket)!=0)
                {
                    printf("Error in pthread_create %s\n", strerror(errno));
                    return -1; 
                }
                pthread_join(th5, NULL);
               return -1; 
           }
        } 
        close(new_socket);
    }
    close(server_fd);
    return 1;
}

Вот мой catgrep() метод:

void *catgrep(void * param)
{
    int *sock = (int*) param;
    int new_sock = *sock;

    int fd[2];
    pipe(fd);
    pid_t pid = fork(); 
    char word[30];
    recv(new_sock, word ,30, 0); //when I put this line code 
    starts messing up. 
    puts(word);

    if(pid==0)
    {
        close(1);
        dup(fd[1]);
        close(fd[0]);
        close(fd[1]);
        char *cat_args[] = {"/bin/cat", "GameData.txt", NULL};
        if(execv(cat_args[0], cat_args)<0)
        {
            printf("Error in execv! %s\n", strerror(errno));
        }
       exit(0);
    }

    if(pid > 0)
    {
        close(0);
        dup(fd[0]);
        close (fd[1]);
        close(fd[0]);

        puts("test2");
        FILE *fp2;
        if ((fp2 = popen("grep -w tries", "r")) == NULL)
        {
            perror("popen failed");
            return NULL;
        }
        puts("test3");
        size_t str_size = 1024;
        char *stringts2 = malloc(str_size);
        if (!stringts2)
        {
            perror("stringts allocation failed");
            return NULL;
        }
        puts("test4");

        stringts2[0] = '\0';
        char buf[128];
        size_t n;
        puts("test5"); //when I use the recv() program gets stuck here. 

        while ((n = fread(buf, 1, sizeof(buf) - 1, fp2)) > 0)
        {
            puts("test10");
            buf[n] = '\0';
            size_t capacity = str_size - strlen(stringts2) - 1;
            while (n > capacity)
            {
                str_size *= 2;
                stringts2 = realloc(stringts2, str_size);
                if (!stringts2)
                {
                    perror("stringts realloation failed");
                    return NULL;
                }
                capacity = str_size - strlen(stringts2) - 1;
            }
            strcat(stringts2, buf);
        }

        puts("test6");

        if (pclose(fp2) != 0)
        {
            perror("pclose failed");
            return NULL;
        }
        puts("test7");

        if(send(new_sock, stringts2, 10000, 0)<0)
        {
            printf("Error in send! %s\n", strerror(errno));
        }
    }
    return NULL;
}

Несколько замечаний:

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

Я использую popen(), так как я хочу вернуть вывод catgrep().

Я изолировал проблему, и не только, когда я включаю функцию recv().

Слово, которое я посылаю, печатается, когда я использую recv(), поэтому функция не вызывает ошибок, но портит другие части.

ОБНОВЛЕНИЕ:

По предложению кого-то в комментариях я изменил способ получения слова, отправленного моим клиентом, теперь я использую следующее:

int count = 0;
int total = 0;

while ((count = recv(new_sock, &word[total], sizeof word - count, 0)) > 0)
{
    total=total+count;
}
if (count==-1)
{
    perror("error in recv()");
}

У меня все та же проблема и тот же результат.

1 Ответ

2 голосов
/ 03 мая 2020

Основная проблема c в том, что вы путаете строки и потоки байтов - это не одно и то же.

В вашем клиенте вы отправляете некоторые данные с:

        char word[30];
        fgets(word, 30, stdin); 
        if(send(sock, &word , 30, 0)<0)

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

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

На стороне чтения вы не проверяете возвращаемое значение recv, чтобы увидеть, сколько байт вы получили. , что может отличаться от того, что вы ожидаете - нет никакой гарантии, что между вызовами send и recv в соединении будет соответствие 1: 1. Одна отправка может быть разбита и разделена между несколькими recvs, и несколько посылок могут объединить свои данные и вернуть в одну recv. Поэтому вам всегда нужно проверять возвращаемое значение recv, чтобы увидеть, сколько байтов вы на самом деле получили.

...