Socket closed as soon as passed into new thread - java

I am trying to create a multi-threaded duplex chat server. I had it working fine before I moved the code into threads, but now I'm getting "SocketException: Socket is closed" whenever a thread tries to access a socket.
My teacher and I can't figure it out. (teacher knows even less Java than I do; he is a C guy). It seems like the socket is open, but as soon as it goes into the thread, it is closed.
What am I doing wrong?
Client code:
public class Client {
public static void main(String[] args) throws IOException {
String hostName = "localhost";
int portNumber = 6969;
try (
Socket socket = new Socket(hostName, portNumber);
) {
System.out.println("Chat connected");
//Sender
if (!socket.isClosed())
new Thread(new Sender(socket)).start();
//Receiver
if (!socket.isClosed())
new Thread(new Receiver(socket)).start();
} catch (SocketException e) {
System.out.println("Connection terminated unexpectedly");
}
}
}
Server code:
public class Server {
public static void main(String[] args) throws IOException {
int portNumber = 6969;
try (
ServerSocket serverSocket = new ServerSocket(portNumber);
Socket clientSocket = serverSocket.accept();
) {
//Receiver
if (!clientSocket.isClosed())
new Thread(new Receiver(clientSocket)).start();
//Sender
if (!clientSocket.isClosed())
new Thread(new Sender(clientSocket)).start();
} catch (Exception e) {
e.printStackTrace();
}
}
}
Receiver thread code:
class Receiver implements Runnable {
private Socket socket;
Receiver(Socket s) throws IOException {
socket = s;
}
#Override
public void run() {
try (BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()))) {
String received;
do {
received = in.readLine();
if (received == null) break;
System.out.println("Them: " + received);
} while (!received.contains("/dropmic"));
} catch (IOException e) {
e.printStackTrace();
}
}
}
Sender thread code:
class Sender implements Runnable {
private Socket socket;
Sender(Socket s) throws IOException {
socket = s;
}
#Override
public void run() {
try (PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
BufferedReader stdIn = new BufferedReader(new InputStreamReader(System.in))) {
String sent;
do {
System.out.print("You: ");
sent = stdIn.readLine();
if (sent == null) break;
out.println(sent);
} while (!sent.contains("/dropmic"));
} catch (IOException e) {
e.printStackTrace();
}
}
}
Server output:
java.net.SocketException: Socket is closed
at java.net.Socket.getOutputStream(Socket.java:943)
at Sender.run(Sender.java:16)
at java.lang.Thread.run(Thread.java:745)
java.net.SocketException: Socket closed
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.socketRead(SocketInputStream.java:116)
at java.net.SocketInputStream.read(SocketInputStream.java:170)
at java.net.SocketInputStream.read(SocketInputStream.java:141)
at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:284)
at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:326)
at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:178)
at java.io.InputStreamReader.read(InputStreamReader.java:184)
at java.io.BufferedReader.fill(BufferedReader.java:161)
at java.io.BufferedReader.readLine(BufferedReader.java:324)
at java.io.BufferedReader.readLine(BufferedReader.java:389)
at Receiver.run(Receiver.java:19)
at java.lang.Thread.run(Thread.java:745)
Process finished with exit code 0
Client output (Still running):
Chat connected
You: java.net.SocketException: Socket is closed
at java.net.Socket.getInputStream(Socket.java:903)
at Receiver.run(Receiver.java:16)
at java.lang.Thread.run(Thread.java:745)

You are using a try-with-resources statement, and putting the socket as the resources. However, when you create the new thread, this try-with-resources reaches the end of its code and closes the sockets. Put your sockets inside the actual try statement and close them manually to fix this.

Related

Why can't server and client be started together?

