3

我正在尝试为数据收集项目用 Java 开发服务器端程序。

这是架构:

我有一个远程电子设备,它定期收集数据并将其发送回服务器。该设备配备了一张激活了 GPRS 连接的 SIM 卡,因此可以将其视为一台可以上网的电脑。在将数据发送回服务器之前,它必须知道服务器的 IP 地址。

由于通过我的 ISP 获得静态 IP 太贵了,所以我决定尝试动态 DNS(DDNS)。我已经在我的 PC 上安装了 DDNS 客户端,并在我的路由器中配置了端口转发,如下所示:

External Port Start: 33333
External Port End: 33333
Protocol: TCP
Internal Port Start: 33333
Internal Port End: 33333
Server IP Address: 192.168.0.100 // My PC's IP Adress.

然后我尝试在我的 PC 上运行一个简单的服务器/客户端程序(是的,它们都在同一台 PC 上)。DataInputStream他们没有做任何复杂的事情,只是使用和DataOutputStream类发送和接收一些字符串。

客户端可以连接到服务器,服务器可以接受连接(端口转发有效?!)。但是当他们试图读取或发送数据时,他们都会抛出一个 IOException。服务器说Connection reset,几秒钟后,客户端得到timeout.

似乎当服务器接受新连接时,他们会选择一个未在端口转发设置中指定的任意新端口号,这是问题吗?

我想知道 IOException 的实际原因是什么,为什么他们无法读取或写入数据,以及解决问题的任何建议?

非常感谢。

服务器代码:

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

public class GreetingServer extends Thread
{
   private ServerSocket serverSocket;

   public GreetingServer(int port) throws IOException
   {
      serverSocket = new ServerSocket(port);
   }

   public void run()
   {
      while(true)
      {
         try
         {
            System.out.println("Waiting for client on port " +
            serverSocket.getLocalPort() + "...");
            Socket server = serverSocket.accept();
            System.out.println("Just connected to "
                  + server.getRemoteSocketAddress());
            DataInputStream in =
                  new DataInputStream(server.getInputStream());
            System.out.println(in.readUTF());
            DataOutputStream out =
                 new DataOutputStream(server.getOutputStream());
            out.writeUTF("Thank you for connecting to "
              + server.getLocalSocketAddress() + "\nGoodbye!");
            server.close();
         }catch(SocketTimeoutException s)
         {
            System.out.println("Socket timed out!");
            break;
         }catch(IOException e)
         {
            e.printStackTrace();
            break;
         }
      }
   }
   public static void main(String [] args)
   {
      int port = 33333;
      try
      {
         Thread t = new GreetingServer(port);
         t.start();
      }catch(IOException e)
      {
         e.printStackTrace();
      }
   }
}

客户端代码: xxxxxxx.xicp.net是我的免费域名,服务器监听端口33333

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

public class GreetingClient
{
   public static void main(String [] args)
   {
      InetAddress ip;
      String serverName;
      int port = 33333;
      try
      {
         ip = InetAddress.getByName("xxxxxxx.xicp.net");
         serverName = ip.getHostAddress();
         System.out.println("Connecting to " + serverName
                             + " on port " + port);
         Socket client = new Socket(ip, port);
         System.out.println("Just connected to "
                      + client.getRemoteSocketAddress());
         OutputStream outToServer = client.getOutputStream();
         DataOutputStream out =
                       new DataOutputStream(outToServer);

         out.writeUTF("Hello from "
                      + client.getLocalSocketAddress());
         InputStream inFromServer = client.getInputStream();
         DataInputStream in =
                        new DataInputStream(inFromServer);
         System.out.println("Server says " + in.readUTF());
         client.close();
      }catch(IOException e)
      {
         e.printStackTrace();
      }
   }
}
4

2 回答 2

0

我的猜测:我在路由器中配置了 NAT,因此所有传入连接都转发到我 PC 的端口 33333。一旦客户端连接到服务器,它将选择另一个端口,例如 5000,与服务器通信。当服务器尝试向客户端发送某些内容时,它会将其发送到端口 5000。AS 在 NAT 中设置端口 5000 不转发,传输失败。我不确定,需要测试。

好的,已确认。我尝试使用手机的 3G 连接在笔记本电脑上运行客户端,而台式 PC 上的服务器连接到路由器。端口 33333 转发给台式机。现在它完美地工作了。

于 2013-11-14T15:23:52.003 回答
0

我知道这是不久前的事了,但一开始我的连接也有同样的问题。

您的问题源于关闭 DataOutputStream/DataInputStream 流。基本上你想让它们保持打开状态,并在编写完成后调用刷新。

但是,如果您尝试读取的字节数多于已发送的字节数,这对于任一连接都可能存在问题。我建议在您的代码(也称为哨兵)中添加一个消息“标头”,以告诉接收方它将读取多少字节。

同样对于快速数据遍历尝试 BufferedOutputStream/BufferedInputStream,速度提升令人难以置信。

于 2014-05-31T21:27:04.727 回答