I am trying to learn a bit more about networking, sockets, udp etc..
// main method:
Socket clientSocket = new Socket("localhost", 10007);
PrintWriter clientSocketOutputStream = new PrintWriter(clientSocket.getOutputStream(), true);
BufferedReader clientSocketInputStream = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
Scanner userInputReader = new Scanner(System.in);
String providedInput;
while ((providedInput = userInputReader.nextLine()) != null) {
clientSocketOutputStream.println(providedInput);
displayOnConsole("You have provided text: " + providedInput);
String responseFromTheServer = clientSocketInputStream.readLine();
System.out.println("Server has responded: " + responseFromTheServer);
System.out.println(waitingForInputText);
}
// rest of the code...
So this little code I have works well. ( I have a ServerSocket which runs fine on localhost ). However now I am trying to do this by GUI, not by commandline.
I have a simple JTextArea, and a JButton. I am stuck at:
while ((providedInput = userInputReader.nextLine()) != null)
How can I invoke the clientSocketOutputStream, everytime I hit the Jbutton and print the text from the JTextArea?
Shall I put a dead while(true) loop just to make sure the socket is waiting? Something tells me there must be another way.
Just put a listener on the the text area to detect when the content changes and then send whatever you like onto the output stream based on the change made.
In general a text area doesn't map well to this though as a text area you can edit anywhere, you are probably better having a read only text area to display the history - and then having a single text entry box (or a smaller text area) and a button that you press to send everything in the smaller box on the screen out on the stream, append the sent text to the end of the history, and then wipe the smaller box.
You can also add an event on a key press (for example the return key) to trigger the send-and-move-to-history process.
Related
I want to have Server - Client relation. Once client gets connected to a server, server sends a message to a client every 1.5 seconds. Server doesn't do anything with messages from client for simplicity. In client's code, I want to use System.in to send messages to server (which don't mean anything) and when I send it, I want to read server's response (all accumulated messages from server). Code is not a snippet, but "real code".
Client:
public class ClientClass {
public static final String IP_ADDRESS = "127.0.0.1";
public static final int PORT = 9090;
public static void main (String[] args) throws IOException {
Socket socket = new Socket (IP_ADDRESS,PORT);
PrintWriter output = new PrintWriter (socket.getOutputStream (),true);
BufferedReader input = new BufferedReader (new InputStreamReader (socket.getInputStream ()));
BufferedReader keyboard = new BufferedReader (new InputStreamReader (System.in));
while (true){
System.out.println ("Enter message you want to send to server:");
String msg = keyboard.readLine ();
output.println (msg);
String serverResponses = input.readLine ();
while (serverResponses!=null){
System.out.println (serverResponses);
serverResponses=input.readLine ();
}
}
}
}
Server:
public class ServerClass {
public static int PORT = 9090;
public static void main (String[] args) throws IOException, InterruptedException {
ServerSocket server = new ServerSocket (PORT);
Socket client = server.accept ();
PrintWriter output = new PrintWriter (client.getOutputStream (),true);
while (true){
output.println ("hello from server");
Thread.sleep (1500);
}
}
}
//My comment: readLine() method in client is blocking, so I can't read server's messages until I actually read something from keyboard. That is why I have loop to "pick up" all lines from inputStream. I expect that once I read all the lines, variable stringResponses gets null and breaks from inner while loop. Then I thought that I would get a print to console of "enter message you want to send to server" found in outer loop. Unfortunately, my code never breaks out from inner while loop and I want to know why. How is it never null, when I am writing to a stream every 1.5s, meaning there is plenty of time for it to be null and break from loop.
ACTUAL OUTPUT:
Enter message you want to send to server:
hey! //this is what I typed
hello from server
hello from server
hello from server
//these three popped immediately, as they accumulated.
hello from server
hello from server
hello from server
hello from server
//keeps printing "hello from server" every 1.5s and never comes back to "enter your message" -WHY?
readLine returns null at the end of stream. Since the Server Socket isn't closed. It is never null in your inner loop.
Link - https://docs.oracle.com/javase/7/docs/api/java/io/BufferedReader.html#readLine()
A String containing the contents of the line, not including any
line-termination characters, or null if the end of the stream has been
reached
What do you expect the behaviour when readLine got invoked in a loop on your keyboard object ?
String msg = keyboard.readLine();
while(msg != null)
msg = keyboard.readLine();
This too will keep on taking inputs from the System.in. The loop would never end.
Solutions
As quoted above from java documentation, readLine method blocks for an input. That is the reason, there is no effect of delaying server response. The method returns null only at the end of the stream.
Solution 1 - Making use of ready method
ready method returns false when the read methods has to wait for an input data. As the Server code is sleeping for 1.5 sec, this method should return false during that time.
The downside of this approach is that if Server is not finished with all the response lines on time, then the inner loop where you collect all Server Responses will break.
while (true){
System.out.println ("Enter message you want to send to server:");
String msg = keyboard.readLine ();
output.println (msg);
String serverResponses = input.readLine ();
System.out.println (serverResponses);
while (input.ready()){
serverResponses=input.readLine ();
System.out.println (serverResponses);
}
}
Solution 2 - Server sends total lines
If the server knows about the total number of lines, then that can be sent as the first line in the stream. Depending upon total lines, client code can read those many lines. The downside of this approach is that an extra line has to be added in the Server response.
while (true){
System.out.println ("Enter message you want to send to server:");
String msg = keyboard.readLine ();
output.println (msg);
Integer linesCount = Integer.parseInt(input.readLine ());
for (int i=0; i< linesCount; i++){
String serverResponses=input.readLine ();
System.out.println (serverResponses);
}
}
I'm doing a client/server program in Java (including a GUI).
I've got the following code in the client:
public class SBListener implements ActionListener{
public void actionPerformed(ActionEvent e){
try{
outToServer.writeUTF(usn.getText().trim());
System.out.println("sent username to server");
playerExists = inToClient.readBoolean();
System.out.println("past getting player");
System.out.println("player exists = " + playerExists);
}catch(IOException a){
System.err.println(a);
}
if(playerExists == false){
JButton submitInfo = new JButton("submit info");
submitInfo.addActionListener(new SBNewInfoListener());
init.add(new JLabel(""));//dummy element to get the right alignment
init.add(new JLabel("First Name:"));
init.add(fn);
init.add(new JLabel("Last Name:"));
init.add(ln);
init.add(submitInfo);
add(init, BorderLayout.WEST);
init.setVisible(true);
init.revalidate();
init.repaint();
}
}
}
And the following code in the Server:
String username = inp.readUTF();
System.out.println(username);
out.writeBoolean(false);
System.out.println("wrote boolean, waiting for fn/ln/un");
fn = inp.readUTF();
System.out.println("got fn");
ln = inp.readUTF();
un = inp.readUTF();
But when the button that calls SBListener is clicked, the program freezes when it gets to the point where the Server is waiting for fn/ln/username. I added a bunch of system.out statements for debugging and I get up to the one that says "wrote boolean, waiting for fn/ln/un".
Basically, I'm trying to update the screen after the Server returns a false value. Specifically, I want to add two text fields for first & last name. I then want to send those values to the server.
Can anyone tell me how to fix this? Thanks in advance for any help!
Don't execute client/server code in an ActionListener. This will cause the Event Dispatch Thread to block while waiting for a response from the server. When EDT is blocked the whole GUI freezes.
Read the section from the Swing tutorial on Concurrency for more information. You need so use a separate Thread for the client/server code. Or you can use a SwingWorker as discussed in the tutorial.
My guess is that outToServer isn't being flushed. I would guess (although I can't tell from your sample code) that outToServer is a DataOutputStream. You need to call .flush to get the data out of the buffer and onto the wire.
Try this:
outToServer.writeUTF(usn.getText().trim());
outToServer.flush();
I am using the following code to give print to a network Lipi Printer (cc2 is printer name)
Process p = Runtime.getRuntime ().exec ("lp -dcc2 abcd.txt");
BufferedReader reader = new BufferedReader (
new InputStreamReader (p.getInputStream ()));
String line;
while ((line = reader.readLine ()) != null) {
System.out.println (line);
}
The problem starts when I run this in loop(> 4000) and a few of the prints get lost in the network and don't get printed.
I want to catch those lost prints and reprint them.
How can I get the printer to acknowledge the print has been received.
Check manual for your implementation of lp command. Some implementations can notify when printing is done, but the form of such notification may vary. Also there is -m switch that tells lp to send an e-mail to a user who initiated printing, once printing is done. Maybe you can somehow check these e-mails from your Java application. Anyway, this question is more about printing system of your OS rather than about Java.
I have a Java application that consists of a client and a server. The client sends encrypted commands to the server, and the server executes them.
The problem that I am having right now is that, with my encryption algorithm, sometimes the encrypted command contains "\n" or "\r" characters, which mess up my server code. This is because I am using the readLine() method, which stops when it finds a line terminator. What I need is a way to read all the characters the client sends into one string.
Here is my code:
public void run(){
System.out.println("Accepted Client!");
try{
in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream(), "ISO8859_1"));
out = new PrintWriter(new OutputStreamWriter(clientSocket.getOutputStream(), "ISO8859_1"));
String clientCommand = null;
while(RunThread){
// read incoming stream
do{
clientCommand = in.readLine();
}while(clientCommand == null);
//decrypt the data
System.out.println("Client: " + clientCommand);
if(clientCommand.equalsIgnoreCase("quit")){
RunThread = false;
}else{
//do something
out.flush();
}
}
}catch(Exception e){
e.printStackTrace();
}
}
Everything I've tried (various forms of nested loops using the read() function) hasn't worked. I would welcome any help or suggestions. Thanks, everyone!
I don't see encryption in the code you posted, but usually it's not a good idea to rely on separator characters.
When sending binary data, you should prepend the length of the data to the stream, and then you know exactly how many bytes to expect (and when the message will end.) It's more efficient to do things that way too instead of looking for a newline character.
// read incoming stream
do{
clientCommand = in.readLine();
}while(clientCommand == null);
That == null seems wrong
Try
String line = null;
do {
line = in.readLine ();
clientCommand += line
} while (line != null);
One thing you must do, when working with TCP/IP, is to send the message length before the actual message. The application level cannot foresee the package size the TCP level is delivering to the destiny. So, before your message, you have to send a header with the message size and the destiny would read just these bytes.
About readLine(), I think it's better use another approaches like streams. Shortly, one suggestion:
Socket oSocket = new Socket(sAddress, iPort);
PrintWriter out = new PrintWriter(oSocket.getOutputStream(), true);
BufferedReader in = new BufferedReader(new InputStreamReader(oSocket.getInputStream()));
do{
clientCommand = in.readLine();
} while(clientCommand == null);
This makes no sense. readLine() only returns null at end of stream, so you are telling Java to loop infinitely at end of stream. I don't even understand why there is a loop at all. You don't want to ignore any input from the client, you want to process it all. You should read one line from the client, execute it, and read another line. Repeat until null, then close the socket.
I ran into a problem while using input/output streams in Java. My thought was to have a DataInputStream to handle receiving text and a PrintStream to pass messages to the server from the server and object(output/input)streams to handle passing piece movements and current board image.
My problem is that the code hangs while it is trying to create the ObjectInputStream in the code below. Is this because I am trying to have multiple input and output streams? If so is there any possible fix I could use?
Socket sock = new Socket("127.0.0.1", 1716);
input = new DataInputStream(sock.getInputStream());
printer = new PrintStream(sock.getOutputStream());
System.out.println("Test 1");
zelda = new ObjectInputStream(sock.getInputStream());
System.out.println("Test 2");
link = new ObjectOutputStream(sock.getOutputStream());
System.out.println("Test 3");
I have a lot of Legend of Zelda references in my server source code and the code is rather large. The previous source code is for the client and although the server connects here is where I call ObjectOutputStream.
ObjectOutputStream ganandorf;
for(int i = 0; i < clients.size(); i++)
{
try
{
ganandorf = new ObjectOutputStream(clients.get(i).getOutputStream());
ganandorf.write(1);
ganandorf.flush();
ganandorf.writeObject(something);
ganandorf.flush();
}
Don't try to use two different kinds of streams/readers/writers on the same underlying connection. You will encounter buffering issues at both ends that make it basically impossible.
I would use ObjectInputStream and ObjectOutputStream and just write objects.
The constructor of ObjectInputStream blocks until it receives the header that is written by the constructor of ObjectOutputStream, so if you are constructing both you must construct the ObjectOutputStream first. You don't need to write anything and you don't need to flush it either, it does that itself.
I think you can only ask for 1 inputStream reference:
InputStream baseInputStream = sock.getInputStream();
input = new DataInputStream(baseInputStream);
zelda = new ObjectInputStream(baseInputStream);
same goes for outputStreams
I never found out what happened with ObjectInputStream, but I switched to DataInputStream and I'm currently modifying my code so it sends the piece name, x location, and y location in one string that will get broken up at the client and the board will be modified accordingly
Open a socket on a different port and use that to create new streams.