Java 8 Socket Example Style Confusion (KnockKnockServer) - java

I'm reading through the KnockKnockServer example:
import java.net.*;
import java.io.*;
public class KnockKnockServer {
public static void main(String[] args) throws IOException {
if (args.length != 1) {
System.err.println("Usage: java KnockKnockServer <port number>");
System.exit(1);
}
int portNumber = Integer.parseInt(args[0]);
try (
ServerSocket serverSocket = new ServerSocket(portNumber);
Socket clientSocket = serverSocket.accept();
PrintWriter out =
new PrintWriter(clientSocket.getOutputStream(), true);
BufferedReader in = new BufferedReader(
new InputStreamReader(clientSocket.getInputStream()));
) {
String inputLine, outputLine;
// Initiate conversation with client
KnockKnockProtocol kkp = new KnockKnockProtocol();
outputLine = kkp.processInput(null);
out.println(outputLine);
while ((inputLine = in.readLine()) != null) {
outputLine = kkp.processInput(inputLine);
out.println(outputLine);
if (outputLine.equals("Bye."))
break;
}
} catch (IOException e) {
System.out.println("Exception caught when trying to listen on
port" + portNumber + " or listening for a connection");
System.out.println(e.getMessage());
}
}
}
My question regards exception handling. Firstly, why does the main method/function have a throws clause associated with it? To my knowledge any IOException will be dealt with in the corresponding catch block and not forwarded up the chain.
Secondly, it is my understanding that accepting a socket connection, and attempting to read from an active/created connection may throw IOExceptions. Is it better to try and handle acceptance of the connection separately from attempts to read from it, or is this particular style "kosher"?

Related

How to broadcast messages to all clients using tcp in java

I am building a multithreaded chat server application which broadcasts a message sent by one client to all the clients.On most of the examples on internet and on Oracle's website too broadcasting is done using udp (Multicast Socket)but i am using tcp .
Does anyone know how to send a message to all the connected clients in a tcp conection?
Here is my current code which works fine and sends the message receieved from a client to that client only:
EchoServer
import java.net.*;
import java.io.*;
public class EchoServer
{
public static void main(String[] args)
throws IOException
{
if (args.length != 1) {
System.err.println("Usage: java EchoServer <port number>");
System.exit(1);
}
int portNumber = Integer.parseInt(args[0]);
ServerSocket serverSocket = new ServerSocket(Integer.parseInt(args[0]));
while (true) {
try {
Thread t = new Thread(new MultiServer(serverSocket.accept()));
t.start();
} catch(IOException e) {
System.out.println("Accept Failed:");
System.exit(-1);
}
}
}
}
EchoClient
import java.io.*;
import java.util.Scanner;
import java.net.*;
public class EchoClient
{
public static void main(String[] args) throws IOException
{
if (args.length != 2) {
System.err.println("Usage: java EchoClient <host name><portnumber>");
System.exit(1);
}
String hostName = "localhost";
int portNumber = Integer.parseInt(args[1]);
try (
Socket echoSocket = new Socket(hostName, portNumber);
PrintWriter out = new PrintWriter(echoSocket.getOutputStream(), true);
BufferedReader in = new BufferedReader(new InputStreamReader(echoSocket.getInputStream()));
BufferedReader stdIn = new BufferedReader(new InputStreamReader(System.in));
) {
String userInput;
while ((userInput = stdIn.readLine()) != null) {
out.println(userInput);
System.out.println("echo::" + in.readLine());
}
} catch (UnknownHostException e) {
System.err.println("Don't know about host " + hostName);
System.exit(1);
} catch (IOException e) {
System.err.println("Couldn't get I/O for the connection to " + hostName);
System.exit(1);
}
}
}
MultiServer
import java.io.*;
import java.net.*;
public class MultiServer implements Runnable
{
private Socket client;
public MultiServer(Socket m)
{
this.client = m;
}
#Override
public void run()
{
BufferedReader in = null;
PrintWriter out = null;
try {
out = new PrintWriter(client.getOutputStream(), true);
in = new BufferedReader(new InputStreamReader(client.getInputStream()));
} catch(IOException ignored) {
}
while (true) {
String line;
try {
while ((line = in.readLine()) != null)
out.println(line);
} catch (IOException e) {
System.out.println("Read Failed");
System.exit(-1);
}
}
}
}
Use the concurrent hashmap and maintain your list of clients in that.
The concurrent hashmap is safe and you won't need to use synchronization while adding / iterating / removing
// Create and main list of active clients based on their host name / ip address
ConcurrentHashMap<String, Socket> activeClients = new ConcurrentHashMap<String, Socket>();
// message received
activeClients.put(clientsocket.getInetAddress().getHostAddress(), clientsocket);
// broadcast message to all available clients
for(String clientHost : activeClients.keySet()) {
// get each socket here and send a message to them.
}
Vector is basically a thread safe one so you don't need to worry about that one.

Creating server in Java for global access

I have a problem which i've already been struggling for 3 days. I need to create server based on socket connection beetween the different local networks.
I found a lot of examples like this :
import java.net.ServerSocket;
import java.net.Socket;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.InputStreamReader;
import java.io.BufferedReader;
/**
* Created by yar 09.09.2009
*/
public class HttpServer {
public static void main(String[] args) throws Throwable {
ServerSocket ss = new ServerSocket(9999);
while (true) {
Socket s = ss.accept();
System.err.println("Client accepted");
new Thread(new SocketProcessor(s)).start();
}
}
private static class SocketProcessor implements Runnable {
private Socket s;
private InputStream is;
private OutputStream os;
private SocketProcessor(Socket s) throws Throwable {
this.s = s;
this.is = s.getInputStream();
this.os = s.getOutputStream();
}
public void run() {
try {
readInputHeaders();
writeResponse("<html><body><h1>Hello from Habrahabr</h1></body></html>");
} catch (Throwable t) {
/*do nothing*/
} finally {
try {
s.close();
} catch (Throwable t) {
/*do nothing*/
}
}
System.err.println("Client processing finished");
}
private void writeResponse(String s) throws Throwable {
String response = "HTTP/1.1 200 OK\r\n" +
"Server: YarServer/2009-09-09\r\n" +
"Content-Type: text/html\r\n" +
"Content-Length: " + s.length() + "\r\n" +
"Connection: close\r\n\r\n";
String result = response + s;
os.write(result.getBytes());
os.flush();
}
private void readInputHeaders() throws Throwable {
BufferedReader br = new BufferedReader(new InputStreamReader(is));
while(true) {
String s = br.readLine();
if(s == null || s.trim().length() == 0) {
break;
}
}
}
}
}
But problem is :
i can access to this ip:port only from the same local network. If i trying to connect from the same network (from Android smartphone to local computer which has the same network ip)? so in this case all is successful, but if i trying to run the same Server sample code on, say for example AWS (Amazon Web Server)
it doesn't work :(
-> Couldn't get I/O for the connection to 172.31.23.98 (java)
or
-> org.apache.http.conn.ConnectTimeoutException: Connect to 172.31.23.98:9999 timed out (groovy)
i'm using this sample code of Server :
public static void main(String[] args) throws IOException {
int portNumber = 9998;
BufferedOutputStream bos = null;
while (true) {
try (ServerSocket serverSocket = new ServerSocket(portNumber);
Socket clientSocket = serverSocket.accept();
PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true);
InputStream in = clientSocket.getInputStream();
BufferedReader inWrapper = new BufferedReader(new InputStreamReader(in))) {
FileOutputStream fos = new FileOutputStream(new File("D:/BufferedAudio.wav"));
bos = new BufferedOutputStream(fos);
System.out.println("Connected with client");
String inputLine, outputLine;
int bytesRead;
byte[] buffer = new byte[1024 * 1024];
while ((bytesRead = in.read(buffer)) > 0) {
bos.write(buffer, 0, bytesRead);
System.out.println(new String(buffer, Charset.defaultCharset()));
bos.flush();
out.println("Hello!!! I'm server");
}
bos.close();
} catch (IOException e) {
System.out.println("Exception caught when trying to listen on port "
+ portNumber + " or listening for a connection");
System.out.println(e.getMessage());
throw e;
}
System.out.println("Upps, the loop was unexpectedly out");
}
}
Here's the code of client :
public static void main(String[] args) throws IOException {
String IP = "172.31.23.98";
int port = 9998;
try (
Socket connectionSocket = new Socket(IP, port);
PrintWriter out = new PrintWriter(connectionSocket.getOutputStream(), true);
BufferedReader in = new BufferedReader(
new InputStreamReader(connectionSocket.getInputStream()))
) {
BufferedReader stdIn =
new BufferedReader(new InputStreamReader(System.in));
String fromServer;
String fromUser;
while ((fromServer = in.readLine()) != null) {
System.out.println("Server: " + fromServer);
fromUser = stdIn.readLine();
if (fromUser != null) {
System.out.println("Client: " + fromUser);
out.println(fromUser);
}
}
} catch (UnknownHostException e) {
System.err.println("Don't know about host " + IP);
System.exit(1);
} catch (IOException e) {
System.err.println("Couldn't get I/O for the connection to " +
IP);
System.exit(1);
}
}
These are the samples from the internet.
Amm how can i modify this code to access from Client to Server from different networks ?
The IP range 172.16.0.0 to 172.31.255.255 is a private address space for use in local area networks. IPs from that range are only valid in the same private LAN.
When you deploy your server software on a host on the Internet which is outside of your local area network, you need to replace it with the IP address of that host. I never used AWS, but the first place I would be looking for when I would want to know the public IP address of a server I rent, would be the web-based control panel. When you have shell access to the server, you can also find it out with ipconfig on Windows and ifconfig on Unix.

