c - 在套接字上写入和读取返回不同的字节数

标签 c sockets

我正在编写一个使用 AF_UNIX 套接字的客户端-服务器应用程序。 客户端生成一个字符串,然后在发送 header 后将其发送到套接字上。然后服务器读取 header ,为字符串分配空间,然后读取字符串。

header 定义为:

typedef struct {
    unsigned long key;
    op_t op; // op_t is an enum
} header_t;

字符串及其长度被存储:

typedef struct {
    unsigned int len;
    char* buf;
} data_t;

还有另一个结构将这两个东西组合成一个(不是我的选择,我必须按原样使用这些东西)。

typedef struct {
    header_t hdr;
    data_t data;
} message_t;

我正在使用 writev() 系统调用通过套接字发送数据,如下所示:

int sendRequest(long fd, message_t *msg) {
    struct iovec to_send[3];
    /* Header */
    to_send[0].iov_base = &(msg->hdr);
    to_send[0].iov_len = sizeof(header_t);

    /* Data */
    to_send[1].iov_base = &(msg->data.len);
    to_send[1].iov_len = sizeof(msg->data.len);

    to_send[2].iov_base = msg->data.buf;
    to_send[2].iov_len = msg->data.len;

    int c;
    if((c = writev(fd, to_send, (msg->data.len > 0) ? 3 : 2)) < 0) {
        return -1;
    }
    printf("#### %i BYTES WRITTEN (header: %i) ####\n",c, to_send[0].iov_len);

    return 0;
}

为了读取,我使用两个不同的函数,一个用于读取标题,一个用于读取数据:

int readHeader(long fd, header_t *hdr) {
    struct iovec to_read[1];

    to_read[0].iov_base = hdr;
    to_read[0].iov_len = sizeof(header_t);

    errno = 0;
    int c;
    if((c = readv(fd, to_read, 1)) <= 0) {
        return -1;
    }
    printf("[H] %i BYTES READ \n",c);

    return 0;
}

int readData(long fd, data_t *data) {
    struct iovec to_read[2];
    /* First, read how long is the buffer */
    to_read[0].iov_base = &(data->len);
    to_read[0].iov_len = sizeof(data->len);

    int c;
    if((errno = 0, c = readv(fd, to_read, 1)) <= 0)
        return -1;

    if(data->len > 0) {
        data->buf = calloc(data->len, sizeof(char));
        if(data->buf == NULL)
            return -1;
        /* Read the string */
        to_read[1].iov_base = data->buf;
        to_read[1].iov_len = data->len;

        if((errno = 0, c += readv(fd, &to_read[1], 1)) <= 0) {
            free(data->buf);
            return -1;
        }
    }
    else {
        data->buf = NULL;
    }
    printf("[D] %i BYTES READ (%i + %i)",c, to_read[0].iov_len, to_read[1].iov_len);

    return 0;
}

问题来了。 如果我发送一个 8193 字节长的字符串,则客户端上一切正常,输出 写入 8213 字节( header :16) 这是正确的,因为 16 个字节来自 header ,4 个字节来自 len 字段,8193 来自字符串。 但服务器打印出这样的信息: [H] 16 字节读取(好的),然后[D] 8176 字节读取(错误!)。因此,还剩 21 个字节可供读取。为什么?如果我尝试发送长度为 8192 或更短的字符串,则一切正常。假设 readv() 可以读取的字节数有限制,那么读取所写入的所有内容的正确方法是什么?

最佳答案

what is the correct way to read everything that was written?

不保证 readv 会立即返回所有数据。如果第一次读取没有返回所有请求的字节,那么您需要再次调用 read/readv 来获取其余的字节。

关于c - 在套接字上写入和读取返回不同的字节数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37378296/

相关文章:

c - 使用哪个IPC我可以将文件描述符从一个进程传递到同一台机器上的另一个进程?

c - scanf() 中不同数量的元素

Java Socket - 如何捕获 BufferedReader.readline() 的异常

c - 无需轮询即可读取多条 UDP 消息

PHP 套接字连接到 TCP 服务器

c - 在 C 中添加/删除链接列表中的节点

C - undefined reference - 除了使用 -lm 进行编译之外,还有其他选择吗?

C Shell 打开文件并返回命令提示符

c - TCP连接双方同时发送时丢包

java - 让 Java IO Socket 像 ServerSocket 一样监听