【发布时间】:2013-11-23 17:02:40
【问题描述】:
我正在尝试用 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();
}
}
}
【问题讨论】:
-
我认为外部端口开始应该是0,外部端口结束应该是65535。通常客户端的操作系统会随机选择一个端口来建立传出连接。您告诉客户端连接到您路由器的公共 IP 的 33333 端口,但它选择用作源的端口可以是任何东西。
-
客户端中的close()关闭连接。您是否尝试过在同一个 JVM 中同时运行服务器和客户端并添加一些 println 语句来查看事件发生的顺序?
-
@NormR 是的,这两个程序都在同一台 PC 上运行,因此在同一个 JVM 中。在关闭套接字之前,客户端必须向服务器发送一个 Hello 消息,然后等待服务器的回复。但是程序在消息传输之前就崩溃了。
-
@mti2935 试过1-65535,还是不行。服务器仍然重置连接,客户端总是超时。客户端打印
Connecting to 174.128.255.227 on port 33333,IP 地址始终相同。然而服务器打印Just connected to /114.43.16.250:6000,IP地址和端口每次都改变。我就是不明白。 -
@vesintio 你说:在同一台PC上,所以在同一个JVM中,你是怎么做到的?当我这样做时,我有另一个 main() 方法,它从线程中调用 Server 和 Client 类的 main() 方法。然后,所有打印输出在运行我的特殊主程序的一个 JVM 中按时间顺序排列。