繁体   English   中英

使用sock_stream连续调用write是否安全?

[英]is it safe to call write successively when using a sock_stream?

我需要在Linux上的C语言中编写一个小型客户端/服务器应用程序。

由于我是网络编程的新手,因此我建立了一个简短的示例,以进行更多的探索。

我基本上是在尝试发送由客户端动态分配的double数组。

我找到了以下方法(客户端):

write(sd,&datas.size,sizeof(int)); /* send size */
write(sd,datas.yi,datas.size*sizeof(double));/* send array */

在服务器端:

read(sd_cli,&datas.size,sizeof(int)); /* receive size */
datas.yi=(double *)malloc(datas.size*sizeof(double));
read(sd_cli,datas.yi,datas.size*sizeof(double)); /* receiving datas */

乍一看,我的代码似乎运行良好。

但是由于write调用是非阻塞的,所以我问自己read序列是否可以接收,例如,大小为double的数组?

是否有任何保证永远不会发生?

谢谢。

SOCK_STREAM类型的套接字提供可靠的有序数据传输,尽管细节取决于基础传输的性质。 读取器将按写入顺序逐字节接收成功写入的所有数据(如果实际上选择全部读取),但不一定是相同大小的块。

封锁 非阻塞与它无关,尽管我实际上看不出是什么使您说您的写入是非阻塞的。 也许您是在评论以下事实: write()read() write()不会承诺在任何给定调用中都传输请求的全部字节数。 这本身不能提供防止阻塞的保证,但是您绝对需要正确地解决它,尤其是对于套接字,尤其是如果您确实已将套接字的一端或两端置于非阻塞模式。 您问题的原始版本似乎声称您确实在考虑该问题。

无论如何,除非存在某种内核错误,否则客户端永远不会在读取数组的任何部分之后读取数组的大小,也不会以不同于写入顺序的相对顺序接收字节。

但是,要完全清楚地说,这是通过流套接字读取和写入可变大小的double精度数组的合理实现。 他们假设发送方和接收方具有相同的double类型表示形式,这对于UNIX域套接字肯定是这种情况。 尽管辅助函数包含大约一半的代码,但它们重用起来并不是很琐碎的:

/******
 * helper functions
 */

/*
 * Returns the number of bytes written, which may be zero, or a number
 * less than zero on failure.
 */
ssize_t write_fully(int fd, const void *buf, size_t count) {
    const unsigned char *next = buf;
    size_t remaining = count;

    while (remaining) {
        ssize_t n_written = write(fd, next, remaining);

        if (n_written < 0) {
            /* error */
            return n_written;
        } else {
            assert(n_written <= remaining);
            next += n_written;
            remaining -= n_written;
        }
    }

    /* all bytes successfully written */
    return count;
}

/* 
 * Returns the number of bytes read on success, or a number less
 * than zero on error.  It is accounted "success" if the end of the stream
 * is reached before the requested number of bytes is read; that case
 * can be distinguished by the return value, but no recovery is
 * possible.
 */
ssize_t read_fully(int fd, void *buf, size_t count) {
    unsigned char *next = buf;
    size_t remaining = count;

    while (remaining) {
        ssize_t n_read = read(fd, next, remaining);

        if (n_read < 0) {
            /* error */
            return n_read;
        } else if (n_read) {
            assert(n_read <= remaining);
            next += n_read;
            remaining -= n_read;
        } else {
            /* premature end of file */
            return count - remaining;
        }
    }

    /* all bytes successfully read */
    return count;
}

/******
 * Array-transfer functions
 */

/* returns 0 on success, else nonzero */
int write_double_array(int fd, unsigned n, double d[n]) {
    ssize_t bytes_written;

    bytes_written = write_fully(fd, &n, sizeof(n));
    if (bytes_written < 0) return bytes_written;

    bytes_written = write_fully(fd, d, n * sizeof(double));
    return (bytes_written < 0) ? bytes_written : 0;
}

/*
 * returns 0 on success, else nonzero.
 * On success, the caller takes responsibility for freeing the
 * dynamically-allocated result array.
 */
int read_double_array(int fd, unsigned *n, double **d) {
    unsigned temp_n;
    ssize_t bytes_read = read_fully(fd, &temp_n, sizeof(temp_n));

    if (bytes_read < 0) {
        return -1;
    } else if (bytes_read != sizeof(temp_n)) {
        return 1;
    } else if (temp_n) {
        size_t n_bytes = temp_n * sizeof(double);
        double *temp = malloc(n_bytes);

        if (!temp) return -1;  /* allocation failure */
        if (read_fully(fd, temp, n_bytes) < n_bytes) {
            free(temp);
            return -1;
        }

        /* success */
        *d = temp;
    }

    *n = temp_n;
    return 0;
}

您可以以不同的方式实现数组传输协议,但是该方法以您声称的相同格式发送数据。 您不能简单地安全地做到这一点。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM