【问题标题】:Send/Read using a TCP socket, anomalies in the byte sizes使用 TCP 套接字发送/读取,字节大小异常
【发布时间】:2014-05-28 20:27:47
【问题描述】:

我正在尝试实现一个有效的 HTTP 客户端-服务器应用程序,只是为了练习网络编程。
这两个程序必须遵循这个基本算法:
客户端 - 发送 GET 请求
服务器 - 发送“+OK\r\n”
服务器 - 以字节为单位发送文件大小
服务器 - 发送文件
客户端 - 发送 ACK

我在读取部分遇到了很多麻烦,可能是因为我对流执行了一些脏读操作。

这些是我正在使用的 2 个阅读功能:

/* Reads a line from stream socket s to buffer ptr
The line is stored in ptr including the final '\n'
At most maxlen chasracters are read*/
int readline (SOCKET s, char *ptr, size_t maxlen)
{
    size_t n;
    ssize_t nread;
    char c;

    for (n=1; n<maxlen; n++)
    {
        nread=recv(s, &c, 1, 0);
        if (nread == 1)
        {
            *ptr++ = c;
            if (c == '\n')
                break;
        }
        else if (nread == 0)    /* connection closed by party */
        {
            *ptr = 0;
            return (n-1);
        }
        else            /* error */
            return (-1);
    }
    *ptr = 0;
    return (n);
}

和:

int readNumber(SOCKET s, long *num, int maxRead)
{
    size_t n;
    ssize_t nread;
    int totRead;
    long number=0;
    for (n=1; n<maxRead+1; n++)
    {
        nread=recv(s, &number, sizeof(number), 0);
        if (nread == sizeof(number))
        {
            totRead+=nread;
            *num = number;
        }
        else if (nread == 0)    /* connection closed by party */
        {
            *num = 0;
            return (n-1);
        }
        else            /* error */
        {
            printf("nread = %d\n", nread);
            return (-1);
        }
    }
    return (totRead);
}

这是我收到+OK消息的主要sn-p,然后是文件大小:

    memset(rbuf,0,sizeof(rbuf));     //rbuf is the buffer where is store the read
    printf("waiting for response...\n");
    result = readline(s, rbuf, sizeof(rbuf));  //reading function is above
    printf("Byte read(okMsg) = %d\n", result);
    if (result <= 0)  
    //ERROR MANAGEMENT
    {
         printf("Read error/Connection closed\n");  
         closesocket(s);
         SockCleanup();
         exit(1);
    }
    else
    {
        long fileLength=0;
        unsigned char *fBuf;
        //RECEIVE OK
        if(!strcmp(rbuf,"+OK\r\n"))
        {
            puts("+OK\n");
            //RECEIVE FILE LEN
            int nw = readNumber(s, &fileLength, 1);  //reading function is above
            printf("Byte read(fDim) = %d\n", nw);
            printf("File is %ld bytes long\n", fileLength);
            if(nw >0)
            {
                // RECEIVE FILE

            }
        }
    }

当我发送“+OK\r\n”字符串时,服务器告诉我它发送了 8 个字节,但是当我阅读时,我发现 '\0' 字符仅在 6 个字节之后。 顺便说一句,它正确读取了消息,但是当我尝试读取文件大小(很长)时,它给了我一个错误的数字。
我的观点是流缓冲区很脏,我正在读取不属于文件大小的 2 个字节,但我不明白为什么会发生这种情况。

如果我不够清楚,请询问我更多信息。

已解决:
谢谢大家的答案!!! 你让我有正确的心态去理解哪里出了问题。
看起来问题是服务器中的这个声明:

char *okMsg = "+OK\r\n";

而不是

char okMsg[] = "+OK\r\n";

这导致我出现未定义的行为。

【问题讨论】:

  • 您必须记住 TCP 是一种流协议。这意味着对recv 的调用可能会返回少于请求的字节数。这是您的readNumber 函数可能无法按预期工作的一个原因。但更大的原因是当您使用未初始化的局部变量(更具体地说是totRead)时,其中包含undefined behavior
  • "+OK\r\n" 是 5 个字节,而不是 8 个字节,因此您可能想弄清楚为什么您的服务器给您一个错误的报告。
  • 我一直相信,每当我不初始化变量时,它都会隐式初始化为零,请问您能否举一个我的代码中未定义行为的示例?
  • 在函数中声明一个局部变量并打印它,这就是验证行为所要做的一切。全局变量和静态变量是零初始化的,但不是普通的局部变量。
  • 我想指出您的 readline 循环非常简单,但也可能是读取数据性能最差的方式。您正在为每个角色调用 recv 。那是系统调用。系统调用会占用大量 CPU 周期。更好的方法是使用缓冲并一次读取 4K 或更多的套接字。

标签: c sockets tcp send recv


【解决方案1】:
long number=0;
for (n=1; n<maxRead+1; n++)
{
    nread=recv(s, &number, sizeof(number), 0);

您忘记设计和实现一个协议来在您的服务器和您的客户端之间传输数据。因为 TCP 提供字节流,所以你的协议应该定义为字节流。

多少字节传达这个数字? “在我的平台上,一个‘长’恰好占据了多少字节”是一个好的答案吗?第一个字节的语义是什么? “无论 'long' 的第一个字节在我的平台上是什么意思”是一个好的答案吗?

的答案是,“大小应以 4 字节无符号整数以 little-endian 字节顺序传送”。然后确保您的代码以该格式发送和接收。

【讨论】:

    猜你喜欢
    • 2017-03-14
    • 1970-01-01
    • 1970-01-01
    • 2010-12-13
    • 1970-01-01
    • 1970-01-01
    • 2015-01-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多