Rick

Rick
Rick

Sunday, November 17, 2013

Socket Server / EchoServer / EchoClient redux



Question of StackOverflow about EchoServer and EchoClient....

I am always learning new things on StackOverflow....

It seems you copied it wrong.
I was able to run it on the first try.
echo: 
hi mom
echo: hi mom
how are you?
echo: how are you?
I took what they had and remixed it a bit to make it simpler (less code, and it does the same thing). You need JDK 7, but you can drop these in an IDE. Hit run on Server first. Then hit run on client. Then click the output area of the IDE and start typing in the client. Or you can run them from the command line.
package com.examples;
import java.net.*;
import java.io.*;

public class EchoServer {
  public static void main(String... args) throws IOException {

    int port;

    if ( args.length != 1 ) {
        System.out.println("listening to port 9999");
        port = 9999;
    } else {
        port = Integer.parseInt ( args[ 0 ] );

    }

    try (
            ServerSocket serverSocket =
                    new ServerSocket(port);
            Socket clientSocket = serverSocket.accept();
            PrintWriter out =
                    new PrintWriter(clientSocket.getOutputStream(), true);
            BufferedReader in = new BufferedReader(
                    new InputStreamReader(clientSocket.getInputStream()));
    ) {
        String inputLine;
        while ((inputLine = in.readLine()) != null) {
            out.println(inputLine);
        }
    }
  }
}
The above uses the new JDK 7 try with auto close syntax. You want this.
Then here is the remixed client.
package com.examples;

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

public class EchoClient {
  public static void main ( String... args ) throws IOException {

    String host;
    int port;

    if ( args.length != 2 ) {
        System.out.println("binding to port localhost:9999");
        host = "localhost";
        port = 9999;
    } else {
        host = args[ 0 ];
        port = Integer.parseInt ( args[ 1 ] );
    }

    try (
            Socket echoSocket = new Socket ( host, port );
            PrintWriter out =
                    new PrintWriter ( echoSocket.getOutputStream (), true );
            BufferedReader in =
                    new BufferedReader (
                            new InputStreamReader ( echoSocket.getInputStream () ) );
            BufferedReader stdIn =
                    new BufferedReader (
                            new InputStreamReader ( System.in ) )
    ) {
        System.out.println("Type in some text please.");
        String userInput;
        while ( ( userInput = stdIn.readLine () ) != null ) {
            out.println ( userInput );
            System.out.println ( "echo: " + in.readLine () );
        }
    }
  }
}
The server is as follows:
We grab the port number from the args passed to main or just set them to 9999 if they are not passed on command line.
    int port;

    if ( args.length != 1 ) {
        System.out.println("listening to port 9999");
        port = 9999;
    } else {
        port = Integer.parseInt ( args[ 0 ] );

    }
Then in the try statement parens we open up our server socket streak gak
            ServerSocket serverSocket =
                    new ServerSocket(port);
            Socket clientSocket = serverSocket.accept();
            PrintWriter out =
                    new PrintWriter(clientSocket.getOutputStream(), true);
            BufferedReader in = new BufferedReader(
                    new InputStreamReader(clientSocket.getInputStream())); 
If the above does not make sense, then you have to learn more about streams. Go to the tutorial on input/output (read and writing files), then come back to this.
Basically it is wrapping the output stream of the server socket in PrintWriter and wrapping the input stream in a BufferedReader. The Java I/O API is a bit daunting if you have not worked with it before so I suggest starting with the I/O tutorial a bit.
Here is the original:
EchoClient
EchoServer
Based on where you got messed up, start reading about IO-Streams, then IO-Character Streams.
Then come back to this after a few hours of background.
Then I saw this post on System.console and wanted to try it out, but it does not work in the IDE so....

I improved the example a bit. EchoServer no longer terminates after first connection (it was annoying me). I tried to use System.console(), but it would not work in my IDE so I canned it.
Notice the use of Scanner (in the EchoClient) which cut down the code quite a bit and made the example much more readable.
Client:
        try (
                Socket echoSocket = new Socket ( host, port );
                PrintWriter socketOut =
                        new PrintWriter ( echoSocket.getOutputStream (), true );
                Scanner socketIn =  new Scanner( echoSocket.getInputStream () );
                Scanner console = new Scanner(System.in);
        ) {
            System.out.println("Type in some text please.");
            while ( console.hasNextLine () ) {
                String userInput = console.nextLine ();
                socketOut.println ( userInput );
                System.out.println ( "echo: " + socketIn.nextLine () );
            }
        }