Java TCPSocket breaks after Client closes connection [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 3 years ago.
Improve this question
I am very new to programming, especially to socket programming. I tried to figure out how communication works in real (not in all my books), but ran immediately into my first problem with the downloaded SimpleEchoServer example. Communicationflow works but when the Clientsocket closes his connection without sending a specific string, my serversocket breaks down. Can you please tell what have i've done wrong?
This is the server side:
import java.net.*;
import java.io.*;
import java.net.InetAddress;
public class EchoServer {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = null;
Integer port = new Integer(args[0]);
try {
serverSocket = new ServerSocket(port);
}
catch (IOException e) {
System.err.println("Could not listen on port: "+port);
System.exit(1);
}
Socket clientSocket = null;
System.out.println ("Waiting for connection on port "+port+" ...");
try {
clientSocket = serverSocket.accept();
}
catch (IOException e) {
System.err.println("Accept failed.");
System.exit(1);
}
System.out.println ("Connection successful");
System.out.println ("Waiting for input.....");
PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true);
BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream(), "UTF-8"));
String inputLine;
while ((inputLine = in.readLine()) != null) {
System.out.println ("received: " + inputLine);
out.println(inputLine);
if (inputLine.equals("Bye."))
break;
}
out.close();
in.close();
clientSocket.close();
serverSocket.close();
}
}
and that's the client side
import java.io.*;
import java.net.*;
public class EchoClient {
public static void main(String[] args) throws IOException {
String serverHostname = new String (args[0]);
Integer port = new Integer(args[1]);
if (args.length > 0)
serverHostname = args[0];
System.out.println ("Attemping to connect to host " + serverHostname + " on port 10007.");
Socket echoSocket = null;
PrintWriter out = null;
BufferedReader in = null;
try {
echoSocket = new Socket(serverHostname, port);
out = new PrintWriter(echoSocket.getOutputStream(), true);
in = new BufferedReader(new InputStreamReader(echoSocket.getInputStream(), "UTF-8"));
} catch (UnknownHostException e) {
System.err.println("Don't know about host: " + serverHostname);
System.exit(1);
} catch (IOException e) {
System.err.println("Couldn't get I/O for " + "the connection to: " + serverHostname);
System.exit(1);
}
BufferedReader stdIn = new BufferedReader(new InputStreamReader(System.in));
String userInput;
System.out.print ("input: ");
while ((userInput = stdIn.readLine()) != null) {
out.println(userInput);
System.out.println("echo: " + in.readLine());
System.out.print ("input: ");
}
out.close();
in.close();
stdIn.close();
echoSocket.close();
}
}
It is not the ServerSocket that breaks.
The EchoServer reads from the client socket's InputStream in the loop while ((inputLine = in.readLine()) != null). When the socket connection is terminated, attempting to read will throw an exception. Since the loop isn't inside a try-catch-block, the exception kills the server process.
To prevent that, you need to handle the exception.
try {
while ((inputLine = in.readLine()) != null) {
System.out.println ("received: " + inputLine);
out.println(inputLine);
if (inputLine.equals("Bye."))
break;
}
} catch (IOException ex) {
System.out.println("Connection error... terminating.");
}

