如何使用recv接收长文本字符串

时间:2014-02-23 18:25:57

标签: c linux send recv unix-socket

我正在尝试创建一个服务器和客户端程序,它从客户端向服务器发送字符串,服务器在该服务器上执行该字符串并将输出发送回客户端。我在linux中这样做,我很困惑为什么我的程序不能正常工作。这是代码。

**Client**
int main()
{
    //Code to use unix socket here

    if (connect(s, (struct sockaddr *)&remote, len) == -1) {
        perror("connect");
        exit(1);
    }

    printf("Connected.\n");

    while(printf("> "), fgets(str, MAX, stdin), !feof(stdin)) {
        if (send(s, str, strlen(str), 0) == -1) {
            perror("send");
            exit(1);
        }
    }
    done=0;
    do {
        if(t=recv(s, str, MAX, 0)<0)
            perror("recv failed at client side!\n");
        str[t] = '\0';
        if(strcmp(str, "ENDOFTRANS")==0)
        {
            printf("\nRead ENDOFTRANS. Breaking loop.\n");
            done=1;
        }
        printf("Server > %s", str);
    } while(!done);
}

然后服务器代码是:

**Server**

#define MAX 1000
int main(void)
{
//Unix socket code

//This process is now a daemon.
daemon();


//Listens for client connections, up to 5 clients can queue up at the same time.
if (listen(s, 5) == -1) {
    perror("listen");
    exit(1);
}

for(;;) {
    int done, n, status;

    printf("Waiting for a connection...\n");
    t = sizeof(remote);

    if ((newsock= accept(s, (struct sockaddr *)&remote, &t)) == -1) {
            perror("accept");
            exit(1);
    }

            printf("Connected.\n");

    done = 0;
    do {
        switch(fork())
        {
            case -1:  //ERROR
            perror("Could not fork.\n");
            break;

            case 0:  //CHILD

            //Accept string from client.
            //Edit: Why am I getting an error here? says: Invalid argument.
            if(n = recv(newsock, str, MAX, 0)) {
                 perror("Recv error at server side.\n");
                 exit(1);
            }
            str[n]='\0';
            if (n <= 0) {
                if (n < 0)
                    perror("recv");
                done = 1;
            }
            printf("String=>%s<",str);

            //Redirect socket to STDOUT & STDERR.
            test = close(WRITE);        assert(test==0);
            test = dup(newsock);        assert(test==WRITE);
            test = close(ERROR);        assert(test==0);
            test = dup(newsock);        assert(test==ERROR);



            if (!done)
            {
                if (str==something)
                {
                    //execute command
                }

                else {
                    //Fork and execvp the command
                }

                //Sends End of Transaction character.
                ENDTHETRANS();
                exit(0);
            }
            break;

            default:  //PARENT
                //Parent keeps accepting further clients.
                wait(&status);
                if ((newsock= accept(s, (struct sockaddr *)&remote, &t)) == -1) {
                    perror("accept");
                    exit(1);
                }

                printf("Connected.\n");
                done=1;
                break;

        }
    } while (!done);
}
close(s);
}

我对编程一般都比较新,根据我的理解,客户端代码很好,只是当它从服务器收回文本时它只收到小位文本(一次2行)。我必须继续按下客户端promt上的输入以获得剩余的输入。我已经尝试了很多东西,到目前为止我甚至都不知道自己做错了什么。

首先,在服务器代码中,在从客户端收到字符串后,我有一个输出字符串的printf("String=>%s<",str);。但是,当服务器将输出打印为String=>ls -l时,最后的<键会以某种方式被吃掉。它不应该这样做吗?

任何帮助非常感谢。请记住,我是一名初学者,之前只使用过管道作为进程间通信。现在我想制作我的第一个unix socket程序。

提前致谢。

1 个答案:

答案 0 :(得分:2)

在这种情况下的常见问题是没有意识到SOCK_STREAM套接字不保留消息边界。因此,通过send调用发送的数据可能会被分割并在多个recv中收到,或者可能会合并,而多个send最终会在一个recv中结束。最重要的是,当内核发送缓冲区填满时,send调用可能会写入部分数据(仅发送一些请求的数据)并返回一个短的返回值。您需要对此进行测试并重新发送其余数据。

经常出现的另一个问题是行结尾的问题(特别是在linux和windows之间进行交谈时)。客户端或服务器中可能存在额外的回车字符(\r),这会混淆另一方。这些在打印时往往会导致输出明显丢失或截断。

修改

该行

if(t=recv(s, str, MAX, 0)<0)

相当于

if(t = (recv(s, str, MAX, 0)<0))

即,根据是否存在错误,将t设置为0或1。与此类型的大多数错误一样,打开警告会给你一些指示。