Progress on preventing multiple instances of a program from running in windows

Lynch, Jonathan BNZ2 at CDC.GOV
Fri Dec 3 09:57:27 EST 2004


I found that checking the opensockets did not find the socket that was
opened by another instance of revolution - only sockets opened by the
instance of revolution that checked for opensockets.

On the other hand - the get shell(netstat -a) command checks for all
open sockets from all processes.

I also figured out how to get the two instances to communicate last
night. The problem was that, when the second instance wrote to the port
that the first instance was listening on, then the second instance took
over the listening activity on that port.

What was happening was that both instances were set to listen to that
port, but once the port was read by one instance, it was not read by the
other.

The solution is like this:

Open socket to "127.0.0.1:48953"
Write "QueryInstance" to socket "127.0.0.1:48953"
Close socket "127.0.0.1:48953"
Close socket "48953"

Notice that 4th line that closes the port. After the 2nd instance writes
to the port that the first instance is listening on, it closes off its
access to listening to port 48953. That allows the first instance (which
is still set to listen to port 48953) to continue accessing information
on port 48953.

When the second instance realizes that 48953 is in use, it needs to
accept connections on a different port - say 48954. That way, when the
first instance sends a message back to the second instance, it will be
listening on a port not used by the first instance, and won't interfere.

I guess that sounds rather confusing doesn't it? I am working on the
script that does that, and will have the full bit of code ready soon.

Cheers

-----Original Message-----
From: use-revolution-bounces at lists.runrev.com
[mailto:use-revolution-bounces at lists.runrev.com] On Behalf Of Alex
Tweedly
Sent: Friday, December 03, 2004 9:28 AM
To: How to use Revolution
Subject: Re: Progress on preventing multiple instances of a program from
running in windows

At 11:52 03/12/2004 +0100, thierry wrote:

>Hi,
>
>LJ> Hello... the following script seems to work.
>
>LJ> Factors to consider:
>LJ> 1)The stack should be set to purge itself from memory upon closing
>LJ> 2)Some firewalls might prevent the program from accepting
>LJ> connections on a port
>LJ> 3)This prevents multiple instances, but still does not quite allow
>LJ> the two instances to communicate. Writing to a socket from one
instance
>LJ> seems to steal the ability of the other instance to listen to that
>LJ> socket - I am still trying to work out how to do that.
>
>humm, with my little experience, you probably need to differenciate the
1st
>instance from the second. if the first do a accept connection ( Server
mode )
>the second instance should do a connect as a client. So, if you see
yourself
>in the netstat result then run a open socket on the port.

That's right. Since we're using sockets anyway, there's no need to use 
netstat at all.

Executive Summary :
the first instance goes into server mode, and accepts connections from 
subsequent instances

Technical Summary:
when an instance starts up, it attempts to open a connection to the
chosen 
port.
If it succeeds, then there is already an instance running - and we have
a 
connection to it.
If it fails, then there is no instance running - become the "server" and

accept connections from others.

Exercise (left to the reader):
if the initial instance (server) is closed down, the client(s) should
react 
to the "socket closed" event, such that one of them becomes a server,
and 
the other clients re-connect to it.

Here's some code to do the initial problem - it has a bunch of error 
checking you could take it if you really wanted to, so it doesn't need
to 
be quite this long. Note - I did this as a handler called "startUp"
rather 
than in OpenStack or preOpenStack because I pulled most of this code out
of 
an existing app and this was easier.

>local lConns
>
>on startUp
>   if the openSockets <> empty then
>     resetAll
>     put "reset" into field "My Status"
>     wait for 100 millisecs
>   end if
>   -- See if there is already an instance running
>   open socket to "127.0.0.1:7654" with message "setMode"
>end startUp
>
>on setMode pMode
>   if pMode = "Server" then
>     -- we should be in server mode
>     put pMode into field "My Status"
>     accept connections on port "7654" with message "connectionMade"
>   else
>     -- another instance is running as server - need to be a client
>     put "Client" into field "My Status"
>     -- send a message to confirm
>     write "this is my input line" & cr to socket "127.0.0.1:7654"
>     read from socket "127.0.0.1:7654" until CR with message 
> "receivedResponse"
>   end if
>end setMode
>
>-- Because this object does the Accepts and Opens, it gets close and
error 
>notifications
>on socketClosed s
>   put lineOffset(s, lConns) into NConn
>   if NConn = 0 then
>     logWrite "Attempt to close a socket that is not open."
>   else
>     logWrite "Socket" && s && "closed."
>     delete line NConn of lConns
>     put lConns into field "Connections"
>   end if
>end socketClosed
>
>on socketError pSocket, pError
>   if offset("10061", pError) > 0 then
>     -- Connection refused - no-one is listening on this port already
>     setMode "Server"
>   else
>     logWrite "Error :" && param(1) && param(2)
>   end if
>end socketError
>
>-- client functions
>on receivedResponse
>   logWrite "Received response : " & param(2)
>end receivedResponse
>
>-- Server mode handlers
>on connectionMade pOtherOne
>   if char 1 to 9 of pOtherOne <> "127.0.0.1" then
>     logWrite "Connection attempt from another machine - reject"
>     close socket theOtherOne
>     exit connectionMade
>   end if
>   if the number of lines in lConns >= 4 then
>     logWrite "Too many connections - rejected."
>     close socket theOtherOne
>     exit connectionMade
>   end if
>   put pOtherOne & cr after lConns
>   read from socket pOtherOne until CR with message "readsome"
>end connectionMade
>
>
>on readsome fromSocket, theInput
>   put lineOffset(fromSocket, lConns) into NConn
>   if NConn = 0 then
>     logWrite "Input rejected - unknown Connection" & fromSocket
>     read from socket fromSocket until CR with message "readsome"
>     exit readsome
>   end if
>   -- echo it
>   write "echo " & theInput & cr to socket fromSocket
>   logWrite fromSocket & theInput
>   read from socket fromSocket until CR with message "readsome"
>end readsome
>
>on logWrite m
>     put m & cr after field "Connections"
>end logWrite

This works fine for me (Win2000), running one instance in the Player and

the other within Rev itself. (And also running an echo server or clients

written in other languages).

Note that it *should* be even easier than this - it makes no sense to
have 
two applications listening on the same port; in Python or C you get an 
error (EADDRINUSE) return from the bind call (approx equivalent of Rev's

"Accept") when another instance has already done an Accept on the port. 
Unfortunately, Rev doesn't seem to send an error in this case.  I will
play 
with this a bit more to make sure that I haven't done anything stupid,
and 
then Bugzilla it.

-- Alex.


More information about the use-livecode mailing list