Java和TCL之间的Socket编程

3

我需要写一个程序,实现Java程序通过Socket编程与TCL程序进行通信。我已经成功地分别尝试了TCL和Java的Socket编程。但是,由于我需要将Java程序作为客户端套接字,而TCL程序作为服务器,因此我无法成功地完成。

TCL服务器程序

set svcPort 9999

#Implement the service
# This example just writes the info back to the client...

proc doService {sock msg} {
  puts $sock "$msg"
}

# Handles the input from the client and  client shutdown
proc  svcHandler {sock} {
  set l [gets $sock]    ;# get the client packet
   puts "The packet from the client is $l"
  if {[eof $sock]} {    ;# client gone or finished
     close $sock        ;# release the servers client channel
  } else {
    doService $sock $l
  }
}

# Accept-Connection handler for Server. 
# called When client makes a connection to the server
# Its passed the channel we're to communicate with the client on, 
# The address of the client and the port we're using 
#
# Setup a handler for (incoming) communication on 
# the client channel - send connection Reply and log connection
proc accept {sock addr port} {

  # if {[badConnect $addr]} {
  #     close $sock
  #     return
  # }

  # Setup handler for future communication on client socket
  fileevent $sock readable [list svcHandler $sock]

  # Read client input in lines, disable blocking I/O
  fconfigure $sock -buffering line -blocking 0

  # Send Acceptance string to client
  puts $sock "$addr:$port, You are connected to the echo server."
  puts $sock "It is now [exec date]"

  # log the connection
  puts "Accepted connection from $addr at [exec date]"
}


# Create a server socket on port $svcPort. 
# Call proc accept when a client attempts a connection.
socket -server accept $svcPort
vwait events    ;# handle events till variable events is set

并且

Java客户端程序

// File Name GreetingClient.java

import java.net.*;
import java.io.*;

public class GreetingClient
{
   public static void main(String [] args)
   {
      String serverName = args[0];
      int port = Integer.parseInt(args[1]);
      try
      {
         System.out.println("Connecting to " + serverName
                             + " on port " + port);
         Socket client = new Socket(serverName, port);
         System.out.println("Just connected to "
                      + client.getRemoteSocketAddress());
         OutputStream outToServer = client.getOutputStream();
         DataOutputStream out =
                       new DataOutputStream(outToServer);

         out.writeUTF("Hello from "
                      + client.getLocalSocketAddress()+"\n");
         InputStream inFromServer = client.getInputStream();
         DataInputStream in =
                    new DataInputStream(inFromServer);
         System.out.println("Server says " + in.readUTF());
         client.close();
      }catch(IOException e)
      {
         e.printStackTrace();
      }
   }
}
  1. 我启动了服务器,但服务器没有显示任何东西。

  2. 我启动了客户端,服务器显示“接受来自于(client ip address)的连接,时间为2013年5月6日星期一02:50:21 PDT”,客户端显示“正在连接到(server ip address) 的9999端口,已连接上/(server ip address):9999”。

  3. 当在客户端执行out.writeUTF时,服务器会显示“来自客户端的数据包是“Hello from: /<client IP地址>:<client 端口号>”。但是客户端并没有像应该显示服务器的回复那样显示任何内容。客户端进程没有退出,而是等待执行“System.out.println("Server says " + in.readUTF());”。

请问有人可以帮忙解决问题并告诉为什么客户端连接后无法看到服务器的回复,但却能向服务器发送数据吗?

谢谢!


请编辑问题,包括您使用的代码,而不是使用网址链接。 - Maximin
我在 Java 代码中进行的另一个修改是 "out.writeUTF("Hello from : "+ client.getLocalSocketAddress()+"\n");"。 - Peeyushpd
如果您通过编辑这样做,那么对于我们来帮助您将会非常有用。 - Maximin
您可以使用telnet手动测试服务器。例如:telnet localhost 9999 - TrojanName
这些程序是从工作的套接字编程示例中提取的。我已经对它们进行了单独测试。因此,当使用TCL客户端套接字程序进行测试时,服务器程序运行良好。 - Peeyushpd
@user 他们正在使用不同的协议;writeUTF并没有发送你所期望的内容... - Donal Fellows
2个回答

4

你的Java客户端正在使用 DataOutputStream.writeUTFDataInputStream.readUTF 方法; 这些方法在socket上使用了一个简单的帧协议,但该Tcl服务器并不支持该协议,这会导致一些错误。

这个帧协议非常简单。首先,将字符串的长度(以字节为单位)写入一个两字节的大端("网络端")整数中。然后发送字符串的UTF-8字节。这很直接了当,但你需要知道才能正确处理它。在这种方式下,你还需要将socket设置为二进制模式;你不再使用基于行的协议。

# 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

请注意,如果您打算发送长消息,则可能需要编写代码来处理短读取。但是对于测试而言,它应该可以工作。 - Donal Fellows
1
此外,如果您投票支持此答案或将其标记为已接受,请_同时给Johannes的答案点个赞_,因为这只是他所指出的事情的一个实际应用示例。 - Donal Fellows
我按照你建议的修改了代码,但还是无法正常工作。在Java程序中,它停留在in.readUTF()处。我忘了提到,我的Java客户端程序运行在Windows系统上,而TCL服务器程序运行在Linux机器上,我不知道这会有多大影响。我已成功地从Windows系统上的Java程序执行了相同Linux系统上的TCL脚本。我曾经使用JSch库来完成此操作,并且能够得到结果。但我必须使用套接字编程来使其交互式。 - Peeyushpd
现在可以工作了。不知道为什么之前不能工作,现在为什么能工作了。 - Peeyushpd

3

您正在使用两种不同的通信方法:


我能够在服务器上读取客户端发送的内容,但反过来却不行。我甚至尝试了以下代码:proc doService {sock msg} { puts $sock "FROM SERVER" }但是没有起作用。 - Peeyushpd

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接