【问题标题】:Java - Listen to localhost and portJava - 监听本地主机和端口
【发布时间】:2022-01-23 07:46:30
【问题描述】:

对于一个菜鸟问题,我很抱歉,但我正在学习 Java,并且正在玩一些我觉得有用且有趣的小项目,以提高我的学习水平。

我目前坚持的项目是我正在尝试用 Java 创建一个小型桌面应用程序,该应用程序将“监听”从另一个应用程序发送到 localhost 的文本。基本上,如果我输入 IP 和端口,我希望应用程序监听发送到该 IP 和端口的任何文本类型的流量。

我尝试使用我找到的一些代码并开始对其进行调整以满足我的需要。

package localHostApp;

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

public class Server2 {  

    public static void main(String[] args){  

        try{  
            ServerSocket ss=new ServerSocket(1234);  
            Socket s=ss.accept();//establishes connection   
            DataInputStream dis=new DataInputStream(s.getInputStream());  
            String  str=(String)dis.readUTF();  
            System.out.println("message= "+str);  

            ss.close();  

        }catch(Exception e){System.out.println(e);}  

    }  
}  

但是,如果您还有一个“客户端”应用程序也使用 Java 套接字进行连接,则此代码似乎才有效:

import java.io.*;  
import java.net.*;  
public class MyClient {  
public static void main(String[] args) {  
try{      
Socket s=new Socket("localhost",1234);  
DataOutputStream dout=new DataOutputStream(s.getOutputStream());  
dout.writeUTF("Hello Server");  
dout.flush();  
dout.close();  
s.close();  
}catch(Exception e){System.out.println(e);}  
}  
}  

当我运行服务器代码和客户端代码时,客户端将流量发送到控制台中显示的服务器就好了。但是,如果我尝试使用另一个应用程序(如 PUTTY)连接到服务器以将原始文本发送到服务器,它不会显示。它显示它已连接,但没有收到文本。

我在这里缺少什么? Java 中的套接字连接是否应该能够读取和显示发送到该 IP 和端口的任何信息?

再次,对于菜鸟问题​​感到抱歉。

--- 已更新 ---

所以我采用了这样的新方法:

import java.io.*;
import java.net.*;
import java.nio.charset.StandardCharsets;

public class Server {

    public static void main(String[] args){

        try{
            ServerSocket ss=new ServerSocket();
            Socket s=ss.accept();//establishes connection
            var rawIn = ss.getInputStream();
            var in = new BufferedReader(new InputStreamReader(rawIn, StandardCharsets.UTF_8)); {

        while (true){
            String cmd = in.readLine().trim();
            if (cmd == null) break; //client is hung up
            if (cmd.isEmpty()) continue; //empty line was sent
            System.out.println("Client sent: " + cmd);
        }
            }

        }catch(Exception e){System.out.println(e);}

    }
}  

在 var rawIn = ss.getInputStream 上,我收到错误消息“无法解析 'ServerSocket' 中的方法 'getInputStream'

我是否错误地采纳了以下建议?

----- 更新 2 ----

在我之前的合并方式中发现了一个错误。 (使用 ss.getInputStream 而不是 s.getInputStream)。

现在我可以编译和运行没有错误,但它立即说套接字尚未绑定并退出。我是否需要专门绑定 IP 和端口才能让它坐下来听?

---- 更新 3 -----

我想我已经危险地接近了。这是我目前的代码。

import java.io.*;
import java.net.*;
import java.nio.charset.StandardCharsets;

public class Server {

    public static void main(String[] args){

        try{
            ServerSocket ss=new ServerSocket(1234, 1, 127.0.0.1);
            Socket s=ss.accept();//establishes connection
            var rawIn = s.getInputStream();
            var in = new BufferedReader(new InputStreamReader(rawIn, StandardCharsets.UTF_8)); {

        while (true){
            String cmd = in.readLine().trim();
            if (cmd == null) break; //client is hung up
            if (cmd.isEmpty()) continue; //empty line was sent
            System.out.println("Client sent: " + cmd);
        }
            }

        }catch(Exception e){System.out.println(e);}

    }
}  

我的绑定地址出现错误,它正在寻找')' 或';'。我很困惑为什么会这样。

根据我从 Java API 中的理解,我的 ServerSocket 构造函数应该说监听端口 1234,一次允许一个套接字连接,并监听 127.0.0.1。

我错过了什么?

【问题讨论】:

  • 如果您使用的是Putty,您需要将其设置为Telnet模式,或者直接使用Telnet客户端。 Putty 的默认模式是 SSH,除了发送原始击键之外,它还会执行许多其他握手操作。
  • 对于ServerSocket 的第三个参数,第三个参数是InetAddress(或子类)类型的对象。 127.0.0.1 不是任何类型的对象,也根本不是标记,因此出现语法错误。 Java 有不带小数点的整数和带一个小数点的浮点数,但没有带三个小数点的数字。您想要稍微令人困惑的InetAddress.getByName("127.0.0.1"),因为原始的伯克利套接字 API(Java 基本上在其上建模)使用(在 C 中)gethostbyname() 来处理 包含主机名 或 地址。
  • 或者你可以使用方便的方法InetAddress.getLoopbackAddress()——这是通常称为'localhost'的正式名称,而Java使用InetAddress.getLocalHost()来表示实际上不同的东西(主机声称网络可见地址)。

