【问题标题】:Receiving multiple TCP segments接收多个 TCP 段
【发布时间】:2017-05-02 01:33:03
【问题描述】:

我有一个任务,其中 TCP 客户端以如下形式向 TCP 服务器发送数据:

IP地址\0端口\0消息\n

现在,当我通过这样的终端发送一些数据时,服务器(IP 地址 10.0.2.15)可以正常接收数据包:

printf "127.0.0.1\0004444\000Some message\n" | nc -N 10.0.2.15 3333

然而,任务的第二部分是读取一个分多段进来的数据包:

(printf "127.0.0.1"; sleep 0.3; printf "\0004444\000"; sleep 0.3; \
printf "It works"; sleep 0.5; printf "\n") | nc -N 10.0.2.15 3333

我应该如何在服务器上实现读取功能,以便尽可能将所有段存储到缓冲区中?

【问题讨论】:

  • 如果它没有分成多个部分,你将如何实现它?有什么区别吗?请注意,您事先并不知道消息的长度。
  • @n.m.我会使用这样的简单读取功能:pastebin.com/RjVdVKmS
  • 什么是BUF_SIZE? 你事先并不知道消息的长度
  • 所以在不知道长度的情况下无法接收多段消息? BUF_SIZE 是消息的最大允许大小(本例中为 512 字节)。
  • 也许检查消息中是否存在\n。还有什么办法?

标签: c sockets tcp


【解决方案1】:

recv() 返回的字节数可以少至 1 字节,多至请求的字节数。 TCP 是字节流,没有消息的概念,必须在应用程序代码中处理。

接收者必须知道需要多少字节,然后循环读取,直到它读取了那么多字节,不管它需要多少次读取。

但是,在这种情况下,接收方不知道消息的确切长度,因为发送方在发送消息本身之前并没有发送消息长度,所以唯一可用的选项是接收方从套接字读取逐字节直到遇到终止的\n

例如:

int readLine(int socket, char **line)
{
    int r, len = 0, cap = 256;
    char b;

    *line = NULL;

    char *outline = (char*) malloc(cap);
    if (!outline) return -2;

    do
    {
        r = recv(socket, &b, 1, 0);
        if (r <= 0)
        {
            free(outline);
            return r;
        }

        if (b == '\n')
            break;

        if (len == cap)
        {
            cap += 256;
            char *newline = (char*) realloc(outline, cap);
            if (!newline)
            {
                free(outline);
                return -2;
            }
            outline = newline;
        }

        outline[len] = b;
        ++len;
    }
    while (true);

    if ((len > 0) && (line[len-1] == '\r'))
        --len;

    if (len == cap)
    {
        char *newline = (char*) realloc(outline, cap + 1);
        if (!newline)
        {
            free(outline);
            return -2;
        }
        outline = newline;
    }

    outline[len] = '\0';

    *line = outline;

    return 1;
}

char *line;
int r;

do
{
    r = readLine(cliSock, &line);
    if (r <= 0)
    {
        if (r == 0)
            printf("client disconnected\n");
        else if (r == -2)
            printf("memory error\n");
        else
            printf("read error\n");
        break;
    }

    // process line as needed...

    free(line);
}
while (true);

或者,您可以使用中间缓冲区来帮助您在读取之间缓存数据并更有效地从套接字中获取数据:

char *buffer;
int buflen, bufcap;

int readLine(int socket, char **line)
{
    char *ptr;
    int r, idx = 0;

    *line = NULL;

    do
    {
        ptr = memchr(buffer + idx, '\n', buflen - idx);
        if (ptr)
        {
            int total = ((ptr + 1) - buffer);

            int len = (total - 1);
            if ((len > 0) && (buffer[len-1] == '\r'))
                --len;

            *line = (char*) malloc(len + 1);
            if (*line == NULL)
                return -2;

            memcpy(*line, buffer, len);
            (*line)[len] = '\0';

            if (total < buflen)
                memmove(buffer, buffer + total, buflen - total);
            buflen -= total;

            break;
        }

        if (buflen == bufcap)
        {
            int newcap = bufcap + 256;
            char *newbuffer = (char*) realloc(buffer, newcap);
            if (!newbuffer)
                return -2;
            buffer = newbuffer;
            bufcap = newcap;
        }

        r = recv(socket, buffer + buflen, bufcap - buflen, 0);
        if (r <= 0)
            return r;

        buflen += r;
    }
    while (true);

    return 1;
}

buflen = 0;
bufcap = 256;
buffer = (char*) malloc(bufcap);
if (buffer)
{
    char *line;
    int r;

    do
    {
        r = readLine(cliSock, &line);
        if (r <= 0)
        {
            if (r == 0)
                printf("client disconnected\n");
            else if (r == -2)
                printf("memory error\n");
            else
                printf("read error\n");
            break;
        }

        // process line as needed...

        free(line);
    }
    while (true);

    free(buffer);
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-17
    • 1970-01-01
    • 2016-11-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多