More Socket Problems.........
Alex Tweedly
alex at tweedly.net
Thu Feb 28 17:37:39 EST 2008
Dave wrote:
> Opps!
>
> Just realized that the IP Addresses are wrong in the example, in the
> real app it's ok. I forgot that my router munges the the LAN IP
> Addresses, so where I've put 192.168.1.101, read 192.168.1.87 and
> where 192.168.1.102 read 192.168.1.105.
>
> Another question is:
>
> Why do I get a read error and not a write error:
>
> socketError: 192.168.1.87:6000|looktowindward Error 54 reading socket
>
> I'm not reading on the Client, I'm trying to try data.
>
You don't get a read error. You get a socket error (-- Connection reset
by peer. This occurs when an established connection is shut down for
some reason by the remote computer.) which the error string misleadingly
indicates was a read error. This probably comes from your system (which
OS etc. are you using ?), and is merely passed along by Rev.
It probably does happen when you try to write to the socket after it has
been closed.
I'd recommend adding a 'socketClosed' handler and see if that helps ...
>
> Questions:
>
> Why do I sometimes not get a socketError or a socketTimeout ?
>
> Why does it sometimes repeat (as it should) for a few times and then
> stop?
>
Don't know :-( but try adding the socketClosed handler and see if that
helps. I have also asked some questions / made some suggestions below.
If it doesn't, resend this log
> Here is the code:
>
> The mouseUp handler are in the main stack of the app and the
>
>
> The following is including in the App using the "start using" command:
>
>
> -- StartServer
>
> function StartServer theServerPortNumber,theClientAllowList
>
> get DebugLogString("StartServer - Accept:" && theServerPortNumber)
>
> put theClientAllowList into sgServerClientAllowList
> accept connections on theServerPortNumber with message
> "ServerContactedByClient"
>
> return empty
> end StartServer
>
>
> -- ServerContactedByClient
>
> on ServerContactedByClient theIPAddress
> local myClientIPAddress
> local myResult
>
> put the result into myResult
>
what do you expect 'the result' to contain at this point ?
> get DebugLogString("ServerContactedByClient:" && theIPAddress &&
> myResult)
>
> if myResult <> empty then
> breakpoint
> exit ServerContactedByClient
> end if
>
> set the itemDelimiter to ":"
> put item 1 of theIPAddress into myClientIPAddress
>
> if myClientIPAddress is not among the lines of
> sgServerClientAllowList then
> get DebugLogString("ServerContactedByClient, Bad Client:" &&
> theIPAddress)
> close socket theIPAddress
I'd recommend a 'exit ServerContactedByClient" at this point - otherwise
you are about to read from a socket you just closed.
> end if
>
> read from socket theIPAddress for kPacketCountSize chars with
> message "ServerReceivedPacketSize"
>
> end ServerContactedByClient
>
>
>
> -- ServerReceivedPacketSize
>
> on ServerReceivedPacketSize theIPAddress,thePacketSize
> local myResult
> local myPacketData
> local myPacketID
> local myPacketCommand
> local myConnectionID
>
> put the result into myResult
>
again, what do you expect in 'the result' here ?
> get DebugLogString("ServerReceivedPacketSize:" && theIPAddress &&
> thePacketSize && myResult)
>
> if myResult <> empty then
> get DebugLogString("ServerReceivedPacketSize, Error:" && myResult)
> breakpoint
> end if
>
> read from socket theIPAddress for thePacketSize chars
> put the result into myResult
> put it into myPacketData
>
Note this is a blocking read. That will normally work OK (since the
client sends the packet size followed by the data), but it is not
robust. If the client was forced to split the data into different
packets (e.g. if the data was relatively large), and the subsequent
packet was lost in the network (i.e needed to be NAK'ed and then
retransmitted), then this could cause your handler to block for an
arbitrarily long period - up to the timeout interval.
It's up to you, but I would NEVER do a blocking read - I'd simply do
read from socket theIPAddress for thePacketSize chars with message
"ServerReceivedPacketData"
and put most of the following code into that new handler (finishing, of
course with another "read from ... ServerReceivedPacketSize")
> get DebugLogString("ServerReceivedPacketSize, Packet Data:" &&
> myPacketData && myResult)
>
> if myResult <> empty then
> get DebugLogString("ServerReceivedPacketSize, Error:" && myResult)
> breakpoint
> end if
>
> --
> -- Get the Message Content
> --
> put item 1 of myPacketData into myPacketID
> put item 2 of myPacketData into myPacketCommand
>
> if myPacketID = "$SYS" then
> if myPacketCommand = "Connect" then
> put item 3 of myPacketData into myConnectionID
>
> end if
>
> end if
>
> end ServerReceivedPacketSize
>
>
> -- StartClient
>
> function StartClient theServerList,theConnectionID
>
> set the socketTimeoutInterval to (2 * 1000)
> put theServerList into sgConnectToServerList
> repeat for each line myIPAddress in sgConnectToServerList
> send "StartOneClient myIPAddress,theConnectionID" to me in 0 seconds
> end repeat
>
> return empty
> end StartClient
>
I notice that StartOneClient really only does 'open socket' (which is
non-blocking, since you specify a callback handler) and therefore is
very quick, so unless you expect very large lists of servers, you could
simplify this and not bother with the send message, just call the
handler directly. No problem doing it the way you have done - just want
to point out the non-blocking (and hence speedy) nature of "open socket".
>
>
> -- StartOneClient
>
> on StartOneClient theIPAddress,theConnectionID
> local myServerIPAddress
> local myServerPortNumber
> local mySocketAddress
> local myConnectString
> local myPacketSize
> local myResult
>
> put
> _DecodeIPAddress(theIPAddress,myServerIPAddress,myServerPortNumber)
> into myResult
> if myResult <> empty then
> get DebugLogString("StartOneClient - IP Address Error:" &&
> theIPAddress && myResult)
> breakpoint
> exit StartOneClient
> end if
>
> put myServerIPAddress & ":" & myServerPortNumber & "|" &
> theConnectionID into mySocketAddress
>
> get DebugLogString("StartOneClient - Connect:" && mySocketAddress &&
> myResult)
>
> open socket mySocketAddress with message "ClientSocketOpen"
> put the result into myResult
I don't believe 'the result' has anything useful here, since you
specified a callback handler.
> if myResult <> empty then
> get DebugLogString("StartOneClient - Write Socket Count Error:" &&
> mySocketAddress && myPacketSize && myResult)
> breakpoint
> exit StartOneClient
> end if
>
> end StartOneClient
--
Alex Tweedly mailto:alex at tweedly.net www.tweedly.net
More information about the use-livecode
mailing list