简体   繁体   English

Java - 监听本地主机和端口

[英]Java - Listen to localhost and port

Sorry in advance for a noob question, but I am learning java and playing with some little projects I find useful and interesting to improve my learning.提前为一个菜鸟问题抱歉,但我正在学习 java 并玩一些我觉得有用且有趣的小项目来提高我的学习。

The current project that I'm stuck on is that I'm trying to create a small desktop app in Java that will "listen" to the text sent to localhost from another application.我坚持的当前项目是我正在尝试在 Java 中创建一个小型桌面应用程序,它将“监听”从另一个应用程序发送到 localhost 的文本。 Basically, if I input an IP and Port, I want the app to listen to any text-type traffic that is sent to that IP and port.基本上,如果我输入 IP 和端口,我希望应用程序侦听发送到该 IP 和端口的任何文本类型的流量。

I tried using some code I found and started adjusting it to meet my needs.我尝试使用我找到的一些代码并开始调整它以满足我的需求。

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);}  

    }  
}  

However, this code only seems to work if you also have a "client" app that is also using Java socket to connect like this:但是,如果您还有一个“客户端”应用程序也使用 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);}  
}  
}  

When I run the server code and the client code, the client sends traffic to the server which displays in the console just fine.当我运行服务器代码和客户端代码时,客户端将流量发送到控制台中显示的服务器就好了。 However, if I try to connect to the server with another app (like PUTTY) to just send raw text to the server, it doesn't display.但是,如果我尝试使用另一个应用程序(如 PUTTY)连接到服务器以将原始文本发送到服务器,它不会显示。 It shows that it connects, but doesn't receive the text.它显示它已连接,但未收到文本。

What am I missing here?我在这里想念什么? Should a socket connection in Java just be able to read and display whatever information is sent to that IP and port? Java 中的套接字连接是否应该能够读取和显示发送到该 IP 和端口的任何信息?

Again, sorry for the noob question.再次,对不起菜鸟问题。

--- UPDATED --- - - 更新 - -

So I incorporated the new approach like this:所以我采用了这样的新方法:

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);}

    }
}  

On the var rawIn = ss.getInputStream, I am getting an error "Cannot resolve method 'getInputStream' in 'ServerSocket'在 var rawIn = ss.getInputStream 上,我收到错误消息“无法解析 'ServerSocket' 中的方法 'getInputStream'

Did I incorporate the suggestion below incorrectly?我是否错误地合并了以下建议?

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

Found an error in how I incorporated it previously.发现我之前如何合并它的错误。 (used ss.getInputStream instead of s.getInputStream). (使用 ss.getInputStream 而不是 s.getInputStream)。

Now I can compile and run without error, but it immediately says socket is not bound yet and exits.现在我可以编译并运行没有错误,但它立即说套接字尚未绑定并退出。 Do I need to specifically bind the IP and Port for it to sit and listen?我是否需要专门绑定 IP 和 Port 才能让它坐下来听?

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

I think I am getting dangerously close.我想我已经危险地接近了。 Here is the code I have in place currently.这是我目前的代码。

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);}

    }
}  

I am getting an error for my bind address that it is looking for a ')' or ';'.我的绑定地址出现错误,它正在寻找“)”或“;”。 I am baffled why that would be the case.我很困惑为什么会这样。

As I understand it from looking at the Java API, my ServerSocket constructor should be saying to listen to port 1234, allow one socket connection at a time, and listen on 127.0.0.1.正如我通过查看 Java API 了解的那样,我的 ServerSocket 构造函数应该说监听端口 1234,一次允许一个套接字连接,并监听 127.0.0.1。

What am I missing?我错过了什么?

TCP/IP connections are just streams of bytes . TCP/IP 连接只是字节流 That is all they are.他们就是这样。 So, if you run readUTF , that is impossible .所以,如果你运行readUTF ,那是不可能的。 How the heck would I know when the string ends?我怎么知道字符串什么时候结束?

Oh, after a newline you say.哦,在你说换行符之后。 You made that up.你编的。 The TCP/IP protocol doesn't state anywhere that there's such a thing as a 'message' that is terminated. TCP/IP 协议不会 state 任何有“消息”之类的东西被终止的地方。 You should be making this stuff up: Protocols are a neccessary part of communication.你应该编造这些东西:协议是通信的必要部分。 However, the key is, you need to 'speak the same protocol' on both sides .但是,关键是,您需要在双方“说相同的协议”。 That's a decision that the TCP/IP spec doesn't include;这是 TCP/IP 规范不包括的决定; you make that on a per-protocol basis.您可以根据每个协议进行此操作。 That's how readUTF exists: It made up arbitrary rules.这就是readUTF的存在方式:它构成了任意规则。 Of course, writeUTF from DataOutputStream uses the same made-up rules.当然,来自DataOutputStreamwriteUTF使用相同的规则。 If you're playing some ballgame and everybody makes up identical rulesets, you're actually playing a game.如果你在玩一些球赛并且每个人都制定了相同的规则集,那么你实际上是在玩游戏。 If one person thinks it's golf and the other thinks its baseball, that's not gonna work.如果一个人认为是高尔夫而另一个人认为是棒球,那是行不通的。