标签: java sockets


【解决方案1】:

TCP/IP 连接只是字节流。他们就是这样。所以,如果你运行readUTF,那不可能。我怎么知道字符串何时结束?

哦,在你说换行符之后。你编的。 TCP/IP 协议在任何地方都没有说明存在终止的“消息”之类的东西。你应该编造这些东西:协议是通信的必要部分。然而,关键是,您需要在双方上“使用相同的协议”。这是 TCP/IP 规范不包括的决定;您可以根据每个协议进行此操作。这就是readUTF 的存在方式:它构成了任意规则。当然,来自DataOutputStreamwriteUTF 使用相同的编造规则。如果你在玩一些球赛并且每个人都制定了相同的规则集,那么你实际上是在玩游戏。如果一个人认为是高尔夫而另一个人认为是棒球,那是行不通的。

readUTF 协议显然不同意 PuTTY 关于如何终止消息。 readUTF 实际上完全不适合所有事情。嗯,不适合所有除了,特别是阅读DataOutputStream.writeUTF 发送的内容。因此,如果您有兴趣阅读其他内容,则需要完全删除该部分代码。来自relevant javadoc

  • 它读取修改后的 UTF-8。我们已经当场输掉了比赛。 UTF-8 很好。很好,甚至,非常明显。但是修改了 UTF-8?哦不。
  • 此协议的工作原理是首先以大端 16 位(即 2 个字节)发送要发送的字符串的大小,根据使用 java 的“修改后的 UTF-8”转换时它变成多少字节格式。

PuTTY 的 RAW 模式不会“谈论”这个协议(事实上,除了DataOutputStream,什么都不会。

这就是我认为你正在做的事情:

  • 您以原始模式连接 PuTTY。
  • 连接似乎已建立。
  • 您使用键盘上的键键入句子。然后按回车键。

瞧。你刚刚制定了一个协议。你“说一种语言”。

我想我对 PuTTY 的了解足够了解它的外观(但请确保将其设置为 RAW 模式!):

  • PuTTY 只是开始通过 UTF-8 编码器将您击键时出现的文本扔掉,并在您键入时开始跨行发送这些字节。
  • 当您按 Enter 键时,PuTTY 将字符 \n 或字符 \r\n 编码为 UTF-8 发送它(即 0x0D, 0x0A 以字节为单位)。
  • PuTTY 不会关闭连接,直到您关闭窗口并在出现的弹出窗口上点击 OK。

那里。那是你的协议。这很简单。 readUTF 不是同一个协议,不可配置,因此不能用来读取这个协议。

不过,这会很好读:

try (Socket s = socketServer.accept();
  var rawIn = s.getInputStream();
  var in = new BufferedReader(new InputStreamReader(rawIn, StandardCharsets.UTF_8))) {

  while (true) {
    String cmd = in.readLine().trim();
    if (cmd == null) break; // client hung up
    if (cmd.isEmpty()) continue; // sent an empty line
    System.out.println("Client sent: " + cmd);
  }
}

在原始模式下使用 PuTTY 试一试,我敢打赌,您的服务器将开始准确地回显您正在输入的内容。即使您输入的是 unicode 雪人、Müller 或表情符号。试试看:输入以下内容:ß、é、☃ 和?。看看会掉什么。请注意,如果出现错误的内容,您的 Java 应用程序也会在协议中与许多层进行对话,然后才会变成像素并射入您的眼球;可能您的 Java 应用程序确实正确读取了 unicode 雪人并正确发送,但是配置错误的终端将其弄乱了。需要记住的一点。

【讨论】:

  • 哇,好棒的回复,谢谢!
  • 我确实利用了您发布的内容(尝试学习,而不仅仅是复制),但我在以下方面遇到错误:var rawIn == ss.getInputStream 行
  • 它是s,getInputStream,因为只有一个 ServerSocket 通常在一个循环中接受客户端套接字,通常在它自己的线程中处理该套接字。
【解决方案2】:

感谢大家的帮助。我真的让它工作了。这是我最终得到的完成代码,它监听并显示我在“客户端”(如 PUTTY)中输入的任何内容,只要我发送到适当的 IP 和端口即可。

我认为我的下一步将是尝试使用 Swing 或 JavaFx 来围绕它放置一个 UI,并创建一个可执行的 jar 文件来制作一个执行此操作的小型桌面应用程序。

再次感谢您的帮助!

import java.io.*;
import java.net.*;
import java.nio.charset.StandardCharsets;

public class Server {

    public static void main(String[] args){

        try{
            ServerSocket ss=new ServerSocket(1234, 1, InetAddress.getByName("127.0.0.1"));
            Socket s=ss.accept();//establishes connection
            var rawIn = s.getInputStream();
            var in = new BufferedReader(new InputStreamReader(rawIn, StandardCharsets.US_ASCII)); {

        while (true){
            String cmd = in.readLine().trim();
            if (cmd == null) break; //client is hung up
            if (cmd.isEmpty()) continue; //empty line was sent
            System.out.println("Client sent: " + cmd);
        }
            }

        }catch(Exception e){System.out.println(e);}

    }
} 

【讨论】:

    猜你喜欢
    • 2019-07-04
    • 1970-01-01
    • 2016-03-29
    • 1970-01-01
    • 2016-12-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-24
    相关资源
    最近更新 更多