Relevant code:
#Test
public void serverTest() throws IOException {
GameServer server = new GameServer();
server.start(9000);
GameClient client1 = new GameClient();
GameClient client2 = new GameClient();
client1.startConnection("localhost", 9000);
client2.startConnection("localhost", 9000);
client1.sendMessage("Hey I am client 1");
client2.sendMessage("Hey I am client 2");
}
public class GameServer {
private ServerSocket serverSocket;
public void start(int port) throws IOException {
System.out.println("Server started !!!");
serverSocket = new ServerSocket(port);
while (true) {
new Thread(new GameClientHandler(serverSocket.accept())).start();
}
}
public void stop() throws IOException {
serverSocket.close();
}
private static class GameClientHandler implements Runnable {
private Socket clientSocket;
private PrintWriter out;
private BufferedReader in;
public GameClientHandler(Socket socket) {
this.clientSocket = socket;
}
#Override
public void run() {
System.out.println(Thread.currentThread().getName());
try {
out = new PrintWriter(clientSocket.getOutputStream(), true);
in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
String inputLine = in.readLine();
while ((inputLine = in.readLine()) != null){
System.out.print(inputLine);
}
} catch (IOException e) {
e.printStackTrace();
}
try {
in.close();
out.close();
clientSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Why can't the server and client be started together in the #Test? I think it gets stuck in the infinite while loop but at the same time, shouldn't there be context switching with the new threads started after accepting the connection?
I expected at least the name of the 2 new threads to be printed but it doesn't happen.
Let us look carefully to your test code:
GameServer server = new GameServer();
Ok, this lines creates a server, and the test thread is ready to execute next line
server.start(9000);
Ok, the test thread starts the server, and will be ready to execute the next line when the start method will return.
What happens in start:
System.out.println("Server started !!!");
Ok, you should see that message
serverSocket = new ServerSocket(port);
Ok, you have created a ServerSocket
while (true) {
new Thread(new GameClientHandler(serverSocket.accept())).start();
}
ok you a waiting for a connection (at serverSocket.accept()), will create a new thread to handle it as soon as you will get one, and loop again.
But as this point, the test thread is waiting and will never go to the following line to start the first connection. And it will remain stuck unless something else (maybe another thread) starts those damned connections.
The method GameServer.start will only return with an exception. That is because you have the while-loop.
So your test execution will start the server and wait for someone to open a connection, but that never happens.

java.net.SocketException: Software caused connection abort: socket write error when resubmitting the request

working with sockets on this problem. I wrote the implementation of Http and TCP servers. HTTP works completely correctly, so I can send requests to the server one by one. What can not be said about the TCP server, the first request leaves and is handled correctly, but when you try to send the following request, throws this exception:
java.net.SocketException: Software caused connection abort: socket write error
at java.net.SocketOutputStream.socketWrite0(Native Method)
at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:111)
at java.net.SocketOutputStream.write(SocketOutputStream.java:134)
at java.io.DataOutputStream.writeBytes(DataOutputStream.java:276)
at Main.main(Main.java:24)
After that, the client side is closed, and the server side continues to work.HTTP and TCP are implemented from the same Server class, which starts the server.
MyServer:
public abstract class Server implements Runnable {
private final Socket clientSocket;
public Server(Socket clientSocket) {
this.clientSocket = clientSocket;
}
#Override
public void run() {
try (BufferedReader reader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
BufferedWriter output = new BufferedWriter(new PrintWriter(clientSocket.getOutputStream()))) {
String req = getRequest(reader);
setResponse(output, req);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
clientSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Class that starts the server:
public class RunServer extends Thread {
private final int port;
private ExecutorService executorService;
private String serverType;
private ServerFactoryContainer serverFactoryContainer;
public RunServer(String serverType, int port) {
this.port = port;
this.executorService = Executors.newFixedThreadPool(4);
this.serverType = serverType;
this.serverFactoryContainer = new ServerFactoryContainer();
}
#Override
public void run() {
try {
ServerSocket serverSocket = new ServerSocket(port);
while (!isInterrupted()) {
Socket clientSocket;
try {
clientSocket = serverSocket.accept();
executorService.execute(serverFactoryContainer.getServerFactory(serverType).createServer(clientSocket));
} catch (IOException e) {
e.printStackTrace();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
TCP client-side:
public class Main {
public static void main(String[] args) throws IOException {
String req;
String resp;
try (Socket clientSocket = new Socket(InetAddress.getLocalHost(), Constants.ServerConstant.TCP_PORT);
BufferedReader inFromClient = new BufferedReader(new InputStreamReader(System.in));
DataOutputStream outToServer = new DataOutputStream(clientSocket.getOutputStream());
BufferedReader inFromServer = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()))) {
while (true) {
System.out.println("Write command [get count] or [get item]");
req = inFromClient.readLine().toLowerCase();
outToServer.writeBytes(req + "\n"); // I get an exception here when I send a request to the server
resp = inFromServer.readLine();
if (!resp.isEmpty()) {
System.out.println(resp);
}
if (req.equals("exit")) {
System.exit(1);
}
}
}
}
Why do I get the exception that I indicated above when I resubmit the request to the TCP server and why is this exception not thrown when sending a second request to the HTTP server?
#Override
protected String getRequest(BufferedReader input) throws IOException {
return input.readLine();
}
#Override
protected void setResponse(BufferedWriter output, String request) throws IOException {
String result = serverCommandController.execute(RequestParser.tcpParserCommand(request));
output.write(result);
output.flush();
}
You are closing the client connection before the client is done. Try this in your Server class:
#Override
public void run()
{
try (BufferedReader reader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream())); BufferedWriter output = new BufferedWriter(new PrintWriter(clientSocket.getOutputStream())))
{
while (clientSocket.isConnected())
{
String req = getRequest(reader);
setResponse(output, req);
}
}
catch (IOException e)
{
e.printStackTrace();
}
finally
{
try
{
clientSocket.close();
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
Your server appears to close the socket after sending a response. After that, the client will not be able to send further requests without opening a new connection. Typically, the server allows the client to control the fate of the connection, so that the client can send multiple requests. Your client could send a "close" request to indicate to the server that the client intends to close the socket and does not expect a response.

Java Sockets - EOFException when trying to implement multi-threading

I think it's because when I multi-thread the client&server, the DataOutputStream and DataInputStream buffers I use get overwritten or something like that since the socket can only have 1 duplex connection.
Here's what I have for now:
Client Class in my client program:
public static void main(String args[]) throws UnknownHostException, IOException, InterruptedException {
for (int i=0;i<2;i++) //change limit on i to change number of threads
{
new Thread(new ClientHandler(i)).start();
}
Thread.sleep(10000);
ClientHandler class in my client program:
(Sends a value to the server, the server will echo it back).
public class ClientHandler implements Runnable {
public int clientNumber;
public ClientHandler(int i){
this.clientNumber=i;
}
public void run() {
Socket socket = null;
try {
socket = new Socket("localhost",9990);
System.out.println("connected client number "+clientNumber);
DataOutputStream output = new DataOutputStream(socket.getOutputStream());
DataInputStream input = new DataInputStream(socket.getInputStream());
output.writeDouble((new Random()).nextDouble());
System.out.println(input.readDouble());
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally{
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
Server Class in my server program:
ServerSocket socket = new ServerSocket(9990);
try {
while (true) {
Socket threadSocket = socket.accept();
new Thread(new ServerHandler(threadSocket)).start();
Thread.sleep(10000);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
finally {
socket.close();
}
}
}
ServerHandler Class in my server program (receives value from client and echoes it back)
public class ServerHandler implements Runnable {
private Socket socket;
public ServerHandler(Socket socket) {
this.socket = socket;
}
public void run() {
while(true) {
try {
DataInputStream input = new DataInputStream(socket.getInputStream());
DataOutputStream output = new DataOutputStream(socket.getOutputStream());
double a = input.readDouble();
output.writeDouble(a);
}catch (IOException e){
e.printStackTrace();
}
}
}
So it's a pretty straight-forward implementation: create multiple threads of the client, and connect them to multiple threads of the server.
Everything works fine until the line:
double a = input.readDouble();
in my ServerHandler class.
I get an EOFException
I'm guessing it's because there can only be a single duplex connection between sockets. But if that's the case then how would I implement multi-threading of sockets at all?
So my question is: how can I get rid of the EOFException and allow myself to perform multi-threaded client-server socket interaction?
(preferably not changing much about my code because it's taken me a long time to get to this point).
The problem is that you share same Socket variable in ServerHandler for all threads:
private static Socket socket
Remove static keyword. Your ServerHandler will be something like this:
public static class ServerHandler implements Runnable {
private Socket socket;
public ServerHandler(Socket socket) {
this.socket = socket;
}
public void run() {
try {
DataInputStream input = new DataInputStream(socket.getInputStream());
DataOutputStream output = new DataOutputStream(socket.getOutputStream());
double a = input.readDouble();
output.writeDouble(a);
} catch (IOException e) {
e.printStackTrace();
}
}
}

Java socket works only for one client, blocked after server accept

I have a problem with my client/server program, which is blocked after one client is connected. My one client can communicate with my server, but when I try to connect another, the second can't connect. I never see my 'ok' on my console:
public class Server{
private Map<Integer,ThreadClient > mapThreads;
private ServerSocket serveur ;
public static void main(String args[])
{
try{
Serveur serv = new Server();
serv.setServer( new ServerSocket(4786,2));
while (true)
{
serv.getMapThreads().put(new ThreadClient(serv.getServer().accept(),serv);
System.out.println("ok");
}
}
catch (Exception e) { }
}
class ThreadClient implements Runnable
{
private Thread t;
private Socket socket;
private ObjectOutputStream oos ;
private ObjectInputStream ois;
private Serveur server;
public ThreadClient(Socket s, Server serv ) throws ClassNotFoundException
{
server = serv;
socket=s;
try{
oos = new ObjectOutputStream(socket.getOutputStream());
ois = new ObjectInputStream(socket.getInputStream());
}
catch (IOException e){ }
t = new Thread(this);
t.start();
}
public void run()
{
try
{
while(true){
// send and recev message
}
}
}
catch (Exception e){ }
}
Move the construction of the object streams out of the constructor and into the run() method. The process implies I/O with the peer so it shouldn't be carried out in the accept() thread.

Socket Closed error when trying to reopen connection

I am making a program that requires the UI to update every time a client receives data from a server. To to this the socket and serversocket have to be closed and reopened every time. Although when the program tries to accept the new connection, here is my code and the error:
public void startServer(){
Thread serverstart = new Thread(){
public void run() {
try {
serversocket = new ServerSocket(socket);
while(true){
skt = serversocket.accept();
close.setEnabled(true);
new Thread(new newClient(skt)).start();
}
} catch (IOException e){
e.printStackTrace();
}
}
};serverstart.start();
}
static class newClient implements Runnable {
private Socket socket;
static PrintStream output;
public newClient(Socket skt){
this.socket = skt;
}
#Override
public void run(){
try {
output = new PrintStream(socket.getOutputStream());
} catch(IOException ioe){
ioe.printStackTrace();
}
}
}
public void sendData(){
tallydata = Integer.toString(preview) + " " + Integer.toString(program);
System.out.println(tallydata);
newClient.output.print(tallydata);
try{
skt.close();
serversocket.close();
} catch(IOException e){
e.printStackTrace();
}
startServer();
}
The socket is closed at the end of the sendData() method and the startServer() method is called to restart the connection again after that. Here is the error:
java.net.SocketException: Socket closed
at java.net.PlainSocketImpl.socketAccept(Native Method)
at java.net.AbstractPlainSocketImpl.accept(AbstractPlainSocketImpl.java:398)
at java.net.ServerSocket.implAccept(ServerSocket.java:522)
at java.net.ServerSocket.accept(ServerSocket.java:490)
at TallySystem.servergui$1.run(servergui.java:201)
Thanks.
Why are you closing and reopening the server anyway? Just start it once and leave it alone. Thats how it should be used.
Anyway, as per the ServerSocket documentation:
public void close()
Closes this socket. Any thread currently blocked in accept() will throw a SocketException.
Thats precisely your problem. You are closing the ServerSocket while its busy awaiting connections.

Categories

Resources