× The internal search function is temporarily non-functional. The current search engine is no longer viable and we are researching alternatives.
As a stop gap measure, we are using Google's custom search engine service.
If you know of an easy to use, open source, search engine ... please contact support@midrange.com.



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.

This thread ...


Follow On AppleNews
Return to Archive home page | Return to MIDRANGE.COM home page

This mailing list archive is Copyright 1997-2024 by midrange.com and David Gibbs as a compilation work. Use of the archive is restricted to research of a business or technical nature. Any other uses are prohibited. Full details are available on our policy page. If you have questions about this, please contact [javascript protected email address].

Operating expenses for this site are earned using the Amazon Associate program and Google Adsense.