Java server-client readLine() method

I have a client class and a server class.
If client sends message to server, server will send response back to the client, then client will print all the messages it received.
For example,
If Client sends "A" to Server, then Server will send response to client
"1111". So I use readLine() in client class to read the message from server, then client print "1111" in the console.
If Client sends "B" to Server, then Server will send response to client
"2222\n 3333". So the expected printing output from client is:
"2222"
"3333"
So the response message from server to client may have 1 line or 2 lines depending on the message it send from client to server.
My question is that how I can use readLine() to read the message that send from server to client. More specifically, if I use the following codes,
String messageFromServer;
while(( messageFromServer = inputStreamFromServer.readLine()) != null) {
println(messageFromServer);
}
It will only print the first line, and will not print anything else even if I keep sending message from client to server, because readLine() will stops once it has read the first line.
update:
More specifically, I am looking for some methods in the client class to read message that contains 1 or multiple lines from server at a time. I am wondering if there are any ways to do it in client side if I don't want to change the format of the message that sent from server to client.
update 2
To make my question more clear, I will put some sample codes in the following:
This is server:
import java.net.*;
import java.io.*;
public class Server {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = null;
try {
serverSocket = new ServerSocket(1234);
} catch (IOException e) {
System.err.println("Could not listen on port: 1234.");
System.exit(1);
}
Socket clientSocket = null;
try {
clientSocket = serverSocket.accept();
} catch (IOException e) {
System.err.println("Accept failed.");
}
System.out.println("Connected");
PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true);
BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
String textFromClient =null;
String textToClient =null;
textFromClient = in.readLine(); // read the text from client
if( textFromClient.equals("A")){
textToClient = "1111";
}else if ( textFromClient.equals("B")){
textToClient = "2222\r\n3333";
}
out.print(textToClient + "\r\n"); // send the response to client
out.flush();
out.close();
in.close();
clientSocket.close();
serverSocket.close();
}
}
The client:
public class Client {
public static void main(String[] args) throws IOException {
Socket socket = null;
PrintWriter out = null;
BufferedReader in = null;
BufferedReader read = new BufferedReader(new InputStreamReader(System.in));
try {
socket = new Socket("localhost", 1234);
out = new PrintWriter(socket.getOutputStream(), true);
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
} catch (UnknownHostException e) {
System.err.println("Don't know about host");
} catch (IOException e) {
System.err.println("Couldn't get I/O for the connection");
}
System.out.println("Connected");
String textToServer;
while((textToServer = read.readLine())!=null){
out.print(textToServer + "\r\n" ); // send to server
out.flush();
String messageFromServer =null;
while(( messageFromServer = textToServer=in.readLine()) != null){
System.out.println(messageFromServer);
}
}
out.close();
in.close();
read.close();
socket.close();
}
private static void debug(String msg)
{
System.out.println("Client: " + msg);
}
}
You shouldn't need to change the format of the data sent by the server, and readLine() should work, but I suspect that the server is not flushing or closing the OutputStream after writing the response which could possibly explain things.
Is the call to readLine() hanging? Are you in control of the server code? If so, can you include it?
Revised classes that work as I believe you expect:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
public class ClientServerTest2
{
public static void main(String[] args) throws Exception
{
Thread serverThread = new Thread(new Server());
serverThread.start();
Thread clientThread = new Thread(new Client());
clientThread.start();
serverThread.join();
clientThread.join();
}
private static class Server implements Runnable
{
#Override
public void run()
{
ServerSocket serverSocket = null;
try
{
serverSocket = new ServerSocket(1234);
Socket clientSocket = null;
clientSocket = serverSocket.accept();
debug("Connected");
PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true);
BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
String textFromClient = null;
String textToClient = null;
textFromClient = in.readLine(); // read the text from client
debug("Read '" + textFromClient + "'");
if ("A".equals(textFromClient))
{
textToClient = "1111";
}
else if ("B".equals(textFromClient))
{
textToClient = "2222\r\n3333";
}
debug("Writing '" + textToClient + "'");
out.print(textToClient + "\r\n"); // send the response to client
out.flush();
out.close();
in.close();
clientSocket.close();
serverSocket.close();
}
catch (Exception e)
{
e.printStackTrace();
}
}
private static void debug(String msg)
{
System.out.println("Server: " + msg);
}
}
private static class Client implements Runnable
{
#Override
public void run()
{
Socket socket = null;
PrintWriter out = null;
BufferedReader in = null;
BufferedReader read = new BufferedReader(new InputStreamReader(System.in));
try
{
socket = new Socket("localhost", 1234);
out = new PrintWriter(socket.getOutputStream(), true);
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
debug("Connected");
String textToServer;
textToServer = read.readLine();
debug("Sending '" + textToServer + "'");
out.print(textToServer + "\r\n"); // send to server
out.flush();
String serverResponse = null;
while ((serverResponse = in.readLine()) != null)
debug(serverResponse); // read from server and print it.
out.close();
in.close();
read.close();
socket.close();
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
private static void debug(String msg)
{
System.out.println("Client: " + msg);
}
}
Change while(( messageFromServer = inputStreamFromServer.readLine() != null) to while(( messageFromServer = inputStreamFromServer.readLine()) != null)
Actually this shouldn't even compile....
It's a work around.
If you want to send multiple strings like in your case : "2222\n 3333".
You can send them by adding a seperator character (like :) between two strings : "2222: 3333".
Then you can call write from server side as
clientOut.write("2222: 3333\n");
On client side parse recieved String :
messageFromServer = inputStreamFromServer.readLine();
String strArray[] = messageFromServer.split(":");
strArray[0] : 2222
strArray[0] : 3333

question regarding Echoclient program

I am always getting the message Don't know about host: taranis. while running echoclient program. here is the program below
import java.io.*;
import java.net.*;
public class EchoClient {
public static void main(String[] args) throws IOException {
Socket echoSocket = null;
PrintWriter out = null;
BufferedReader in = null;
try {
echoSocket = new Socket("taranis",3218);
out = new PrintWriter(echoSocket.getOutputStream(), true);
in = new BufferedReader(new InputStreamReader(
echoSocket.getInputStream()));
} catch (UnknownHostException e) {
System.err.println("Don't know about host: taranis.");
System.exit(1);
} catch (IOException e) {
System.err.println("Couldn't get I/O for "
+ "the connection to: taranis.");
System.exit(1);
}
BufferedReader stdIn = new BufferedReader(
new InputStreamReader(System.in));
String userInput;
while ((userInput = stdIn.readLine()) != null) {
out.println(userInput);
System.out.println("echo: " + in.readLine());
}
out.close();
in.close();
stdIn.close();
echoSocket.close();
}
}
You need to use a valid host name, or a valid IP of your server (assuming you have one) when you initialize your socket (new Socket("taranis",3218) ). It is great to take those tutorials (as pointed by icktoofay), but especially when it comes to networking, you have to make sure you have the matching application running on the other side, and that the parameters match it. IP and port usually change from machine to machine and from application to application.

Categories