c - 多次发送,多次接收

标签 c sockets tcp

我对 TCP/IP 套接字编程非常非常非常陌生。 client.c 有 2 个 argv 值 我需要将这两个发送到 server.c

我想如果我从client.c中send()两次并在server.c中recv两次,那就可以了,但实际上并非如此。谁能告诉我如何将两个缓冲区发送到 server.c 中?

在client.c

ssize_t byteNumSentAccName = send(clientSock, accountName, strlen(accountName), 0);
ssize_t byteNumSentCmd = send(clientSock, command, strlen(accountName), 0);

其中 accountName 和 command 都是字符缓冲区。

在server.c中

ssize_t byteNumRecvAccName = recv(clientSock, nameBuf, BUFSIZE-1, 0);
  ssize_t byteNumRecvCmd = recv(clientSock, cmdBuf, BUFSIZE-1, 0);

最佳答案

TCP 是字节流,send()recv() 之间不存在 1:1 关系,如 UDP 中那样。

在 TCP 中,send() 可以发送比请求更少的字节,而 recv() 可以返回比请求更少的字节。因此,您需要循环调用它们,直到发送/接收所有字节。您需要以这样一种方式构建数据,以便接收者知道一个值在哪里结束以及下一个值在哪里开始。例如,当发送可变长度字符串时,您可以

  • 在发送实际字符串字符之前,将字符串长度作为固定宽度整数发送。然后接收方可以先读取长度,然后再读取,直到接收到指定数量的字符为止。
bool sendRaw(int sock, const void *data, int size)
{
    const char *buffer = (const char*) data;
    while (size > 0)
    { 
        ssize_t sent = send(sock, buffer, size, 0);
        if (sent < 0)
            return false;
        buffer += sent;
        size -= sent;
    }
    return true;
}

bool sendInt32(int sock, int32_t value)
{
    value = htonl(value);
    return sendRaw(sock, &value, sizeof(value));
}

bool sendString(int sock, const char *s)
{
    int32_t len = strlen(s);
    if (!sendInt32(sock, len))
        return false;
    return sendRaw(sock, s, len);
}

...

sendString(clientSock, accountName);
sendString(clientSock, command);
int readRaw(int sock, void *data, int size)
{
    char *buffer = (char*) data;
    while (size > 0)
    { 
        ssize_t recvd = recv(sock, buffer, size, 0);
        if (recvd < 0)
            return -1;
        if (recvd == 0)
            return 0;
        buffer += recvd;
        size -= recvd;
    }
    return 1;
}

int readInt32(int sock, int32_t *value)
{
    int ret = readRaw(sock, value, sizeof(*value));
    if (ret == 1)
        *value = ntohl(*value);
    return ret;
}

char* readString(int sock)
{
    int32_t len = 0;
    if (readInt32(sock, &len) <= 0)
        return NULL;

    char *ret = (char*) malloc(len+1);
    if (!ret)
        return NULL;

    if (readRaw(sock, ret, len) <= 0)
    {
        free(ret);
        return NULL;
    }

    ret[len] = '\0';
    return ret;
}

...

nameBuf = readString(clientSock);
cmdBuf = readString(clientSock);
...
free(nameBuf);
free(cmdBuf);
  • 在发送实际的字符串字符后发送一个唯一的分隔符(空终止符、换行符,任何你想要的,只要它永远不会出现在字符串中)。然后接收者可以读取,直到收到该分隔符。
bool sendRaw(int sock, const void *data, int size)
{
    const char *buffer = (const char*) data;
    while (size > 0)
    { 
        ssize_t sent = send(sock, buffer, size, 0);
        if (sent < 0)
            return false;
        buffer += sent;
        size -= sent;
    }
    return true;
}

bool sendString(int sock, const char *s)
{
    int32_t len = strlen(s) + 1;
    return sendRaw(s, len);
}

sendString(clientSock, accountName);
sendString(clientSock, command);
int readRaw(int sock, void *data, int size)
{
    char *buffer = (char*) data;
    while (size > 0)
    { 
        ssize_t recvd = recv(sock, buffer, size, 0);
        if (recvd < 0)
            return -1;
        if (recvd == 0)
            return 0;
        buffer += recvd;
        size -= recvd;
    }
    return 1;
}

char* readString(int sock)
{
    char *ret = NULL, *tmp;
    size_t len = 0, cap = 0;
    char ch;

    do
    {
        if (readRaw(sock, &ch, 1) <= 0)
        {
            free(ret);
            return NULL;
        }

        if (ch == '\0')
            break;

        if (len == cap)
        {
            cap += 100;
            tmp = (char*) realloc(ret, cap);
            if (!tmp)
            {
                free(ret);
                return NULL;
            }
            ret = tmp;
        }

        ret[len] = ch;
        ++len;
    }
    while (true);

    if (len == cap)
    {
        tmp = (char*) realloc(ret, cap+1);
        if (!tmp)
        {
            free(ret);
            return NULL;
        }
        ret = tmp;
    }

    ret[len] = '\0';    
    return ret;
}

...

nameBuf = readString(clientSock);
cmdBuf = sendString(clientSock);
...
free(nameBuf);
free(cmdBuf);

关于c - 多次发送,多次接收,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58019804/

相关文章:

python - 带有 Python : How to optimize my implementation? 的 TCP 服务器

c - 在 C 中使用 FFTW 的高通滤波器

c - C 中结构体的 Malloc 数组

c - Unsigned/Signed Arthmetic Problems from A Programmer's Perspective 教科书

java - Java Sockets 默认实现什么 ARQ 协议(protocol)?

c++ - 在 C++ 中通过 UDP 发送字符串

c - 关系数据库和查询

c# - 在 C# 中实现所有端口扫描技术/在 C# 中创建原始低级数据包

security - CRC 是否有助于防止安全攻击或保证数据的完整性?

tcp - Spring 集成。 TCP 服务器工厂