【问题标题】:Recv() function messing up other parts of my codeRecv() 函数弄乱了我代码的其他部分
【发布时间】:2020-08-18 03:38:59
【问题描述】:

我正在尝试使用客户端服务器设置执行 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; 
} 

这里是服务端的main方法:

#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;
}

几点说明:

我知道在这段特定的代码中我没有使用客户端发送的单词,因此为什么有些行是 cmets,当我的问题得到解决时,我将实现这一点。

我正在使用popen(),因为我想返回catgrep() 的输出。

我隔离了问题,而不是仅在包含 recv() 函数时才发生。

当我使用recv() 时,正在打印我发送的单词,因此该函数不会导致错误,但会弄乱其他部分。

更新:

根据 cmets 中某人的建议,我更改了接收客户发送的单词的方式,我现在使用以下内容:

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()");
}

仍然有同样的问题和同样的输出。

【问题讨论】:

  • 你能修正一下代码的缩进吗?读起来不容易。
  • @RobertoCaboni 现在好点了吗?
  • 我已经编辑了代码。现在它是。无论如何,我看到你已经得到了一个(明智的)答案。

标签: c sockets recv


【解决方案1】:

基本问题是您混淆了字符串和字节流——它们不是一回事。

在您的客户端中,您发送一些数据:

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

这会将一行(包括换行符)读入堆栈缓冲区的开头,然后发送整个缓冲区,包括缓冲区结束后发生的任何垃圾细绳。你可能不想要换行符,也许不想要 NUL 终止符,当然也不想要垃圾。

此外,对于短发送,您不会检查 send 的返回值——在某些(非常罕见的)情况下,发送可能不会发送您请求的所有数据。

在阅读方面,您不会检查 recv 的返回值来查看您获得了多少字节,这可能与您的预期不同——没有保证发送之间会有 1:1 的对应关系并在连接上调用 recv。一个发送可能会被分解并拆分为多个接收,并且多个发送可能会将它们的数据合并并在一个接收中返回。所以你总是需要检查 recv 的返回值,看看你实际得到了多少字节。

【讨论】:

  • 我的意思是检查发送和接收值如何使代码的其他部分工作?为了不发送垃圾,还需要在发送/接收方面进行哪些更改
  • @ayrebelcoding 你必须写循环。假设您有 N 个字节要接收。将 recv 的结果存储在一个变量中,检查它不是 -1(错误),因此它们是实际接收到的字节。从 N 中减去它并重复 recv 期望差异。重复直到收到所有字节。
  • 但最重要的建议是第一个。您不能确定 fgets 会读取 30 个字符(尤其是最多接收 29 个字符)。所以不要发送 30 个字符,而是 strlen (word) 个字符。
  • @RobertoCaboni 当我正确接收到单词时,这将如何解决我的问题?如果我发送一个单词,接收它,打印它,它将正确打印。您介意解释并包含示例代码,因为我可能会误解您的意思吗?
  • 我实施了给定的更改,但仍然得到相同的结果
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-12-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多