Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 17 Nov 1996 13:13:08 -0600
From:      jlemon@americantv.com (Jonathan Lemon)
To:        scrappy@ki.net (Marc G. Fournier)
Cc:        hackers@freebsd.org
Subject:   Re: Advise needed (readv()/writev())
Message-ID:  <199611171913.TAA04944@right.PCS>
In-Reply-To: <Pine.NEB.3.95.961117121157.18169B-100000@quagmire.ki.net>; from Marc G. Fournier on Nov 17, 1996 12:30:49 -0500
References:  <Pine.NEB.3.95.961117121157.18169B-100000@quagmire.ki.net>

next in thread | previous in thread | raw e-mail | index | archive | help
Marc G. Fournier writes:
> 	What I want to do is send a block of data across a link (X bytes)
> and have the other side read in X bytes.  Then, I want the sending send to
> send over another X bytes, and the receiving end to receive another X bytes.

What you do is send a header block across first, that tells the receiver how
many bytes are in the data page.  Then your receiver knows how many bytes to 
expect per page.  I've attached some quick-n-dirty sample code at the end 
for your perusal.


> 	What I've thought of doing was to use 'readv/writev', since then
> I could send across a page as an iovec structure, have readv read it in,
> process it and then go back and read the next page...and from what I've read
> in the book, this *should* work...but writev is returning -1 for the following
> sequence of events, which looks like:

All readv/writev does for you is allow your buffers to be non-contiguous in
memory.  Otherwise, they are conceptually identical to read/write.


> PS. my understanding from "the book" is that with readv, I'm assured that
>     the read will return with the number of bytes specified by iov_len, so
>     that the multiple reads are hidden behind the function call...

No.  All readv does is guarantee that your iov structures will be filled 
in order; eg: iov[1] will not be filled until iov[0] is completely filled.
It does not guarantee that iov[0] will be filled.

When reading from a socket, the call:

    read(socket, buffer, nbytes)

means "read a maximum of nbytes from the socket", and return.  It does not
mean "read exactly nbytes and return".
--
Jonathan

------------------------------ cut here ------------------------------
# This is a shell archive.  Save it in a file, remove anything before
# this line, and then unpack it by entering "sh file".  Note, it may
# create directories; files and directories will be owned by you and
# have default permissions.
#
# This archive contains:
#
#	server.c
#	client.c
#
echo x - server.c
sed 's/^X//' >server.c << 'END-of-server.c'
X#include <err.h>
X#include <fcntl.h>
X#include <stdio.h>
X#include <unistd.h>
X#include <sys/stat.h>
X#include <sys/types.h>
X#include <sys/mman.h>
X#include <sys/socket.h>
X#include <netinet/in.h>
X#include <arpa/inet.h>
X
X#define TESTFILE "/kernel"
X#define TEST_PORT 5005
X
Xint
Xmain()
X{
X    int fd, nfd, cnt, n;
X    struct stat st;
X    caddr_t maddr;
X    struct sockaddr_in sin;
X    size_t datasize;
X
X    if ((fd = open(TESTFILE, O_RDONLY)) < 0)
X        err(1, "open");
X    if (fstat(fd, &st) < 0)
X        err(1, "fstat");
X    if ((maddr = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0)) < 0)
X        err(1, "mmap");
X    close(fd);
X
X    if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
X        err(1, "socket");
X    sin.sin_family = AF_INET;
X    sin.sin_port = ntohs(TEST_PORT);
X    sin.sin_addr.s_addr = INADDR_ANY;
X    if (bind(fd, (struct sockaddr *)&sin, sizeof(sin)) < 0)
X        err(1, "bind");
X    n = 1;
X    if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &n, sizeof(n)) < 0)
X        err(1, "setsockopt");
X    if (listen(fd, 1) < 0)
X        err(1, "listen");
X
X    nfd = accept(fd, (struct sockaddr *)&sin, &n);
X    if (nfd < 0)
X        err(1, "accept");
X
X    cnt = 3;
X    while (cnt-- != 0) {		/* set to 1 for initial test */
X
X                /* assume that st.st_size fits in a (size_t) chunk,
X                   otherwise we will need multiple writes */
X        datasize = st.st_size;
X        n = write(nfd, (char *)&datasize, sizeof(datasize));
X        if (n < 0)
X            errx(1, "failed to write data size to socket: [%d bytes]", n);
X        printf("Wrote data size: %d bytes\n", n);
X
X        n = write(nfd, (char *)maddr, datasize);
X        if (n < 0)
X            errx(1, "failed to write data to socket: [%d bytes]", n);
X        printf("Wrote data: %d bytes\n", n);
X    }
X            /* write zero length marker for end of transmission */
X    datasize = 0;
X    n = write(nfd, (char *)&datasize, sizeof(datasize));
X    if (n < 0)
X        errx(1, "failed to write data size to socket: [%d bytes]", n);
X    close(nfd);
X    return (1);
X}
END-of-server.c
echo x - client.c
sed 's/^X//' >client.c << 'END-of-client.c'
X#include <err.h>
X#include <fcntl.h>
X#include <stdio.h>
X#include <unistd.h>
X#include <sys/types.h>
X#include <sys/socket.h>
X#include <netinet/in.h>
X#include <arpa/inet.h>
X
X#define TESTFILE "/kernel"
X#define TEST_HOST "127.0.0.1"
X#define TEST_PORT 5005
X#define NBYTES 8192
X
Xvoid
Xxread(int fd, char *buf, size_t bytes)
X{
X    int n;
X    char *p = buf;
X    
X    while (bytes) {
X        n = read(fd, p, bytes);
X        if (n < 0)
X            err(1, "read");
X        if (n == 0 && bytes != 0)
X            errx(1, "short file on read, %d bytes left", bytes);
X        fprintf(stderr, "Read: %d bytes\n", n);
X        bytes -= n;
X        p += n;
X    }
X}
X
X
Xint
Xmain()
X{
X    int fd, bytes;
X    char buf[NBYTES];
X    struct sockaddr_in sin;
X    size_t datasize; 
X
X    if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
X        err(1, "socket");
X    sin.sin_family = AF_INET;
X    sin.sin_port = ntohs(TEST_PORT);
X    sin.sin_addr.s_addr = inet_addr(TEST_HOST);
X    if (connect(fd, (struct sockaddr *)&sin, sizeof(sin)) < 0)
X        err(1, "connect");
X
X    for (;;) {
X        xread(fd, (char *)&datasize, sizeof(datasize));
X        if (datasize == 0)
X            break;
X        bytes = 0;
X        while (datasize) {
X            size_t chunk = datasize > NBYTES ? NBYTES : datasize; 
X            xread(fd, buf, chunk);
X            if (write(1, buf, chunk) != chunk)
X                err(1, "write");
X            datasize -= chunk;
X            bytes += chunk;
X        }
X        fprintf(stderr, "Read page, total bytes: %d\n", bytes);
X    }
X    return (1);
X}
END-of-client.c
exit



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199611171913.TAA04944>