Your Java client is using DataOutputStream.writeUTF
and DataInputStream.readUTF
; these use a simple framing protocol on top of the socket, which that Tcl server doesn't speak. This makes things go wrong.
The framing protocol is pretty simple. First, the length of the string (in bytes) is written as a two-byte big-endian ("network-endian") integer. Then the UTF-8 bytes of the string are sent. Pretty straight-forward, but you need to know in order to actually handle it right. You also want to put the socket in binary mode when working this way; you're not using a line-oriented protocol any more.
# Two helper procedures that know how to do the framing encoding/decoding
proc writeJavaUTF {sock msg} {
set data [encoding convertto utf-8 $msg]
puts -nonewline $sock [binary format "S" [string length $data]]$data
}
proc readJavaUTF {sock} {
binary scan [read $sock 2] "S" len
set data [read $sock [expr {$len & 0xFFFF}]]
return [encoding convertfrom utf-8 $data]
}
# This is your sample code, stripped of comments and adapted
set svcPort 9999
proc doService {sock msg} {
writeJavaUTF $sock "$msg"; # <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
}
proc svcHandler {sock} {
set l [readJavaUTF $sock]; # <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
puts "The packet from the client is $l"
if {[eof $sock]} {
close $sock
} else {
doService $sock $l
}
}
proc accept {sock addr port} {
fileevent $sock readable [list svcHandler $sock]
# Next *three* lines are changed!
fconfigure $sock -buffering line -blocking 0 -translation binary
writeJavaUTF $sock "$addr:$port, You are connected to the echo server."
writeJavaUTF $sock "It is now [exec date]"
puts "Accepted connection from $addr at [exec date]"
}
socket -server accept $svcPort
vwait events