The readUTF protocol evidently disagrees with PuTTY on how messages are terminated. readUTF协议显然不同意 PuTTY 关于如何终止消息。 readUTF is in fact entirely unsuitable for everything . readUTF实际上完全不适合一切 Well, unsuitable for everything except , specifically, reading what DataOutputStream.writeUTF sends.好吧,除了读取DataOutputStream.writeUTF发送的内容之外,不适合所有内容。 So, if you have any interest in reading anything else, you need to delete that part of your code entirely.因此,如果您有兴趣阅读其他内容,则需要完全删除该部分代码。 From the relevant javadoc :相关的 javadoc

  • It reads modified UTF-8.它读取修改后的 UTF-8。 We lost the game on the spot already.我们已经当场输掉了比赛。 UTF-8 is fine. UTF-8 没问题。 Great, even, very obvious.很好,甚至,非常明显。 But modified UTF-8?但是修改了UTF-8? Oh no.不好了。
  • This protocol works by first sending in big-endian 16-bit (so, 2 bytes) the size of the string to be sent, in terms of how many bytes it turns into when converted with java's "modified UTF-8" format.该协议通过首先以大端 16 位(即 2 个字节)发送要发送的字符串的大小,根据使用 java 的“修改后的 UTF-8”格式转换为多少字节来工作。

PuTTY's RAW mode doesn't 'talk' this protocol (in fact, nothing does, except DataOutputStream ). PuTTY 的 RAW 模式不会“谈论”这个协议(事实上,除了DataOutputStream之外,什么都不会)。

Here's what I think you're doing:这就是我认为你正在做的事情:

  • You connect with PuTTY in raw mode.您以原始模式连接 PuTTY。
  • The connection appears to get established.连接似乎已建立。
  • You type a sentence using the keys on your keyboard.您使用键盘上的键键入句子。 Then you hit enter.然后你按回车。

Voila.瞧。 You just made up a protocol.你刚刚制定了一个协议。 You 'spoke a language'.你“说一种语言”。

I think I know enough of PuTTY to know what this looks like (but make sure you set that up in RAW mode:):我想我对 PuTTY 的了解足够了解它的外观(但请确保将其设置为 RAW 模式:):

  • PuTTY just starts tossing the text that appears as you hit keys through a UTF-8 encoder and starts sending those bytes across the line as you type.当您通过 UTF-8 编码器敲击键时,PuTTY 刚刚开始抛出出现的文本,并在您键入时开始跨行发送这些字节。
  • When you hit enter, PuTTY encodes either the character \n or the characters \r\n as UTF-8 sends it (That's 0x0D, 0x0A in bytes).当您按 Enter 键时,PuTTY 将字符\n或字符\r\n编码为 UTF-8 发送它(即0x0D, 0x0A字节)。
  • PuTTY does not close the connection until you close the window and hit OK on the popup that shows up. PuTTY 不会关闭连接,直到您关闭 window 并在出现的弹出窗口上点击 OK。

There.那里。 That's your protocol.那是你的协议。 It's simple.这很简单。 readUTF is not the same protocol, and is not configurable, therefore cannot be used to read this protocol. readUTF不是同一个协议,并且不可配置,因此不能用于读取该协议。

This will read it fine, though:不过,这会很好读:

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);
  }
}

Give that a shot with PuTTY in raw mode, and I bet your server will start echoing exactly what you're typing.在原始模式下使用 PuTTY 试一试,我敢打赌您的服务器将开始准确地回显您正在输入的内容。 Even if you're typing unicode snowmen, Müller, or emojis.即使您输入的是 unicode 雪人、穆勒或表情符号。 Try that: Type this stuff: ß, é, and ☃ and.试试看:输入以下内容:ß、é 和 ☃ 和。 See what falls out.看看会掉什么。 Note that if the wrong stuff falls out, your java app is also speaking in protocols to many layers before it turns into pixels and beams into your eyeballs;请注意,如果错误的东西掉出来了,您的 java 应用程序也会在它变成像素和光束进入您的眼球之前在多层协议中说话; it may be possible your java app is really reading a unicode snowman properly and sending it properly, but a misconfigured terminal is messing it up.您的 java 应用程序可能确实在正确读取 unicode 雪人并将其正确发送,但是配置错误的终端将其弄乱了。 Something to keep in mind.要记住的事情。

Thank you everyone for the help.谢谢大家的帮助。 I actually got it to work.我真的让它工作了。 Here is the finished code I ended up with that listens and displays anything I type into a "client" like PUTTY or whatever so long as I am sending to the appropriate IP and Port.这是我最终得到的完成的代码,它监听并显示我输入到“客户端”中的任何内容,比如 PUTTY 或任何东西,只要我发送到适当的 IP 和端口。

I think my next steps will be to experiment with Swing or JavaFx to put a UI around this and create an executable jar file to make a little desktop app that does this.我认为我的下一步将是尝试使用 Swing 或 JavaFx 围绕此放置一个 UI 并创建一个可执行的 jar 文件来制作一个执行此操作的小型桌面应用程序。

Thanks again for the help!再次感谢您的帮助!

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);}

    }
} 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM