Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

work with socket

18 views
Skip to first unread message

Maky

unread,
Sep 10, 2007, 11:04:48 AM9/10/07
to
Hello
i'm opening server to read and write

if {[catch {set fd [socket -async $server $port]}]} {
Error "Unknown host"
return unknown
}
fconfigure $fd -blocking false -translation binary
fileevent $fd readable "network::ReadData"
set data(socket) $fd

and when i'm writing in such way

set packet [binary format I $key]
if {[catch {puts -nonewline $data(socket) $packet;flush
$data(socket)}]} {
Error "send error!"
}

all packets going together
But when i'm debugging under Komodo, everything working fine , packets
are going one by one..
How to fix this?

Gerald W. Lester

unread,
Sep 10, 2007, 2:06:38 PM9/10/07
to

Why do you think all the packets are going together at the same time?

And what exactly do you mean by "all the packets are going together at the
same time"?

--
+--------------------------------+---------------------------------------+
| Gerald W. Lester |
|"The man who fights for his ideals is the man who is alive." - Cervantes|
+------------------------------------------------------------------------+

David Gravereaux

unread,
Sep 10, 2007, 2:42:15 PM9/10/07
to
Maky wrote:

> all packets going together

packets smackets.. streams are buffered, not only by Tcl but by the network
subsystem, your router, all other in the middle to your destination. By
packets, do you really mean a literal IP payload as seen by a sniffer or your
receiving app got a notification to read?

'fconfigure $fd -buffering none' if you want Tcl's buffering off.

Don't forget the first idiom of tcp programming... `chunk boundaries are not
maintained from sender to the receiver using a stream protocol'.


signature.asc

Cameron Laird

unread,
Sep 10, 2007, 3:22:55 PM9/10/07
to
In article <1189436688.7...@50g2000hsm.googlegroups.com>,

Along with what Gerald and Davy have already advised, please be aware
that
1. Evaluation of [socket -async $server $port] might
toss errors other than "unknown host";
2. Similarly for [puts -nonewline ...].

I suspect I understand your original question, although it might be
hard to explain. You're doing an asynchronous connect. While you
don't give us enough of your source to be certain, it seems likely
to me that when you are NOT in Komodo, your first [flush] is reached
BEFORE the connect is complete. As <URL:
http://www.tcl.tk/man/tcl8.4/TclCmd/socket.htm#M8 > documents, the
[flush] (and perhaps subsequent ones) returns immediately.

Are you sure you want nonblocking mode?

John Kelly

unread,
Sep 10, 2007, 4:24:53 PM9/10/07
to
On Mon, 10 Sep 2007 19:22:55 +0000, cla...@lairds.us (Cameron Laird)
wrote:

