I have a client-server app.
It opens a socket on client side, then I input data to send, it's also sent to other clients, but then the socket is closed. Why? I have tried many different approaches, like shifting din and dout to thread itself, adding some handlers, etc. But no progress yet.
I saw some other problems like this, but the solutions there are not applicable to my problem (I am not so experienced in sockets). Would like a solution to my specific problem.
Errors:
java.net.SocketException: Socket is closed
at java.base/java.net.Socket.getInputStream(Socket.java:927)
at com.uniqueapps.network.ClientThread.lambda$run$1(ClientThread.java:23)
at java.base/java.lang.Thread.run(Thread.java:833)
java.net.SocketException: Socket is closed
at java.base/java.net.Socket.getOutputStream(Socket.java:998)
at com.uniqueapps.network.ClientThread.lambda$run$0(ClientThread.java:28)
at java.base/java.lang.Thread.run(Thread.java:833)
Exception in thread "Thread-2" java.util.ConcurrentModificationException
at java.base/java.util.ArrayList$Itr.checkForComodification(ArrayList.java:1013)
at java.base/java.util.ArrayList$Itr.next(ArrayList.java:967)
at com.uniqueapps.network.ClientThread.lambda$run$0(ClientThread.java:27)
at java.base/java.lang.Thread.run(Thread.java:833)
Server.java codes:
package com.uniqueapps.network;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.util.ArrayList;
public class Server {
final static int PORT = 5555;
static ServerSocket serverSocket;
static ArrayList<ClientThread> clients = new ArrayList<>();
public static void main(String[] args) {
try {
serverSocket = new ServerSocket(PORT);
new Thread(() -> {
while (true) {
try {
Socket clientSocket = serverSocket.accept();
ClientThread client = new ClientThread(clientSocket);
client.run();
clients.add(client);
System.out.println("New client joined: " + client.socket.getLocalPort());
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
} catch (IOException e) {
e.printStackTrace();
}
}
}
ClientThread.java codes:
package com.uniqueapps.network;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.IOException;
import java.net.Socket;
import java.net.SocketException;
public class ClientThread implements Runnable {
Socket socket;
public ClientThread(Socket socket) {
this.socket = socket;
}
#Override
public void run() {
new Thread(() -> {
boolean run = true;
while (run) {
try (DataInputStream din = new DataInputStream(socket.getInputStream())) {
String text = din.readUTF();
if (!text.equals("")) {
new Thread(() -> {
for (ClientThread clientThread : Server.clients) {
try (DataOutputStream dout = new DataOutputStream(clientThread.socket.getOutputStream())) {
dout.writeUTF(text);
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
}
} catch (EOFException ignored) {
} catch (SocketException e) {
e.printStackTrace();
Server.clients.remove(this);
run = false;
System.out.println("Client left: " + socket.getLocalPort());
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
}
}
Client.java codes:
package com.uniqueapps.network;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.IOException;
import java.net.Socket;
import java.util.Scanner;
public class Client {
public static void main(String[] args) {
try {
Socket socket = new Socket("localhost", 5555);
socket.setKeepAlive(true);
new Thread(() -> {
try {
DataOutputStream dout = new DataOutputStream(socket.getOutputStream());
Scanner scn = new Scanner(System.in);
while (true) {
String text = scn.nextLine();
if (!text.equals("")) {
try {
dout.writeUTF(text);
} catch (IOException e) {
e.printStackTrace();
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
}).start();
new Thread(() -> {
try {
DataInputStream din = new DataInputStream(socket.getInputStream());
while (true) {
try {
String text = din.readUTF();
if (!text.equals("")) {
System.out.println(text);
}
} catch (EOFException ignored) {
} catch (IOException e) {
e.printStackTrace();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}).start();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Edit:
Thanks to Michael Lee, i understood the problem i have been trying to understand for weeks. I remade the code, but i am stuck a place.
I got to know that the .run(); method of "runnable" halts the current thread, but .start(); of "thread" doesn't. So i removed threads from all places, except one. This place is still getting the "Socket closed" error (If i keep runnable here, then the thread is halted, and the message not relayed to other clients). How can i overcome this?
Server.java:
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.util.ArrayList;
public class Server {
final static int PORT = 8686;
static ServerSocket serverSocket;
static ArrayList<ClientThread> clients = new ArrayList<>();
public static void main(String[] args) {
try {
serverSocket = new ServerSocket(PORT);
System.out.println("Server ready! Running on port " + PORT);
while (true) {
try {
Socket clientSocket = serverSocket.accept();
System.out.println("New client joined: " + clientSocket.getPort());
ClientThread client = new ClientThread(clientSocket);
System.out.println("Created thread for client.");
clients.add(client);
System.out.println("Added client to list.");
} catch (IOException e) {
e.printStackTrace();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
ClientThread.java:
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.IOException;
import java.net.Socket;
import java.net.SocketException;
public class ClientThread extends Thread {
Socket socket;
public ClientThread(Socket socket) {
this.socket = socket;
this.start();
System.out.println("Started thread for client.");
}
#Override
public void run() {
try {
boolean run = true;
DataInputStream din = new DataInputStream(socket.getInputStream());
while (run) {
try {
String text = din.readUTF();
if (!text.equals("")) {
for (ClientThread clientThread : Server.clients) {
try (DataOutputStream dout = new DataOutputStream(clientThread.socket.getOutputStream())) {
dout.writeUTF(text);
} catch (IOException e) {
e.printStackTrace();
}
}
}
} catch (EOFException ignored) {
} catch (SocketException e) {
e.printStackTrace();
Server.clients.remove(this);
run = false;
System.out.println("Client left: " + socket.getPort());
} catch (IOException e) {
e.printStackTrace();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
Client.java:
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.IOException;
import java.net.Socket;
import java.net.SocketException;
public class ClientThread extends Thread {
Socket socket;
public ClientThread(Socket socket) {
this.socket = socket;
this.start();
System.out.println("Started thread for client.");
}
#Override
public void run() {
try {
boolean run = true;
DataInputStream din = new DataInputStream(socket.getInputStream());
while (run) {
try {
String text = din.readUTF();
if (!text.equals("")) {
for (ClientThread clientThread : Server.clients) {
try (DataOutputStream dout = new DataOutputStream(clientThread.socket.getOutputStream())) {
dout.writeUTF(text);
} catch (IOException e) {
e.printStackTrace();
}
}
}
} catch (EOFException ignored) {
} catch (SocketException e) {
e.printStackTrace();
Server.clients.remove(this);
run = false;
System.out.println("Client left: " + socket.getPort());
} catch (IOException e) {
e.printStackTrace();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
In your ClientThread, after din.readUTF(); if (!text.equals("")) { ..., you should directly start processing the incoming data in current thread, rather than initializing a new thread to handle them.
Because in you current thread, the one holding the connected socket, probably closed before the new thread has not even started up. As Java Docs says:
void close() throws Exception
Closes this resource, relinquishing any underlying resources. This method is invoked automatically on objects managed by the try-with-resources statement.
That is why you got Socket Closed exceptions.
One more thing is that, there are too many threads in either Server or Client. Most of time such things are unnecessary, say, for a rather simple application. Because they are not quite managed well in your codes, which more likely makes your program behave unexpectedly in the future. Try use threads only if necessary, instead of using them as much as possible.
Related
so today I've tried to install Citadel Email server on a raspberry pi which went ok but unfortunantly I cannot reach it from outside LAN.
I've tried to pinpoint the problem and use scanner tools that look for open ports like these :https://www.whatsmyip.org/port-scanner/
I've verified that my public IP adress is the same as my domain returns. Which indeed it is.
I've checked port forwarding severel times.
Last but not least I've wrote this java code to have a really simple example:
package main;
import java.io.IOException;
public class Main {
public static void main(String... args){
try {
Server server = new Server(8080);
Client client = new Client(8080);
} catch (IOException e) {
e.printStackTrace();
}
}
}
package main;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
public class Server {
private boolean stop = false;
public Server(int port) throws IOException {
ServerSocket serverSocket = new ServerSocket(port);
Runnable runnable = new Runnable() {
#Override
public void run() {
while(stop == false) {
try {
Socket socket = serverSocket.accept();
DataOutputStream outputStream = new DataOutputStream(socket.getOutputStream());
outputStream.writeUTF("Hello World!");
DataInputStream inputStream = new DataInputStream(socket.getInputStream());
String input = inputStream.readUTF();
System.out.println("Client wrote: " + input);
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
try {
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
};
Thread thread = new Thread(runnable, "server executor");
thread.start();
}
public void stop(){
this.stop = true;
}
}
package main;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
public class Client {
public static final String LOCALHOST = "localhost";
public static final String KIRAZUKE = "---";
public static final String PUBLIC_IP_4 = "---";
public Client(int port) {
try{
doTest(LOCALHOST, port);
} catch (IOException e) {
e.printStackTrace();
}
try{
Thread.sleep(2500);
} catch (InterruptedException e) {
e.printStackTrace();
}
try{
doTest(KIRAZUKE, port);
} catch (IOException e) {
e.printStackTrace();
}
try{
Thread.sleep(2500);
} catch (InterruptedException e) {
e.printStackTrace();
}
try{
doTest(PUBLIC_IP_4, port);
} catch (IOException e) {
e.printStackTrace();
}
}
private void doTest(String host, int port) throws IOException {
System.out.println("Opening to: " + host);
Socket socket = new Socket(host, port);
DataOutputStream outputStream = new DataOutputStream(socket.getOutputStream());
outputStream.writeUTF("Hello dear Server ... calling from " + host + " ... over.");
DataInputStream inputStream = new DataInputStream(socket.getInputStream());
String string = inputStream.readUTF();
System.out.println("Response from server after " + host + " call: " + string);
}
}
So I've replaced the domain name and my public ip with dashes for privacy reasons. But what happens is that when using the localhost connection everything works fine the server prints the text sent by the client and vise versa. While using either the public IP or Domain name it fails due to time out.
What could be reasons that any incoming traffic is blocked altough port forwarding is enabled for the 8080 port (and other ports that I tried) ?
Note: I've also called my ISP, according to them they "don't block anything". Additionally I tried port forwarding port 3389 and tried remote desktop to my pi but that also failed.
Thanks in advance :)
I am Trying to create a simple client-server application for global chat I am getting the following error when quitting the connection from client Side.
java.net.SocketException: Socket closed
at java.net.SocketInputStream.read(SocketInputStream.java:203)
at java.net.SocketInputStream.read(SocketInputStream.java:141)
at java.net.SocketInputStream.read(SocketInputStream.java:223)
at java.io.DataInputStream.readUnsignedShort(DataInputStream.java:337)
at java.io.DataInputStream.readUTF(DataInputStream.java:589)
at java.io.DataInputStream.readUTF(DataInputStream.java:564)
at ReadFromServer.run(ChatClient.java:25)
and when client crashes without using Quit this error
java.io.EOFException
at java.io.DataInputStream.readUnsignedShort(DataInputStream.java:340)
at java.io.DataInputStream.readUTF(DataInputStream.java:589)
at java.io.DataInputStream.readUTF(DataInputStream.java:564)
at Clients.run(ChatServer.java:34)
ChatServer.java
import java.util.*;
import java.io.*;
import java.net.*;
class Clients extends Thread
{
private static ArrayList<DataOutputStream> clientOutputStreams;
private DataInputStream dataInputStream;
private DataOutputStream dataOutputStream;
private Socket socket;
static
{
clientOutputStreams=new ArrayList<>();
}
Clients(Socket socket)
{
try
{
this.socket=socket;
this.dataInputStream=new DataInputStream(socket.getInputStream());
this.dataOutputStream=new DataOutputStream(socket.getOutputStream());
clientOutputStreams.add(dataOutputStream);
}
catch(Exception e)
{
e.printStackTrace();
}
}
public void run()
{
try
{
try
{
String message=dataInputStream.readUTF();
while(!message.equalsIgnoreCase("quit"))
{
for(DataOutputStream dis:clientOutputStreams)
{
dis.writeUTF(message);
}
message=dataInputStream.readUTF();
}
Thread.currentThread().interrupt();
}
finally
{
dataInputStream.close();
dataOutputStream.close();
clientOutputStreams.remove(clientOutputStreams.indexOf(dataOutputStream));
socket.close();
}
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
public class ChatServer
{
public static void main(String[] args)throws Exception
{
try
{
ServerSocket serverSocket=new ServerSocket(9000);
while(true)
{
Socket s=serverSocket.accept();
Clients client=new Clients(s);
client.start();
}
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
ChatClient.java
import java.util.*;
import java.io.*;
import java.net.*;
class ReadFromServer extends Thread
{
private DataInputStream readMessage;
ReadFromServer(Socket socket)
{
try
{
this.readMessage=new DataInputStream(socket.getInputStream());
}
catch(Exception e)
{
e.printStackTrace();
Thread.currentThread().interrupt();
}
}
public void run()
{
try
{
while(!Thread.currentThread().isInterrupted())
{
System.out.println(readMessage.readUTF());
}
readMessage.close();
Thread.currentThread().interrupt();
if(Thread.currentThread().isInterrupted())
return;
}
catch(Exception e)
{
e.printStackTrace();
Thread.currentThread().interrupt();
}
}
}
class WriteToServer extends Thread
{
private DataOutputStream writeMessage;
private String clientName;
private Socket socket;
WriteToServer(Socket socket,String clientName)
{
try
{
this.socket=socket;
this.writeMessage=new DataOutputStream(socket.getOutputStream());
this.clientName=clientName;
}
catch(Exception e)
{
e.printStackTrace();
Thread.currentThread().interrupt();
}
}
public void run()
{
try
{
Scanner scanner=new Scanner(System.in);
String message=scanner.nextLine();
while(!message.equalsIgnoreCase("quit"))
{
writeMessage.writeUTF(clientName+":"+message);
message=scanner.nextLine();
}
writeMessage.writeUTF(message);
writeMessage.close();
Thread.currentThread().interrupt();
if(Thread.currentThread().isInterrupted())
return;
}
catch(Exception e)
{
e.printStackTrace();
Thread.currentThread().interrupt();
}
}
}
public class ChatClient
{
public static void main(String[] args)
{
try
{
Socket socket=new Socket("localhost",9000);
try
{
System.out.print("Enter Your Name:");
Scanner scanner=new Scanner(System.in);
String clientName=scanner.nextLine();
ReadFromServer rfs=new ReadFromServer(socket);
WriteToServer wts=new WriteToServer(socket,clientName);
wts.start();
rfs.start();
while(wts.isAlive());
rfs.interrupt();
System.out.println("End of Both Threads");
//socket.close();
}
finally
{
socket.close();
}
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
How to handle such situations when Socket is closed when being used by InputStreamReader
SocketClosedException means that you closed the socket, at writeMessage.close(), and then continued to use it, at readMessage.readUTF(). It's a bug in your code. You will have to sort out which of the reader and writer threads should do the closing, and it should only be one of them, and not while the other is still running.
The EOFException is exactly what you should expect when you call readUTF() on a connection that has already been closed by the peer. Catch it and handle it separately.
I want to make a game (jungle speed), where players click totem and it changes position on screen (I'm using swing, it's not important) and information about localisation change should be sent to everyone.
I want to make a server which gets player's click, verifies it and send update info to all.
In this scenario, client listens to server if someone has clicked totem and meanwhile is ready to send info about his own click.
Server listens to everyone and meanwhile is ready to send information to all.
I try to implement it like this:
Server generates thread for each player, listens inside for click and is ready to be interrupted to send new totem localisation (I use method shutdownNow on ExecutorService, which should cause IOException in threads which will made them to stop doing loop and send information about new localisation) then client-side gets it.
Same for client side if he clicks, thread is interrupted and instead of waiting for new localisation it sends his click.
The problem is that I can't create streams. Here is output and code
Client side:
2017-05-22T23:04:06.417Connected
2017-05-22T23:04:06.417Trying to make output
2017-05-22T23:04:06.417Trying to make input
Server side:
2017-05-22T23:04:03.278Server Thread :Socket created
2017-05-22T23:04:03.294Server Thread :Waiting for client!
2017-05-22T23:04:06.385Server Thread :Correct, connected!
2017-05-22T23:04:12.239Trying to make input
Client side code :
package client;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.time.LocalDateTime;
import java.util.logging.Level;
import java.util.logging.Logger;
public class ServerConnection implements Runnable {
MainWindow frame;
Socket toServ;
Socket fromServ;
ServerSocket myServ;
ObjectOutputStream out;
ObjectInputStream reader;
public int x, y, totemx, totemy;
int i = 0;
public ServerConnection(MainWindow frame) {
try {
this.frame = frame;
myServ = new ServerSocket(1338);
toServ = new Socket("localhost", 1337);
fromServ = myServ.accept();
System.out.println(LocalDateTime.now() + "Connected");
try {
System.out.println(LocalDateTime.now() + "Trying to make output");
out = new ObjectOutputStream(new BufferedOutputStream(toServ.getOutputStream()));
} catch (IOException ex) {
Logger.getLogger(ServerConnection.class.getName()).log(Level.SEVERE, null, ex);
}
System.out.println(LocalDateTime.now() + "Trying to make input");
reader = new ObjectInputStream(new BufferedInputStream(fromServ.getInputStream()));
} catch (IOException ex) {
Logger.getLogger(ServerConnection.class.getName()).log(Level.SEVERE, null, ex);
}
}
#Override
public void run() {
System.out.println(LocalDateTime.now() + "Running");
while (true) {
try {
int xGot, yGot;
System.out.println(LocalDateTime.now() + "Waiting for params");
xGot = (int) reader.readInt();
yGot = (int) reader.readInt();
System.out.println(LocalDateTime.now() + "I got new params");
frame.refresh(xGot, yGot);
} catch (IOException ex) {
{
try {
System.out.println(LocalDateTime.now() + "Sending click thread: Sending my click");
out.writeInt(x);
out.writeInt(y);
System.out.println(LocalDateTime.now() + "Sent");
} catch (IOException ex1) {
Logger.getLogger(ServerConnection.class.getName()).log(Level.SEVERE, null, ex1);
}
}
}
}
}
}
Server side code
First file:
package javaapplicationserwer;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.time.LocalDateTime;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
*
* #author Japko
*/
public class Server{
public int x, y;
ServerSocket serv = null;
ExecutorService executor;
Server()
{
x = 10;
y = 50;
executor = Executors.newFixedThreadPool(4);
try {
serv = new ServerSocket(1337);
System.out.println(LocalDateTime.now() + "Server Thread :Socket created");
while (true) {
System.out.println(LocalDateTime.now() + "Server Thread :Waiting for client!");
Socket fromSocket = serv.accept();
Socket toSocket=new Socket(fromSocket.getInetAddress(),1338);
System.out.println(LocalDateTime.now() + "Server Thread :Correct, connected!");
ClientConnection temp = new ClientConnection(fromSocket,toSocket, this);
executor.submit(temp);
}
} catch (IOException ex) {
Logger.getLogger(JavaApplicationSerwer.class.getName()).log(Level.SEVERE, null, ex);
}
}
public void updateIt(int x, int y) {
System.out.println(LocalDateTime.now() + "Updating");
if (x == this.x && y == this.y) {
Random rand = new Random();
this.x = rand.nextInt(300);
this.y = rand.nextInt(300);
System.out.println(LocalDateTime.now() + "Updated");
executor.shutdownNow();
}
System.out.println(LocalDateTime.now() + "I notify");
}
}
Second file (Class implementing runnable which is created for each player by server):
package javaapplicationserwer;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.time.LocalDateTime;
import java.util.logging.Level;
import java.util.logging.Logger;
public class ClientConnection implements Runnable {
Socket fromSocket, toSocket;
InetAddress IP;
Server serv;
ObjectOutputStream out;
ObjectInputStream reader;
public ClientConnection(Socket fromSocket, Socket toSocket, Server serwer) {
this.fromSocket = fromSocket;
this.toSocket = toSocket;
this.serv = serwer;
try {
System.out.println(LocalDateTime.now() + "Trying to make input");
reader = new ObjectInputStream(new BufferedInputStream(fromSocket.getInputStream()));
} catch (IOException ex) {
Logger.getLogger(ClientConnection.class.getName()).log(Level.SEVERE, null, ex);
}
System.out.println(LocalDateTime.now() + "Trying to make output");
try {
out = new ObjectOutputStream(new BufferedOutputStream(toSocket.getOutputStream()));
} catch (IOException ex) {
Logger.getLogger(ClientConnection.class.getName()).log(Level.SEVERE, null, ex);
}
}
#Override
public void run() {
while (true) {
System.out.println(LocalDateTime.now() + "Starting");
try {
int xGot, yGot;
while (true) {
System.out.println(LocalDateTime.now() + "Waiting for params");
try {
xGot = reader.readInt();
yGot = reader.readInt();
System.out.println(LocalDateTime.now() + "Got this");
//serv.wait();
System.out.println(LocalDateTime.now() + "Waited");
serv.updateIt(xGot, yGot);
System.out.println(LocalDateTime.now() + "Verified");
} catch (IOException ex) {
try {
out.writeInt(serv.x);
out.writeInt(serv.y);
} catch (IOException ex1) {
Logger.getLogger(ClientConnection.class.getName()).log(Level.SEVERE, null, ex1);
}
Logger.getLogger(ClientConnection.class.getName()).log(Level.SEVERE, null, ex);
}
}
} finally {
System.out.println(LocalDateTime.now() + "I'm not serving for you");
}
}
}
}
It sounds like client has mate output (which means that server has input), then client wants to create input, but server escapes from constructor and doesn't even try to make its output.
Thanks in advance for help.
Sockets are a two (2) way connection. You only need one socket in the client connection.
here is some code that does simple tcp:
package p;
import java.io.*;
import java.net.*;
import java.util.function.*;
public class Tcp {
static class Acceptor extends Thread {
Acceptor(ServerSocket serverSocket,Consumer<Socket> consumer) {
super("Acceptor");
this.serverSocket=serverSocket;
this.consumer=consumer;
}
#Override public void run() {
p("acceptor running on: "+serverSocket);
while(true)
try {
Socket socket=serverSocket.accept();
if(consumer!=null) consumer.accept(socket);
} catch(IOException e) {
p(getName()+" caught: "+e);
break;
}
}
final ServerSocket serverSocket;
final Consumer<Socket> consumer;
}
static class Connection implements Runnable {
Connection(Socket socket) throws IOException {
this.socket=socket;
in=new BufferedReader(new InputStreamReader(socket.getInputStream()));
out=new OutputStreamWriter(socket.getOutputStream());
}
boolean send(String string) {
try {
p("sending: "+string+" on: "+socket);
out.write(string+'\n'/*System.getProperty("line.separator")*/);
out.flush();
return true;
} catch(IOException e) {
e.printStackTrace();
}
return false;
}
void process(String string) {
p("connection on: "+socket+" received: "+string);
}
#Override public void run() {
p("connection on: "+socket+" is runing.");
String string=null;
try {
p("connection on: "+socket+" is trying to read.");
while((string=in.readLine())!=null) {
process(string);
}
} catch(IOException e) {
e.printStackTrace();
}
process(null);
p("connection on: "+socket+" is exiting run()");
}
final Socket socket;
final BufferedReader in;
final Writer out;
}
public static void p(String string) {
System.out.println(string);
}
Tcp(String host,Integer service) throws IOException {
ServerSocket serverSocket=new ServerSocket();
SocketAddress socketAddress=new InetSocketAddress(host,service);
serverSocket.bind(socketAddress);
Consumer<Socket> socketConsumer=(socket)-> {
p("accepted from: "+socket);
try {
final Connection connection=new Connection(socket) {
#Override void process(String string) {
super.process(string);
send(string.toUpperCase());
}
};
new Thread(connection,"incoming").start();
} catch(IOException e2) {
e2.printStackTrace();
}
};
new Acceptor(serverSocket,socketConsumer).start();
}
public static void main(String[] args) throws UnknownHostException,IOException,InterruptedException {
final String host="localhost";
final Integer service=1237;
Tcp tcp=new Tcp(host,service);
Socket socket=new Socket(host,service);
Connection c1=new Connection(socket);
new Thread(c1,"c1").start();
socket=new Socket(host,service);
Connection c2=new Connection(socket);
Thread.sleep(500);
new Thread(c2,"c2").start();
c1.send("foo");
c2.send("bar");
}
}
out.flush() helped in this case.
I wrote simple client serwer, but unfortunately, I did it so chaotic and poorly that I decided to write everything from scratch. I want to write to communicate in both directions with the ability to disconnect and connect a new client. It means the client or the server sends a message and an appropriate one reads it. At the beginning all works but when i want to close client i get two errors:
java.net.SocketException: Socket closed readSocketData()
java.net.SocketException: Socket closedwriteData(String data)
Of course I understand what those errors means , but I do not understand why they show up because i have a while loop in which i check if the client is connected. Later when i try to connect a new client everything is falling apart.
I wrote 3 classes client, server and communication. Client and server inherits from communication (methods for opening and reading data streams). It all looks like that:
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
public class Server extends Communication{
ServerSocket serverSocket;
Socket listener;
boolean listenerLife;
public Server(int port) {
try {
serverSocket = new ServerSocket(port);
} catch (IOException e) {
System.out.println(e);
}
}
public void startListener(){
while (true){
try {
listener = serverSocket.accept();
listenerLife = true;
} catch (IOException e) {
System.out.println(e);
}
openWriter(listener);
openReader(listener);
writeServerDataThread();
new Thread(new Runnable() {
#Override
public void run() {
readData();
}
}).start();
}
}
public void writeServerDataThread(){
openLocalReader();
new Thread(new Runnable() {
#Override
public void run() {
while (true){
String data = readLocalData();
writeData(data);
}
}
}).start();
}
public void readData(){
while (listenerLife){
String data = readSocketData();
if("exit".equals(data) || data == null){
try {
listenerLife = false;
listener.close();
} catch (IOException e) {
System.out.println(e);
}
}
else {
System.out.println(data);
}
}
}
public void writeData(String data){
try {
writer.writeBytes(data + '\n');
writer.flush();
} catch (IOException e) {
System.out.println(e);
}
}
public static void main(String[] args) {
Server server = new Server(8080);
server.startListener();
}
}
import java.io.IOException;
import java.net.Socket;
public class Client extends Communication{
Socket clientSocket;
boolean clientLive;
public Client(String hostName, int port) {
try {
clientSocket = new Socket(hostName, port);
clientLive = true;
} catch (IOException e) {
System.out.println(e + "Client(String hostName, int port)");
}
}
public boolean closeConnection(String data){
if("exit".equals(data) || data == null){
try {
writeData("Zamykam klienta");
clientSocket.close();
clientLive = false;
return false;
} catch (IOException e) {
System.out.println(e + "closeConnection(String data)");
}
}
return true;
}
public void readClientData(){
new Thread(new Runnable() {
#Override
public synchronized void run() {
openLocalReader();
while (!clientSocket.isClosed()){
String data = readLocalData();
if(closeConnection(data)){
writeData(data);
}
}
}
}).start();
}
public void readServerDataThread(){
new Thread(new Runnable() {
#Override
public synchronized void run() {
while (!clientSocket.isClosed()){
String data = readSocketData();
if(closeConnection(data)){
System.out.println(data);
}
}
}
}).start();
}
public void writeData(String data){
try {
writer.writeBytes(data + '\n');
writer.flush();
} catch (IOException e) {
System.out.println(e + "writeData(String data)");
}
}
public static void main(String[] args) {
final Client client = new Client("localhost", 8080);
client.openReader(client.clientSocket);
client.openWriter(client.clientSocket);
client.readServerDataThread();
client.readClientData();
}
}
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
public class Communication {
BufferedReader reader;
BufferedReader localReader;
DataOutputStream writer;
public void openReader(Socket incomingSocket){
try {
reader = new BufferedReader(new InputStreamReader(incomingSocket.getInputStream()));
} catch (IOException e) {
System.out.println(e);
}
}
public void openWriter(Socket incomingSocket){
try {
writer = new DataOutputStream(incomingSocket.getOutputStream());
} catch (IOException e) {
System.out.println(e);
}
}
public void openLocalReader(){
localReader = new BufferedReader(new InputStreamReader(System.in));
}
public String readLocalData(){
String data = null;
try {
data = localReader.readLine();
} catch (IOException e) {
System.out.println(e + " readLocalData()");
}
return data;
}
public String readSocketData(){
String data = null;
try {
data = reader.readLine();
} catch (IOException e) {
System.out.println(e + " readSocketData()");
}
return data;
}
}
java.net.SocketException: Socket closed readSocketData()
java.net.SocketException: Socket closed writeData(String data)
Of course I understand what those errors means
They mean you closed the socket and continued to use it.
but I do not understand why they show up because i have a while loop in which i check if the client is connected.
No you don't. You have a while loop in which you check if the client socket is still open, which isn't the same thing at all ... but in any case that doesn't prevent you from using a closed socket inside the loop, for example after you close it in closeConnection(), whose return value being back to front from what it should be is doubtless causing confusion, and which is called by two threads as far as I can tell.
I'm creating this little client-server program to learn about sockets, and so far, I'm having a bit of trouble. For the purpose of this post, I consolidated the code into a single class. And the code will compile. (So it will show the same errors I get)
When the client connects to the server, the server socket properly creates a socket on the server-side. The Client then successfully sends a message to the server, but when the server tries to send a response to the client, there is an error saying the socket is closed.
Main.java
package main;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.BindException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.Hashtable;
public class Main {
boolean running = true;
public static void main(String[] args){
new Main().start();
}
public void start(){
new Thread(new ConnectionListener()).start(); //Starts Server
try {
connectToServer();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public class ConnectionListener implements Runnable{
public void run() {
ServerSocket ss = null;
try {
ss = new ServerSocket(31415);
}catch (BindException e) {
e.printStackTrace();
return;
} catch (IOException e) {
e.printStackTrace();
return;
}
while(running){
try {
Socket sock = ss.accept();
ServerConnection c = new ServerConnection(sock);
c.start();
} catch (IOException e) {
e.printStackTrace();
}
}
try {
ss.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public void connectToServer() throws UnknownHostException, IOException{
//Create Connection to Server
Socket socket = new Socket("localhost",31415);
ClientConnection cc = new ClientConnection(socket);
cc.start();
//Send First Message to Server
Hashtable<Integer, String> htt = new Hashtable<Integer, String>();
htt.put(0,"Hello, This is a Chat Test");
Message m = new Message(Message.Type.CHAT,htt);
cc.sendMessage(m);
}
public class ServerConnection{
Socket sock;
boolean connected = true;
public ServerConnection(Socket sock){
this.sock = sock;
}
public void start() {
new Thread(new RequestListener()).start();
}
private void handleMessage(Message m){
System.out.println("Server : Handle message " + m.type.toString());
}
public void disconnect(){
System.out.println("Disconnect user");
}
public void sendMessage(Message m){
try {
ObjectOutputStream os = new ObjectOutputStream(sock.getOutputStream());
os.writeObject(m);
os.flush();
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
class RequestListener implements Runnable{
public void run() {
ObjectInputStream is = null;
try {
is = new ObjectInputStream(sock.getInputStream());
while(connected){
try {
Message m = (Message)
is.readObject(); //EOFException
handleMessage(m);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}catch(SocketException e){
disconnect();
e.printStackTrace();
break;
}catch (IOException e) {
//e.printStackTrace(); //EOFException Here
}
}
} catch (IOException e) {
e.printStackTrace();
}finally{
try {
is.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
public class ClientConnection {
private Socket socket;
private boolean connected = true;
public ClientConnection(Socket socket) {
this.socket = socket;
}
public void start(){
new Thread(new RequestListener()).start();
}
public void sendMessage(Message m){
try {
ObjectOutputStream os = new ObjectOutputStream(socket.getOutputStream());
os.writeObject(m);
os.flush();
os.close();
} catch (IOException e) {
System.out.println("Error Sending Message");
e.printStackTrace();
}
}
public void close() throws IOException{
Message m = new Message(Message.Type.DISCONNECT,null);
sendMessage(m);
socket.close();
}
private void handleMessage(Message m){
System.out.println("Client : Handle message " + m.type.toString());
}
class RequestListener implements Runnable{
public void run() {
ObjectInputStream is = null;
try {
System.out.println(socket.isConnected()); //true
System.out.println(socket.isClosed()); //false
InputStream iss = socket.getInputStream();
is = new ObjectInputStream(iss); //socketClosedException
while(connected){
try {
Message m = (Message)is.readObject();
handleMessage(m);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}catch(SocketException e){
System.out.println("Server Disconnected");
break;
}catch (IOException e) {
e.printStackTrace();
}
}
} catch (IOException e) {
e.printStackTrace();
}finally{
try {
is.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
}
Message.java
package main;
import java.io.Serializable;
import java.util.Hashtable;
public class Message implements Serializable{
public enum Type{
LOGIN, PM, DISCONNECT, INCORRECT_LP,CORRECT_LP, UPDATE_USERLIST, CHAT, INCORRECT_VERSION
}
public Type type;
Hashtable ht;
public Message(Type type, Hashtable ht){
this.type = type;
this.ht = ht;
}
public Object get(Object o){
return ht.get(o);
}
}
There's nothing 'random' about it.
Closing the input or output stream of a Socket closes the other stream and the Socket.
In this case you are closing the ObjectOutputStream you have wrapped around the socket's output stream, which closes that output stream, which closes the socket's input stream and the socket.