From owner-freebsd-hackers Sun Nov 17 11:15:16 1996 Return-Path: owner-hackers Received: (from root@localhost) by freefall.freebsd.org (8.7.5/8.7.3) id LAA00895 for hackers-outgoing; Sun, 17 Nov 1996 11:15:16 -0800 (PST) Received: from sumatra.americantv.com (sumatra.americantv.com [199.184.181.250]) by freefall.freebsd.org (8.7.5/8.7.3) with ESMTP id LAA00849 for ; Sun, 17 Nov 1996 11:15:05 -0800 (PST) Received: from right.PCS (right.pcs. [148.105.10.31]) by sumatra.americantv.com (8.7.6/8.7.3) with ESMTP id MAA15776; Sun, 17 Nov 1996 12:36:28 -0600 (CST) Received: (jlemon@localhost) by right.PCS (8.6.13/8.6.4) id TAA04944; Sun, 17 Nov 1996 19:13:09 GMT Message-Id: <199611171913.TAA04944@right.PCS> 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()) References: X-Mailer: Mutt 0.48.1 Mime-Version: 1.0 In-Reply-To: ; from Marc G. Fournier on Nov 17, 1996 12:30:49 -0500 Sender: owner-hackers@freebsd.org X-Loop: FreeBSD.org Precedence: bulk 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 X#include X#include X#include X#include X#include X#include X#include X#include X#include 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 X#include X#include X#include X#include X#include X#include X#include 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