All along, the personal concept of only non-blocking socket will produce eagain error, meaning is currently not read and write, as long as you continue to try again. When we recently redis an error in the module to correct this concept of my mistake.
Event review: Hiredis's redisconnectwithtimeout and Rediscontextsettimeout interfaces set the socket that is connected to the Redis-server as blocking mode and set the read-write timeout. The setting timeout in our project is 50ms. Then in the following days the log found Hiredis error "Resource temporarily unavailable", at first very strange, because this error corresponds to Eagain, and this situation in my knowledge concept only
Will be reported in non-blocking mode. Here's what I do to clarify this concept:
1. View Redis read-write interface
/* Use this function to handle a read event on the descriptor.
It'll try * and read some bytes from the socket and feeds them to the reply parser. * After this function is called, your may use rediscontextreadreply to * the If there is a reply available.
* * int redisbufferread (Rediscontext *c) {char buf[1024*16];
int nread; /* Return early when the context has seen an error.
*/if (C->ERR) return redis_err;
Nread = Read (c->fd,buf,sizeof (BUF)); if (nread = = 1) {if (errno = = Eagain &&! ( C->flags & redis_block)) | | (errno = = eintr))
{/* Try again later/} else {__redisseterror (c,redis_err_io,null); return redis_err; </span>//Branch a1</span>}} else if (nread = = 0) {__re
Disseterror (c,redis_err_eof, "Server closed the connection"); return redis_err; </span> Branch A2</span>} else {if (Redisreaderfeed (c->reader,buf,nread)!= redis_ok) {__rediss
Eterror (C,C->READER->ERR,C->READER->ERRSTR);
return redis_err;
} return REDIS_OK; }
/* Write the output buffer to the socket. * Returns REDIS_OK when the ' is empty ', or (a part of) the ' buffer was ' * succesfully written to the socket.
When the ' is ' empty after the * write operation, the ' done ' is set to 1 (if given).
* Returns Redis_err If a error occured trying to write and sets * C->ERRSTR to hold the appropriate error string.
* * int Redisbufferwrite (rediscontext *c, int *done) {int nwritten; /* Return early when the context has seen an error.
*/if (C->ERR) return redis_err;
if (Sdslen (C->OBUF) > 0) {nwritten = write (C->fd,c->obuf,sdslen (C->OBUF)); if (Nwritten = = 1) {if (errno = = Eagain &&! ( C->flags & redis_block)) | | (errno = = eintr)) {/* Try again later/} else {__redisseterror (c,redis_err_io,null);
Branch B1 return redis_err;
} else if (Nwritten > 0) { if (Nwritten = = (signed) Sdslen (C->OBUF)) {sdsfree (C->OBUF);
C->obuf = Sdsempty ();
else {sdsrange (c->obuf,nwritten,-1);
}} if (done!= NULL) *done = (Sdslen (c->obuf) = = 0);
return REDIS_OK; }
Note that the error log shows the Hiredis setting error as Redis_err_io, and Errstr as "Resource temporarily unavailable", then it is only possible to branch A1 and branch B1, and then investigate
2. View the error setting process
void __redisseterror (rediscontext *c, int type, const char *str) {
size_t len;
C->err = type;
if (str!= NULL) {
len = strlen (str);
Len = Len < (sizeof (C->ERRSTR)-1)? Len: (sizeof (C->ERRSTR)-1);
memcpy (C->errstr,str,len);
C->errstr[len] = ' I ';
} else {
<span style= "color: #ff0000;" > /* Only redis_err_io may lack a description!
/assert (type = = Redis_err_io);
Strerror_r (errno,c->errstr,sizeof (C->ERRSTR));</span>
}
}
C->ERRSTR is set to "Resource temporarily unavailable" in the branch, which pushes errno to Eagain
3. Why blocking's read and write will cause errno to be eagain.
1 What do we do with the socket. Set timeout time
int Rediscontextsettimeout (rediscontext *c, const struct Timeval TV) {
if setsockopt (c->fd,sol_socket,so_ RCVTIMEO,&TV,SIZEOF (TV) = = = 1) {
__redisseterrorfromerrno (c,redis_err_io, "setsockopt (So_rcvtimeo)");
return redis_err;
}
if (setsockopt c->fd,sol_socket,so_sndtimeo,&tv,sizeof (TV) = =-1) {
__redisseterrorfromerrno (c,REDIS_ Err_io, "setsockopt (So_sndtimeo)");
return redis_err;
}
return REDIS_OK;
}
2 socket Settings So_rcvtimeo and So_sndtimeo have any effect on read/write. Look what man says.
So_rcvtimeoandSo_sndtimeoSpecify the receiving or sending timeouts until reporting an error. The argument is a struct timeval. If an input or output function blocks for this period of time, and data has been sent or received, the return value of tha t function would be the amount of data transferred; If no data has been transferred and the timeout has been reached then-1 are returned with errno set toEagainOrEwouldblock, oreinprogress(ForConnect(2)) just as if the socket is specified to be nonblocking. If The timeout is set to zero (the default) then the operation would never timeout. Timeouts only have effect for system calls that perform socket I/O (e.g.,Read(2),recvmsg(2),Send(2),sendmsg(2)); Timeouts have no effect forSelect(2),Poll(2),epoll_wait(2), and so on.
Finally clear:So_rcvtimeo and So_sndtimeo will cause the Read/write function to return Eagain
In addition, in determining the error process, the colleague mentions that O_nodelay will cause the write interface to return Eagain, indeed, if the o_nodelay is set and is not currently writable, then the write interface sets errno to Eagain, But the write interface returns 0 instead of-1. In this case, there is no o_nodelay in the Hiredis interface