can anybody tell me if it is possible (in tcl) for a server to open
two(or more) sockets and to talk simultaneousley with two clients on
these two sockets?...and if yes...do you know any links with such
examples?
i tried to do it like this but it dosen't work simultaneousley...
server:
#!/usr/bin/tclsh8.4
proc ServerAlloc {channel1 clientaddr clientport} {
fconfigure $channel1 -buffering line -blocking off
#read from client
puts "Accepted connection from $clientaddr port $clientport channel
$channel1
for Alloc"
gets $channel1 line
puts "Client (alloc) sais: \"$line\""
after 2000
#send message to client
puts $channel1 "mesaj1"
flush $channel1
puts "Sent \"mesaj 1\" to client (alloc)"
after 2000
#send message to client
puts $channel1 "mesaj2"
flush $channel1
puts "Sent \"mesaj 2\" to client (alloc)"
after 3000
#close channel
close $channel1
puts "Channel closed"
}
proc ServerFree {channel2 clientaddr clientport} {
fconfigure $channel2 -buffering line -blocking off
#read from client
puts "Accepted connection from $clientaddr port $clientport channel
$channel2
for Free"
gets $channel2 line
puts "Client (free) sais: \"$line\""
after 2000
#send message to client
puts $channel2 "mesaj1"
flush $channel2
puts "Sent \"mesaj 1\" to client (free)"
after 2000
#send message to client
puts $channel2 "mesaj2"
flush $channel2
puts "Sent \"mesaj 2\" to client (free)"
after 3000
#close channel
close $channel2
puts "Channel closed"
}
socket -server ServerAlloc 2500
socket -server ServerFree 7272
vwait forever
client1:
#!/usr/bin/tclsh8.4
set server localhost
puts "server: $server"
set sockChan [socket $server 2500]
fconfigure $sockChan -buffering line
#recieve from server
gets $sockChan line
puts "Client2: Server sais \"$line\""
#send to server
puts $sockChan "I am client2"
flush $sockChan
puts "Sent \"I am client2\" to server"
gets $sockChan line
puts "Client2: Server sais \"$line\""
#close $sockChan
client 2:
#!/usr/bin/tclsh8.4
set server localhost
puts "server: $server"
set sockChan [socket $server 7272]
fconfigure $sockChan -buffering line
#recieve from server
puts $sockChan "I am client3"
flush $sockChan
puts "Sent \"I am client2\" to server"
#recieve from server
gets $sockChan line
puts "Client3: Server sais \"$line\""
gets $sockChan line
puts "Client3: Server sais \"$line\""
#close $sockChan
Use fileevents my friend.
Here's an example how to:
Server code:
#! /usr/bin/env tclsh
proc server {channel} {
set err [catch {set dataLength [gets $channel data]} errmsg]
if {$err != 0} {
puts "Error <$channel>: $errmsg"
puts "Closing connection $channel"
close $channel
} else {
if {$dataLength != -1} {
# Process incoming messages here:
puts "Client $channel sent $data"
puts $channel "Thank you for sending \"$data\""
flush $channel
}
if {[eof $channel]} {
puts "Connection $channel closed"
close $channel
}
}
}
proc accept {channel client port} {
puts "Accepted connection $channel from $client"
fconfigure $channel -translation auto -blocking 0
fileevent $channel readable "server $channel"
}
socket -server accept 1234
vwait forever
Test client code:
#! /usr/bin/env tclsh
proc client {channel} {
set err [catch {set dataLength [gets $channel data]} errmsg]
if {$err != 0} {
puts "Error <$channel>: $errmsg"
puts "Closing connection $channel"
close $channel
} else {
if {$dataLength != -1} {
# Process incoming messages here:
puts "Server sent $data"
}
if {[eof $channel]} {
puts "Connection $channel closed"
close $channel
}
}
}
set connection1 [socket localhost 1234]
fconfigure $connection1 -translation auto -blocking 0
fileevent $connection1 readable "client $channel"
set connection2 [socket localhost 1234]
fconfigure $connection2 -translation auto -blocking 0
fileevent $connection2 readable "client $channel"
puts $connection1 "This message is from connection1"
flush $connection1
puts $connection2 "This message is from connection2"
flush $connection2
puts $connection1 "Second message from connection1"
flush $connection1
puts $connection2 "Second message from connection2"
flush $connection2
after 2000 "close $connection2"
after 2000 "close $connection1"
vwait forever
In the example above the server only opens a single port. You can
easily modify it to accept multiple ports by adding another [socket
-server accept $portnumber].
> bogdan wrote:
>> hey!
>>
>> can anybody tell me if it is possible (in tcl) for a server to open
>> two(or more) sockets and to talk simultaneousley with two clients on
>> these two sockets?...and if yes...do you know any links with such
>> examples?
>>
>> i tried to do it like this but it dosen't work simultaneousley...
>>
>> server:
>>
>> #!/usr/bin/tclsh8.4
>> <snipped non-concurrent code>
>
> Use fileevents my friend.
>
> Here's an example how to:
>
> Server code:
>
... server code elided
>
> proc accept {channel client port} {
> puts "Accepted connection $channel from $client"
> fconfigure $channel -translation auto -blocking 0
> fileevent $channel readable "server $channel"
> }
>
> socket -server accept 1234
> vwait forever
>
>
> Test client code:
... client code elided
> In the example above the server only opens a single port. You can
> easily modify it to accept multiple ports by adding another [socket
> -server accept $portnumber].
Hi Bogdan,
for mor sockets to accept connections just add a server id
to the socket and accept commands:
socket -server {accept Server1} 1234
socket -server {accept Server2} 1235
socket -server {accept Server3} 1236
proc accept {srv channel client port} {
...
}
srv will contain the server id.
Kind regards
Ulrich
Server ID's are only necessary if each port does different things
(which is what the TCP/IP model intended). But from the OPs original
example I had a feeling that he wanted all opened ports to do the same
thing. Kind of like bittorrent opening multiple listening ports but
they are all bittorent anyway. For a single service running on multiple
ports you can simply do:
socket -server accept 1234
socket -server accept 1235
socket -server accept 1236
proc accept {channel client port} {
...
}
Ulrich's example is useful for doing things like:
socket -server {accept http_server} 80
socket -server {accept pop3_server} 110
socket -server {accept custom_server} 1234
proc accept {server channel client port} {
fconfigure $channel -blocking 0
switch -exact $server {
"http_server" {
fileevent $channel readable "httpProc $channel"
}
"pop3_server" {
fileevent $channel readable "pop3Proc $channel"
}
"custom_server" {
fileevent $channel readable "myServerProc $channel"
}
}
}
I'd do this instead:
package require log ;# from tcllib
socket -server {accept httpProc} 80
socket -server {accept pop3Proc} 110
socket -server {accept myServerProc} 1234
proc accept {server channel client port} {
fconfigure $channel -blocking 0
log::logMsg "Connection from ${client}:${port}\
to $channel (service = $server)"
fileevent $channel readable "$server $channel"
}
It's both more flexible and shorter. And keeps a record of who is
connecting to you, which can be very helpful indeed.
Donal.