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.
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. 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.
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:
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. 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?
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'
Did I incorporate the suggestion below incorrectly?
----- UPDATE 2 ----
Found an error in how I incorporated it previously. (used ss.getInputStream instead of 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?
---- UPDATE 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.
What am I missing?
CodePudding user response:
TCP/IP connections are just streams of bytes. That is all they are. So, if you run readUTF, that is impossible. 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. 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; you make that on a per-protocol basis. That's how readUTF exists: It made up arbitrary rules. Of course, writeUTF from DataOutputStream uses the same made-up rules. 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 is in fact entirely unsuitable for everything. Well, unsuitable for everything except, specifically, reading what DataOutputStream.writeUTF sends. So, if you have any interest in reading anything else, you need to delete that part of your code entirely. From the relevant javadoc:
- It reads modified UTF-8. We lost the game on the spot already. UTF-8 is fine. Great, even, very obvious. But modified 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.
PuTTY's RAW mode doesn't 'talk' this protocol (in fact, nothing does, except DataOutputStream).
Here's what I think you're doing:
- You connect with PuTTY in raw mode.
- 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 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.
- When you hit enter, PuTTY encodes either the character
\nor the characters\r\nas UTF-8 sends it (That's0x0D, 0x0Ain bytes). - PuTTY does not close the connection until you close the window and hit OK on the popup that shows up.
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.
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. Even if you're typing unicode snowmen, Müller, or emojis. Try that: Type this stuff: ß, é, and ☃ and
