I appreciate your reply, Scott. Just talking about it might help point
me in the right direction.
Scott said: "Remember, your program has two sockets... one that you
create with the socket() API, and another that you create by calling the
accept() API. Both should be closed. (But, it's the former of the two
that will cause the error message you posted.)"
Just to make sure, you're saying the *former* of the two, i.e. the one
created by socket(), would cause the "Address already in use error? I
would have thought that the *latter*, i.e. the one created by accept(),
would have caused the error.
Wow, 100W light bulb, ""two sockets"", dumb question: Am I supposed to
be doing the setsockopt() on the socket I use for the listen() or the
socket I get back from the accept()??? Maybe this is my whole problem
(see below). Maybe I should be doing setsockopt on sock2 AFTER the
accept().
I definitely perform a close on both sockets, as shown in my attempt at
pseudo-code:
PGM
CLPtop:
misc. processing
socketpgm {
listen_sock = socket
setsockopt listen_sock SO_LINGER
setsockopt listen_sock SO_REUSEADDR
bind
listen
sock2 = accept
close listen_sock
fcntl(sock2, F_SETFL, O_NONBLOCK)
perform conversation on sock2
close sock2
}
misc. processing
goto cmdlabel(CLPtop)
ENDPGM
However, I did NOT check errno after the close on listen_sock. I have
added such a check and it is not returning an error.
One thing I neglected to mention, but you reminded me, it that I am
using non-blocking I/O (because I need to implement variable receive
timeouts). Therefore, I do an fcntl call after the accept() and I have
added it to the pseudo-code.
Do you suppose I could be doing my setsockopt() wrong? Here is the
relevant excerpt from my code:
int listen_sock;
int nonzero = 1; /* need a nonzero value to turn on sockopt */
...
if (setsockopt(listen_sock,
SOL_SOCKET,
SO_REUSEADDR,
(char*)&nonzero,
sizeof(nonzero) ) < 0) {
dspmsg("Bad setsockopt reuseaddr: %s",strerror(errno));
close(listen_sock);
return ERROR;
}
...
Thanks again for your input. It helps to talk to somebody who knows what
I am talking about.
-Marty
=====================================================
* Subject: Re: TCP/IP sockets problem: SO_REUSEADDR
* From: Scott Klement <midrange-l@xxxxxxxxxxxxxxxx>
* Date: Mon, 23 Jul 2007 12:58:52 -0500
Hi Marty,
The sockopt REUSEADDR is intended to allow the local address to be
reused when the server is restarted before the required wait time
expires.
That's true. But there are other things as well. SO_REUSEADDR allows a
socket to bind to a port that another socket is bound to, thus
eliminating the need to wait for the close-wait timeout.
However, it does NOT allow two sockets to LISTEN to the same port. The
previous listener must be closed.
I thought that perhaps my SO_LINGER option was conflicting with
SO_REUSEADDR, so I removed SO_LINGER.
SO_LINGER controls how long the socket waits on the close() API. When
linger is turned on, the close() API will wait for any unsent data to be
sent. Assuming your sockets are in blocking mode, your program will sit
and wait on the close() API until any data in the socket's "send buffer"
has been sent to the remote host, and won't actually close until that
data is sent -- or until the timeout value (the l_linger value) has
elapsed. IF that timeout is elapsed, the remaining data will be
discarded.
You have yours set to 1 second, which means that close() can wait for up
to 1 second, and if there's still data in the send buffer, it'll be
discarded.
The normal behavior (when l_onoff = 0, i.e. the default), is for close()
to return immediately, and let i5/OS continue to attempt to send the
"send buffer" data in the background. It will continue to try for as
long as the timeout value set with the TCPCLOTIMO parameter of the
CHGTCPA command.
However, I can't see how this could cause bind() to fail. Even with the
default wait time of 120 seconds, if you've set SO_REUSEADDR correctly,
you're able to re-start the server program without problems.
I would suspect that either your listener socket (the one you called the
listen() API on) has not been closed properly, or that (for some unknown
reason?) the setsockopt() API for SO_REUSEADDR is failing.
Do you check whether setsockopt() was successful? If it fails, have you
checked the value of errno()?
Did you make sure that you closed the socket that you called listen()
on? Did the close() complete without error? Remember, your program has
two sockets... one that you create with the socket() API, and another
that you create by calling the accept() API. Both should be closed.
(But, it's the former of the two that will cause the error message you
posted.)
hope that helps...?
As an Amazon Associate we earn from qualifying purchases.