>> if {[catch {set fd [socket -async $server $port]}]} {

>your first [flush] is reached BEFORE the connect is complete. As


>URL: http://www.tcl.tk/man/tcl8.4/TclCmd/socket.htm#M8 > documents,
>the [flush] (and perhaps subsequent ones) returns immediately.

>Are you sure you want nonblocking mode?

My first attempt at using Tcl is to write a simple network client, and
I do NOT want my socket open to block (dns delays, whatever).

After reading man pages and various examples, I'm still struggling to
code an idiomatic non-blocking client socket open, while handling all
possible error conditions.

Anyone have an example?


--
Internet service
http://www.isp2dial.com/

Cameron Laird

unread,
Sep 10, 2007, 5:20:08 PM9/10/07
to
In article <189be31uovlobmacu...@4ax.com>,
.
.
.
A partial response: "nonblocking", "handling all possible error
conditions", and "simple ... example" don't go together particularly
well--they have low mutual compossibility.

We'll likely follow up with different examples of two-out-of-three.

David Gravereaux

unread,
Sep 10, 2007, 10:04:26 PM9/10/07
to
John Kelly wrote:
> On Mon, 10 Sep 2007 19:22:55 +0000, cla...@lairds.us (Cameron Laird)
> wrote:
>
>>> if {[catch {set fd [socket -async $server $port]}]} {
>
>> your first [flush] is reached BEFORE the connect is complete. As
>> URL: http://www.tcl.tk/man/tcl8.4/TclCmd/socket.htm#M8 > documents,
>> the [flush] (and perhaps subsequent ones) returns immediately.
>
>> Are you sure you want nonblocking mode?
>
> My first attempt at using Tcl is to write a simple network client, and
> I do NOT want my socket open to block (dns delays, whatever).

That first requirement is a NOP. An async connect _does_ actually block doing
the name lookup. The easiest fix is to call out to an external app (like
nslookup or whatever) over an async pipe, parse the result, then call [socket]
with the IP. That's a most frequently requested new feature that hopefully
will happen one day.


signature.asc

Maky

unread,
Sep 11, 2007, 3:25:15 AM9/11/07
to
On Sep 10, 9:06 pm, "Gerald W. Lester" <Gerald.Les...@cox.net> wrote:
> Maky wrote:
> > Hello
> > i'm opening server to read and write
>
> > if {[catch {set fd [socket -async $server $port]}]} {
> > Error "Unknown host"
> > return unknown
> > }
> > fconfigure $fd -blocking false -translation binary
> > fileevent $fd readable "network::ReadData"
> > set data(socket) $fd
>
> > and when i'm writing in such way
>
> > set packet [binary format I $key]
> > if {[catch {puts -nonewline $data(socket) $packet;flush
> > $data(socket)}]} {
> > Error "send error!"
> > }
>
> > all packets going together
> > But when i'm debugging under Komodo, everything working fine , packets
> > are going one by one..
> > How to fix this?
>
> Why do you think all the packets are going together at the same time?
>
> And what exactly do you mean by "all the packets are going together at the
> same time"?
>

When i sniff interface using ngrep, i can really see the difference.

And also in second case i can really get bytes from server and modify
outgoing packet according
the info i get


John Kelly

unread,
Sep 11, 2007, 4:13:54 AM9/11/07
to
On Mon, 10 Sep 2007 21:20:08 +0000, cla...@lairds.us (Cameron Laird)
wrote:

>> I'm still struggling to code an idiomatic non-blocking client


>> socket open, while handling all possible error conditions.

> "nonblocking", "handling all possible error conditions", and "simple


> ... example" don't go together particularly well


Here's a first draft ... on linux, the following script does what I
want. But on Windows (server 2003), Tcl seems untrue to the fileevent
docs which say:

> A channel is also considered to be readable if an ... error condition
> is present on the underlying file or device.

On Windows, when the socket fails to open (e.g., connection refused),
there is no fileevent, and the alarm timer expires. It still works,
more or less, but I also need the error information, for reporting to
the user.

Works perfectly on linux:


proc getline {sock} {

set exception [catch {gets $sock line} data]

if {$exception} {
global host port
puts "On socket to $host port $port, $data"
} elseif {$data < 0} {
if {[fblocked $sock]} {
return
} elseif {[eof $sock]} {
puts "* EOF"
}
} else {
puts $line
if {![eof $sock]} {
return
} else {
puts "* EOF"
}
}

catch {close $sock}
global mainevent
set mainevent sockclosed

}

proc initsocket {sock} {

global initalarm
after cancel $initalarm
fileevent $sock readable [list getline $sock]

}

set host localhost
set port 143
set initlimit 5000

set sock [socket -async $host $port]
fconfigure $sock -blocking 0
fileevent $sock readable [list initsocket $sock]

set initalarm [after $initlimit set mainevent initfailure]

vwait mainevent

switch $mainevent {
initfailure {
puts "What we've got here is a failure to communicate."
}
sockclosed {
puts "And Dat's De End."
}
default {
puts "Who knows?"

Gerald W. Lester

unread,
Sep 11, 2007, 8:30:35 AM9/11/07
to

Please see the other posts in the thread.

Gerald W. Lester

unread,
Sep 11, 2007, 8:32:27 AM9/11/07
to

The OP responded to a post I made with:

> When i sniff interface using ngrep, i can really see the difference.
>
> And also in second case i can really get bytes from server and modify
> outgoing packet according
> the info i get

--

David Gravereaux

unread,
Sep 11, 2007, 3:19:16 PM9/11/07
to
John Kelly wrote:

> proc initsocket {sock} {
>
> global initalarm
> after cancel $initalarm

set connectErr [fconfigure $sock -error]
if {[string length $connectErr]} {
global mainevent
set mainevent initerror
catch {close $sock}
} else {

> fileevent $sock readable [list getline $sock]

}
> }


You might also want to try an alternate socket implementation for windows that
is a bit more capable at returning useful error messages:
http://sf.net/projects/iocpsock

I think all that stock Tcl can say about a connection error is EINVAL rather
than something useful like: no route to host, or no such name.


signature.asc

John Kelly

unread,
Sep 11, 2007, 9:01:49 PM9/11/07
to
On Tue, 11 Sep 2007 12:19:16 -0700, David Gravereaux
<davy...@pobox.com> wrote:

>> proc initsocket {sock} {
>>
>> global initalarm
>> after cancel $initalarm
>
> set connectErr [fconfigure $sock -error]
> if {[string length $connectErr]} {
> global mainevent
> set mainevent initerror
> catch {close $sock}
> } else {
>
>> fileevent $sock readable [list getline $sock]
>
> }
>> }

I like that refinement, checking for startup errors in initsocket. I
knew there was something undesirable about the way I had it structured
before ...


>You might also want to try an alternate socket implementation for windows that
>is a bit more capable at returning useful error messages:
>http://sf.net/projects/iocpsock

I took a peek, but I don't use Windows enough to justify exerting that
much effort right now ...


>I think all that stock Tcl can say about a connection error is EINVAL rather
>than something useful like: no route to host, or no such name.

For the second draft, I added your refinement and cleaned things up.
Unfortunately, Windows still does not generate a fileevent on an error
condition, as linux does. I wonder if this is a bug in Windows Tcl?

For anyone who cares about copyrights or licenses, fear not: I hereby
release this original work to the public domain (no license needed).


set host localhost
set port 143
set initlimit 5000

proc getline {sock} {

set exception [catch {gets $sock line} data]

if {$exception} {
puts "$data"
global mainevent
set mainevent getsfailure

} else {
if {!($data < 0)} {
puts $line
} elseif {[fblocked $sock]} {
# Nothing to do


}
if {[eof $sock]} {
puts "* EOF"

global mainevent
set mainevent sockclosed
}
}

return

}

proc initsocket {sock} {

global initalarm
after cancel $initalarm

set initerror [fconfigure $sock -error]

if {![string length $initerror]} {


fileevent $sock readable [list getline $sock]

} else {
puts "$initerror"
global mainevent
set mainevent sockfailure
}

return

}

set sock [socket -async $host $port]
fconfigure $sock -blocking 0
fileevent $sock readable [list initsocket $sock]

set initalarm [after $initlimit set mainevent initfailure]

vwait mainevent

switch $mainevent {
initfailure {
puts "Failure contacting host $host port $port."
}
sockfailure {
puts "Failure opening socket to host $host port $port."
}
getsfailure {
puts "Failure getting socket data from host $host port $port."


}
sockclosed {
puts "And Dat's De End."
}
default {
puts "What we've got here is a failure to communicate."
}
}

catch {close $sock}

return

David Gravereaux

unread,
Sep 11, 2007, 11:17:35 PM9/11/07
to
John Kelly wrote:
>> I think all that stock Tcl can say about a connection error is EINVAL rather
>> than something useful like: no route to host, or no such name.
>
> For the second draft, I added your refinement and cleaned things up.
> Unfortunately, Windows still does not generate a fileevent on an error
> condition, as linux does. I wonder if this is a bug in Windows Tcl?

Change the first fileevent to ask for writable, not readable. In initsocket,
then ask for readable after its validated as good. I should have caught that
before, sorry.


signature.asc

John Kelly

unread,
Sep 12, 2007, 12:19:15 AM9/12/07
to
On Tue, 11 Sep 2007 20:17:35 -0700, David Gravereaux
<davy...@pobox.com> wrote:

>> For the second draft, I added your refinement and cleaned things up.
>> Unfortunately, Windows still does not generate a fileevent on an error
>> condition, as linux does. I wonder if this is a bug in Windows Tcl?

>Change the first fileevent to ask for writable, not readable. In initsocket,
>then ask for readable after its validated as good. I should have caught that
>before, sorry.

With that change, now it's working on linux and Windows too.

I would not guess to start with writable, it seems counter intuitive
to open a channel writable before readable. And since readable works
on linux, and the docs say readable should work with error conditions,
I thought the only solution was a bug report.

Thanks, David, for that trick!

John Kelly

unread,
Sep 12, 2007, 2:15:21 AM9/12/07
to
On Wed, 12 Sep 2007 04:19:15 +0000, John Kelly <j...@isp2dial.com>
wrote:

><davy...@pobox.com> wrote:

>>Change the first fileevent to ask for writable, not readable. In initsocket,
>>then ask for readable after its validated as good. I should have caught that
>>before, sorry.

>Thanks, David, for that trick!

Hmmm, tricky is the word.

Now I realize that initsocket is firing infinitely. Apparently, the
writable event is rescheduled on every exit from initsocket, because
the channel is still writable. Whoa! Looks like I need to cancel the
writable event as soon as I enter initsocket.

It's getting interesting now, figuring out how to accept user input
and move data in both directions on the socket, all in non-blocking
mode ...

0 new messages