Here is a better example and I think it also answers the original question better.
Full server with while true loop:
package com.examples;
import java.net.*;
import java.io.*;

public class EchoServer {
    public static void main(String... args) throws IOException {

        int port;

        if ( args.length != 1 ) {
            System.out.println("listening to port 9999");
            port = 9999;
        } else {
            port = Integer.parseInt ( args[ 0 ] );

        }

        while(true) {
            try (
                    ServerSocket serverSocket =
                            new ServerSocket(port);
                    Socket clientSocket = serverSocket.accept();
                    PrintWriter out =
                            new PrintWriter(clientSocket.getOutputStream(), true);
                    BufferedReader in = new BufferedReader(
                            new InputStreamReader(clientSocket.getInputStream()));
            ) {
                String inputLine;
                while ((inputLine = in.readLine()) != null) {
                    out.println(inputLine);
                }
            }
        }
    }
}
Notice how the main method works even if the end user (a developer learning Sockets) is running in an IDE and passing args are not convenient. When I write examples, I spend a lot of time trying to simplify and amplify the topic I am covering with as little clutter as possible.
Here is the client once again, notice how the code is much shorter using Scanner than BufferredReader and it is more logical (you don't have to check for null, if there are lines process them).
Full Client
package com.examples;

import java.io.*;
import java.net.*;
import java.util.Scanner;


public class EchoClient {
    public static void main ( String... args ) throws IOException {

        String host;
        int port;

        if ( args.length != 2 ) {
            System.out.println("binding to port localhost:9999");
            host = "localhost";
            port = 9999;
        } else {
            host = args[ 0 ];
            port = Integer.parseInt ( args[ 1 ] );

        }



        try (
                Socket echoSocket = new Socket ( host, port );
                PrintWriter socketOut =
                        new PrintWriter ( echoSocket.getOutputStream (), true );
                Scanner socketIn =  new Scanner( echoSocket.getInputStream () );
                Scanner console = new Scanner(System.in);
        ) {
            System.out.println("Type in some text please.");
            while ( console.hasNextLine () ) {
                String userInput = console.nextLine ();
                socketOut.println ( userInput );
                System.out.println ( "echo: " + socketIn.nextLine () );
            }
        }


    }

}
I also renamed the variables in Client so it is more clear what they are doing. Now that I write this I realize I could do the same for the EchoServer.
I might add a set of socket utils to Boon.
share|edit|delete|flag




194reputation
15
biowebsiterick-hightower.blogspot.com
locationSan Francisco Bay Area
emailrichardhightower@gmail.com
real nameRick Hightower
age
visitsmember for36 days
visited32 days, 2 consecutive
seen2 mins ago
statsprofile views15
recent names1
Rick Hightower works at Mammatus Inc. where he focuses on cloud computing, NoSQL, EC2, and scalable Java, Python and PHP development. Rick was a Java editor for InfoQ, and now is an editor at InfoQ focusing on NoSQL.
He is author of the best-selling book Java Tools for Extreme Programming (#1 SW development book on Amazon for 3 months) and coauthor of Professional Struts and Struts Live (#1 download on TheServerSide.com 2004-2007).
He was a Zone Leader for JavaLobby and was on the editorial board for the Java Developer's Journal (and writes for the JDJ on occasion). In addition, he writes for IBM developerWorks (Python, Pyjamas, Spring, JPA, Hibernate, JSF, Facelets, etc.) He was also once the NoSQL editor at InfoQ.
Rick has spoken at JavaOne, XP Universe, SD West, SD East, etc., over 20 different conferences as well as being a speaker at many user group meetings (like JUGS in San Jose, San Diego, Phoenix, Tucson, Los Angeles, etc.) on topics ranging from Spring AOP to Facelets.
Rick has 26 software development certifications and has been director of development at three different software development firms as well as CTO of two different consulting/training companies before founding ArcMind Inc. in 2003.
You have not asked any questions
11
 × 24
1
 × 2
1
 × 5
1
 × 2
1
 × 3
1
1
 × 3
1
1
 × 3
1
all time by type month 
10up1question2
0down9answer
Kafka and Cassandra support, training for AWS EC2 Cassandra 3.0 Training