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.
Related
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.
At the moment i have a Server and a Client, and when the Client is connected to the Server, a Thread is created to handle all the resposnses from the respective Client and also to send any needed answers. My problem now is that i need to be able to send a message through every existent Thread to their respective Client.
I was thinking of doing it like this:
public class ServerThread extends Thread {
//ignore most of the constructor, just things i need
public ServerThread(Socket socket, int threadId, Manager manager) throws Exception {
try {
this.socket = socket;
this.threadId=threadId;
this.manager=manager;
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
manager.addThread(); //This should add this Thread to the Collection in the Manager class
} catch (IOException ex) {
throw new Exception("Error", ex);
}
}
public void notify(String message){
// Do something
}
//In the end of the thread i would call manager.removeThread to remove the Thread from the Collection
}
public class Manager {
private //Thread Collection here
public Manager(){
//Initialize the collection;
}
public void addThread(){
//Add thread
}
public void removeThread(){
//Remove Thread
}
}
If this is a viable option to handle this, what Collection would i need to store the Threads and also, what would the notify(String message) method look like? It would need to call a method in Manager that would send a message to every Thread right?
If you want to create a multi-client server what is usually recommended is that in the main thread (or a separate thread) of the server class, the server will be accepting incoming Sockets (client) and with every socket accepted a new thread is created to service that client and it is better to have the service as a separate class that implements runnable or extends thread. Each service thread will be waiting for input from the client it is associated with and replying according to the client's request.
If you are looking to broadcast data to all the connected clients then what you need is to have an ArrayList that stores the client service objects and then loop over it, with every loop you send data to one of the connected clients but you have to make sure that you remove the clients that disconnected from the ArrayList otherwise it will start throwing exceptions.
usually, client service classes have the accepted socket, an input stream, and an output stream.
here is an example of a multiclient echo server that I have made maybe it will help.
public class TcpServer {
public TcpServer(){
ServerSocket server = null;
try{
server = new ServerSocket(9991);
while(!server.isClosed()){
Socket acceptedSocket = server.accept();
EchoService service = new EchoService(acceptedSocket);
service.start();
}
}catch (IOException e){
e.printStackTrace();
} finally {
if(server!=null) {
try {
server.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args){
new TcpServer();
}}
This is the service class:
public class EchoService extends Thread {
private Socket acceptedSocket;
private DataInputStream is;
private DataOutputStream os;
public EchoService(Socket acceptedSocket) {
try {
this.acceptedSocket = acceptedSocket;
is = new DataInputStream(acceptedSocket.getInputStream());
os = new DataOutputStream(acceptedSocket.getOutputStream());
} catch (IOException e) {
try {
if (this.acceptedSocket != null)
acceptedSocket.close();
if(is != null)
is.close();
if(os != null)
os.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
#Override
public void run() {
super.run();
try {
while (!acceptedSocket.isClosed()) {
String usrMsg = is.readUTF();
String serverMsg = "server: "+usrMsg;
os.writeUTF(serverMsg);
os.flush();
}
} catch (IOException e) {
try {
if(this.acceptedSocket != null)
acceptedSocket.close();
if(is != null)
is.close();
if(os != null)
os.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}}
This is the same example but with the Broadcast feature included
Server class:
package TCP;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
public class TcpServer {
public static ArrayList<EchoService> connectedServices;
public TcpServer(){
ServerSocket server = null;
try{
server = new ServerSocket(9991);
System.out.println("server started");
connectedServices = new ArrayList<>();
while(!server.isClosed()){
Socket acceptedSocket = server.accept();
System.out.println("client connected: "
+acceptedSocket.getInetAddress());
EchoService service = new EchoService(acceptedSocket);
service.start();
}
}catch (IOException e){
e.printStackTrace();
} finally {
if(server!=null) {
try {
server.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args){
new TcpServer();
}
public static void removeConnectedService(EchoService client) {
boolean removed = connectedServices.remove(client);
System.out.println("client has been removed"+
client.getAcceptedSocket().getInetAddress()+", "+removed);
}
public static void broadCastMsg(long id, String usrMsg) throws IOException {
for(EchoService client: connectedServices){
if(client.getId()!=id)
{
String serverMsg = "server broadcast: " + usrMsg;
client.getOs().writeUTF(serverMsg);
client.getOs().flush();
}
}
}
}
service class:
package TCP;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
public class EchoService extends Thread {
private Socket acceptedSocket;
private DataInputStream is;
private DataOutputStream os;
public EchoService(Socket acceptedSocket) {
try {
this.acceptedSocket = acceptedSocket;
is = new DataInputStream(acceptedSocket.getInputStream());
os = new DataOutputStream(acceptedSocket.getOutputStream());
} catch (IOException e) {
try {
if (this.acceptedSocket != null)
acceptedSocket.close();
if(is != null)
is.close();
if(os != null)
os.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
#Override
public void run() {
super.run();
try {
TcpServer.connectedServices.add(this);
while (!acceptedSocket.isClosed()) {
String usrMsg = is.readUTF();
if(usrMsg.contains("BROADCAST"))
TcpServer.broadCastMsg(this.getId(),usrMsg);
else {
String serverMsg = "server: " + usrMsg;
os.writeUTF(serverMsg);
os.flush();
}
}
} catch (IOException e) {
TcpServer.removeConnectedService(this);
try {
if(this.acceptedSocket != null)
acceptedSocket.close();
if(is != null)
is.close();
if(os != null)
os.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
public DataInputStream getIs() {
return is;
}
public DataOutputStream getOs() {
return os;
}
public Socket getAcceptedSocket() {
return acceptedSocket;
}
}
Server output:
client 1 output:
client 2 output:
client 3 output:
I would create a static method getInstance(int threadId) in ServerThread.
Inside this, you create a syncronized and static Map (see class Collections).
In notify just navigate over the map and send your messages to your ServerThread instances.
(note: if it's a TreMap it will be sorted by the key)
I wrote a simple server client program today, but I have a problem and don't know why.
Here are my 3 important classes(all methods are called properly):
public class Server {
private ServerSocket server;
private ArrayList<Client> clients = new ArrayList<Client>();
public Server(int port) {
try {
server = new ServerSocket(port);
server.setSoTimeout(900000);
} catch (IOException e) {
e.printStackTrace();
}
acceptClients();
Main.frame.log("Server started on port "+port);
}
public void acceptClients() {
Thread t = new Thread() {
#Override
public void run() {
System.out.println("Accepting");
while(true) {
try {
Socket client = server.accept();
System.out.println("Accepted: "+client.getLocalSocketAddress());
clients.add(new Client(client));
} catch (IOException e) {
e.printStackTrace();
break;
}
}
};
};
t.start();
}
}
public class Client {
private static Socket client;
private static DataOutputStream out;
private static DataInputStream in;
public static void main(String[] args) throws UnknownHostException, IOException {
client = new Socket("localhost", 1567);
client.setSoTimeout(900000);
in = new DataInputStream(client.getInputStream());
out = new DataOutputStream(client.getOutputStream());
receive();
send("Hi I am a client!");
}
public static void receive() {
Thread t = new Thread() {
#Override
public void run() {
while (true) {
try {
String data = in.readUTF();
System.out.println("Received: "+data);
send("Test");
} catch (IOException e) {
e.printStackTrace();
break;
}
}
};
};
t.start();
}
public static void send(String data) {
try {
System.out.println("Sending");
out.writeUTF(data);
System.out.println("Sent: "+data);
} catch (IOException e) {
e.printStackTrace();
}
}
}
The client handler of my server:
public class Client {
Socket socket;
DataOutputStream out;
DataInputStream in;
public Client(Socket client) {
socket = client;
try {
socket.setSoTimeout(900000);
in = new DataInputStream(socket.getInputStream());
out = new DataOutputStream(socket.getOutputStream());
receive();
} catch (IOException e) {
e.printStackTrace();
}
}
private void receive() {
Thread t = new Thread() {
#Override
public void run() {
while (true) {
try {
process(in.readUTF());
in.close();
sleep(100);
} catch (IOException | InterruptedException e) {
e.printStackTrace();
break;
}
}
}
};
t.start();
}
public void send(String data) {
try {
out.writeUTF(data);
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
private void process(String data) {
Main.frame.log("Received--> "+data);
send("I received your message!");
}
}
When I execute the server and the client everything is fine until the client sends the second message. Then I get this error from the server:
java.net.SocketException: socket closed
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.socketRead(Unknown Source)
at java.net.SocketInputStream.read(Unknown Source)
at java.net.SocketInputStream.read(Unknown Source)
at java.net.SocketInputStream.read(Unknown Source)
at java.io.DataInputStream.readUnsignedShort(Unknown Source)
at java.io.DataInputStream.readUTF(Unknown Source)
at java.io.DataInputStream.readUTF(Unknown Source)
at de.julian.factoryserver.net.Client$1.run(Client.java:33)
And this error from my client:
java.io.EOFException
at java.io.DataInputStream.readUnsignedShort(Unknown Source)
at java.io.DataInputStream.readUTF(Unknown Source)
at java.io.DataInputStream.readUTF(Unknown Source)
at ftc.Client$1.run(Client.java:28)
I hope someone can help me!
In class Server, in method send you seem to have closed the outputstream, dont close it, just flush it
public void send(String data) {
try {
out.writeUTF(data);
out.close(); // remove this and replace it with out.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
also in recieve you seem to prematurely close the inputstream
private void receive() {
Thread t = new Thread() {
#Override
public void run() {
while (true) {
try {
process(in.readUTF());
in.close(); // remove this
sleep(100);
} catch (IOException | InterruptedException e) {
e.printStackTrace();
break;
}
}
}
};
t.start();
}
Apply the above fixes and that should fix your exceptions.
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.