简体   繁体   中英

stringstream vs ifstream (ofstream) in c++ using socket programming

I have one question about socket programming in C++. Most of the tutorials I found on web assume that

  • (binding etc. is omitted)

    1. there is a string at client process

    2. it is saved to a file

    3. then the file is sent to server by first reading the file into stream

    4. server receives the stream and write it into another file.

Then, my question is that what if we can use stringstrem at step 2 instead of saving as a file? File I/O (in C++ ifstream and ofstream are typically used) is generally slow. Is it more efficient if I use stringstream directory?

Your Original Question:

"What if we can use stringstrem at step 2 instead of saving as a file?"

My Initial Response:

stringstream has nothing to do with server sockets and IO files.

You are lacking the fundamental idea of IO operations which is the concept of files for IO devices. There is no way around. You save nothing in a logical file stream. Your file bytes are buffered temporarily on your memory and flushed.

stringstream is a nice C++ library utility that let's you treat strings as file streams. Just like you read from an input file stream bytes after bytes until EOF/some other errors, or write into an output file stream bytes after bytes, using stringstream you can treat your string like the way you do to file streams. This is really helpful when you want to divide your string in small logical units. For example, suppose you read a string line and want to read each word from that line by treating the string line as a stream of words.

Further Instructions To Guide You To The Right Direction:

Nothing is "saved" in a logical file stream. Every I/O operation is performed through "logical" files in any computer system. Socket connection has two file descriptors on both ends: one is a client file descriptor and another one is a server file descriptor (connected file descriptor). Server listens for connection requests through a listening file descriptor which actually stays around as long as the lifetime of the server, and when it accepts a connection request, it returns another file descriptor through accept function called connected file descriptor that stays around as long as the client-server connection/transaction is ongoing.

int accept(int listenfd, struct sockaddr *addr, int *addrlen);

If you want to read from or write into a file stream and also wish to buffer your file bytes, you exactly need to do that- buffer your bytes. This is also very important in the context of servers and short counts because your connection might time out or it might get interrupted by signals. There are several options and techniques that you might implement. However, such discussions are not possible in this small thread. What I'm going to do based on your question is give you an example of how you can buffer your file stream, avoid short count, and handle signal interruptions through following steps:

For example, following is a function that reads n bytes and doesn't buffer

ssize_t rio_readn(int fd, void *usrbuf, size_t n)
{
size_t nleft = n;
ssize_t nread;
char *bufp = usrbuf;

while (nleft > 0) {
if ((nread = read(fd, bufp, nleft)) < 0) {
if (errno == EINTR) /* Interrupted by sig handler return */
nread = 0;/* and call read() again */
else
return -1;/* errno set by read() */
}
else if (nread == 0)
break;/* EOF */
nleft -= nread;
bufp += nread;
}
return (n - nleft);/* Return >= 0 */
}

We can implement the following steps to do buffered and robust IO operations (note RIO means robust IO):

Step 1: Set up empty read buffer and associate an open file descriptor so that we can implement our robust IO operations

#define RIO_BUFSIZE 8192
typedef struct {
int rio_fd;/* Descriptor for this internal buf */
int rio_cnt;/* Unread bytes in internal buf */
char *rio_bufptr;/* Next unread byte in internal buf */
char rio_buf[RIO_BUFSIZE]; /* Internal buffer */
} rio_t;

//Initialize robust IO buffer

void rio_readinitb(rio_t *rp, int fd)
{
rp->rio_fd = fd;
rp->rio_cnt = 0;
rp->rio_bufptr = rp->rio_buf;
}

Step 2: A robust read utility function to handle short count

static ssize_t rio_read(rio_t *rp, char *usrbuf, size_t n)
{
int cnt;

while (rp->rio_cnt <= 0) {/* Refill if buf is empty */
rp->rio_cnt = read(rp->rio_fd, rp->rio_buf,
sizeof(rp->rio_buf));
if (rp->rio_cnt < 0) {
if (errno != EINTR) /* Interrupted by sig handler return */
return -1;
}
else if (rp->rio_cnt == 0)/* EOF */
return 0;
else
rp->rio_bufptr = rp->rio_buf; /* Reset buffer ptr */
}

/* Copy min(n, rp->rio_cnt) bytes from internal buf to user buf */
cnt = n;
if (rp->rio_cnt < n)
cnt = rp->rio_cnt;
memcpy(usrbuf, rp->rio_bufptr, cnt);
rp->rio_bufptr += cnt;
rp->rio_cnt -= cnt;
return cnt;
}

Step 3: A robust IO function for buffered reading

ssize_t rio_readnb(rio_t *rp, void *usrbuf, size_t n)
{
size_t nleft = n;
ssize_t nread;
char *bufp = usrbuf;

while (nleft > 0) {
if ((nread = rio_read(rp, bufp, nleft)) < 0) {
if (errno == EINTR) /* Interrupted by sig handler return */
nread = 0;/* Call read() again */
else
return -1;/* errno set by read() */
}
else if (nread == 0)
break;/* EOF */
nleft -= nread;
bufp += nread;
}
return (n - nleft);/* Return >= 0 */
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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