【问题标题】:Socket communication between C and javaC和java之间的套接字通信
【发布时间】:2011-10-19 06:23:43
【问题描述】:

我有一个客户端和一个服务器都在 C 中运行。我的任务是介绍 java 程序,在该程序中我为 C 客户端创建一个服务器,并为 C 服务器创建一个客户端。我成功地尝试正确设置连接。然而,问题在于两个 C 程序之间的数据通信。下面是我在我的java程序中写的:

while(true){
while((userInput1=br1.readLine())!=null||(userInput2=br2.readLine())!=null){
   if(userInput1=!null){
      bw1.write(userInput1);
      bw1.flush();
   }
   if(userInput2=!null){
      bw2.write(userInput2);
      bw2.flush();
   }
}    

在调试上面的时候,可以看到执行卡在第二个while语句,这意味着输入流一直在等待C客户端的输入。我正在为流使用 BufferedReader 和 BufferedWriter。 C 客户端和服务器使用 send 和 recv 函数进行通信。 请帮助任何输入以使 java 程序帮助两个 C 程序相互通信,因为它们没有这个。

【问题讨论】:

  • 我对 Java 网络了解不多,但在我看来,用于读者的套接字是阻塞的。您需要使用非阻塞套接字。
  • 你有两个套接字连接,当第一个连接不发送数据时,你想要第二个连接块吗?您是否有任何理由不使用线程,以便可以独立读取套接字连接。如果两个连接之间存在依赖关系,您能说一下它是什么吗?

标签: java c sockets network-programming communication


【解决方案1】:

你是否正确考虑过 Java 的“短路”或运算符的影响?

与 ||如果第一个子句为真,则永远不会评估第二个子句。

   while(
        (userInput1=br1.readLine())!=null ||
        (userInput2=br2.readLine())!=null) {

所以你读成功了

 userInput1=br1.readLine())!=null

并立即输入您的处理,然后返回 while 并再次将下一行读入 userInput1。因此 userInput2 永远不会收到值。

您需要单独的逻辑,例如

    read first line
    read second line 

但是,当读取 line2 并且数据还没有准备好时,你应该怎么做呢?再试一次?您接下来阅读的行是预期的 line2 还是新的 line1?这很难做到。

我不希望在我的协议中依赖两个单独的 readlines。

【讨论】:

  • 我用过||操作员要注意,在某个时间只有客户端或服务器准备好提供输入,而另一个则等待该输入或参与自己的某些操作。所以每次while循环开始时,任何一个条件都应该成立(输入将在客户端或服务器端给出),因此应该将输入写入相应的输出流。
  • 并让您注意到,虽然执行停留在第二个 while 语句,但如果我终止 C 客户端程序,现在已经给出的输入将写入服务器的输出流并且服务器开始响应该输入,即,只有当客户端程序结束时,它才会意识到它已经到达缓冲区的末尾。请问有什么意见吗?
  • 所以你有混合客户端和服务器端的代码?抱歉没有意识到这一点。在我看来,这不是一个干净的设计。
  • 所以你建议编写 2 个独立的 java 程序,一个作为实际 C 服务器的客户端,另一个作为实际 C 客户端的服务器。然后在这个客户端-服务器二重奏之间建立连接。如果我在这里显得过度使用人,我很抱歉。我只是在学习中..请指教..
  • 是的,单独的客户端和服务器程序,或者至少单独的处理客户端和服务器端的方法。我声称通过分离关注点,您的代码将更容易理解。
【解决方案2】:
while((userInput1=br1.readLine())!=null||(userInput2=br2.readLine())!=null){

这种情况意味着您将在从 br2 读取任何内容之前一直读取 br1 到 EOS。这真的是你的意图吗?

相反,如果你被困在br2.readLine() 这意味着两件事:(a) br1 在 EOS,并且 (b) 与 br2 关联的对等点没有发送任何东西,或者至少没有发送任何东西。 t 发送了一个以换行符结束的行。

您是否可能会误以为没有数据可供读取时 readLine() 返回 null?

另外,您正在读取由换行符终止的行,这些行被 readLine() 调用删除,然后在没有任何换行符的情况下将它们写出来,这几乎是不正确的。

在我看来,您真正编写的是代理,在这种情况下,每个套接字需要两个线程,一个从 A 读取并写入 B,另一个从 B 读取并写入 A。如果是您应该使用 InputStreams 和 OutputStreams 而不是 Readers 和 Writers 的代理,因为您可能没有理由检查数据,因此您不应该通过使用 Readers 隐含的 byte->char 和 char->byte 转换过程和作家。编写代理时还有一些微妙之处,但我会等待您的确认,然后再解释它们。

【讨论】:

  • 我现在有 2 个线程可以很好地完成这项工作。我使用 br1.ready() 和 br2.ready() 来了解流中是否有任何数据。并且还使用一种技术在原始通信程序中添加奇偶校验字符以通过我的代理发送数据。我现在正在读取数据,直到遇到这个奇偶校验并将其发送到通信部分的另一端。这似乎工作正常。是的,我仍然继续使用 InputStreamReader 和 OutputStreamWriter。如果有更好的方法来处理这个问题,请赐教。谢谢。
  • @abhiram 不要使用 ready()。你有两个线程。堵塞。无论如何,线程还会做什么?如果你知道数据只是字符数据,你应该只使用 Readers 和 Writers。如果有任何现在的未来或遥远的可能性它是二进制的,请使用 Streams:换句话说,使用流。当您仅在客户端和服务器之间进行调解时,我不知道为什么您需要这种奇偶校验,即您是代理。只需双向复制字节即可。
【解决方案3】:

我使用奇偶校验字符的原因是为了解释流的结尾。否则,仅使用 read() 会使程序永远停止输入(即使在实际发送了所有数据之后)。我正在通过以下方式使用 ready():

//The proxy client
while(true){
    if(br1.ready()){
        while((temp1=br1.read())!=(int)par)
            userInput1=userInput1+(char)temp1;
        System.out.println("Input to Actual Server: " + userInput1);
        bw1.write(userInput1);
        bw1.flush();
        System.out.flush();
        userInput1="";
        temp1=0;
        }
        if(br2.ready()){
            while((temp2=br2.read())!=(int)par)
                userInput2=userInput2+(char)temp2;
            System.out.println("Response from Actual Server: " + userInput2);
            userInput2=userInput2+par;
            bw2.write(userInput2);
            bw2.flush();
            System.out.flush();
            userInput2="";
            temp2=0;
        }
}

//The proxy server
while(true){
     if(br1.ready()){
         while((temp1=br1.read())!=(int)par)
                         userInput1=userInput1+(char)temp1;
         System.out.println("Input from Actual Client: " + userInput1);
         userInput1=userInput1+par;
         bw1.write(userInput1);
         bw1.flush();
         System.out.flush();
         userInput1="";
         temp1=0;
     }
     if(br2.ready()){
         while((temp2=br2.read())!=(int)par)
                userInput2=userInput2+(char)temp2;
         System.out.println("Response to Actual Client: " + userInput2);
         bw2.write(userInput2);
         bw2.flush();
         System.out.flush();
         userInput2="";
         temp2=0;
     }
}

如果使用ready()有任何问题,请提出建议。

【讨论】:

  • 好吧,我对上面做了一些改动。使用 BuffereInputStream 中的 available() 方法来了解流中是否还有数据,因此不需要使用奇偶校验字符。不再需要使用 ready()。
猜你喜欢
  • 2012-01-26
  • 1970-01-01
  • 1970-01-01
  • 2015-05-29
  • 1970-01-01
  • 1970-01-01
  • 2016-11-26
  • 1970-01-01
  • 2021-06-20
相关资源
最近更新 更多