0

While going through the answer in the link below, i understand that the "open" command opens up an IO channel for read/write similar to what socket command does.

Link: How can I redirect stdout into a file in tcl

Question: It looks like once you close the stdout using close stdout, the default channel moves to the what was created using open $file w. Why doesn't this work in socket IO programming. For example:

set sock [socket -server $port]

close stdout

puts "hello there"

Error: can not find channel named "stdout"

Expecting the output of puts command to directly go to channel

mrcalvin
  • 3,291
  • 12
  • 18
  • You'd have to close stdout first, then the next opened descriptor will replace it. See https://stackoverflow.com/a/68869664/9952196 for the logic, just replacing descriptor 0 with 1. – Shawn Sep 07 '21 at 05:06
  • Tried reversing the order of commands. First `close stdout` and then `set sock [socket -server $port]` and i get this error "channel "stdout" wasn't opened for writing". It is probably expecting stdout to be available as the writable channel – almostacoder Sep 07 '21 at 05:50
  • You'd have to use a connected socket, not one just listening for connections. – Shawn Sep 07 '21 at 05:54
  • You're missing an argument to `socket -server`, btw. – Shawn Sep 07 '21 at 05:55
  • Yes, the socket is connected to a client. The client side executes `socket $host $port` and get connected to the server and i can do puts on the server side correctly . Is that what you mean? Right, The complete command is `set sock [socket -server Accept $port]`. – almostacoder Sep 07 '21 at 06:06

1 Answers1

1

Firstly, socket -server is its own special thing. It necessarily does a callback when a client connects (the underlying infrastructure of the accept() system call is hidden from you). There's also not really very much else you can do with a server socket; in particular, you can't read or write on a server socket, as there's no other end connected.

The connected sockets created (which are really just ordinary client sockets except for how they were made) are using whatever file descriptor the OS assigned; Tcl doesn't reassign them. You're strongly recommended to not try to land an accept on any of the standard channels, but passing a connected socket to a subprocess via redirection is supported on POSIX (I don't know if it works on Windows). You'd do that like this:

socket -server spawnSubprocess 12345

proc spawnSubprocess {sock host port} {
    puts "connection from ${host}:${port}"
    exec [info nameofexecutable] myscript.tcl <@$sock >@$sock 2>@$sock &
    # You might want stderr to not go back to the client...
    close $sock
}

vwait forever

Note that the subprocess can discover the socket configuration using fconfigure.

In general, while it is possible to redirect the standard channels, it's very confusing to actually do it. Far better to leave them connected to wherever the calling process told them to go. But redirecting for subprocesses you create is absolutely fine.

Donal Fellows
  • 133,037
  • 18
  • 149
  • 215
  • Also note that the above code is vulnerable to DDoS attacks because it creates subprocesses as fast as it receives connections. Firewalling is strongly recommended for production use. – Donal Fellows Sep 07 '21 at 11:21
  • Thanks @donal-fellows. I noticed that when i run `close stdout` on the client side and then connect to the server. I can successfully print anything on the server via puts on the client, this is similar to closing stdout and opening a file as per your example. Why can't i run something like `close stdout; socket -server ...` ; connect a client and then do a puts on server and print back on client ? (since it worked for client side) – almostacoder Sep 07 '21 at 11:42