0

I've been playing around with sockets recently, but I've come across a problem... I'm getting a "java.net.SocketException: socket closed" exception when I receive data from the server. I haven't closed the socket anywhere, in fact, the only place I use close() is on the scanner to read text from System.in;

Here is my code:

Client:

package packets.sidedcomputer;

import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;

import packets.MessagePacket;
import packets.sender.PacketSender;
import packets.side.Side;

public class Client extends SidedComputer
{
    volatile boolean finished = false;

    volatile String username;

    volatile Server server;

    public Socket clientSocket;

    public ClientReciever reciever;

    public Client(Server server, String username) throws UnknownHostException, IOException
    {
        this.username = username;
        this.server = server;
        this.reciever = new ClientReciever(this);
    }

    public void stopClient()
    {
        finished = true;
    }

    @Override
    public void run()
    {
        Scanner scanner = new Scanner(System.in);

        reciever.start();

        while(!finished)
        {
            try 
            {
                this.clientSocket = new Socket("192.168.1.25", 10501);

                String line;

                while((line = scanner.nextLine()) != null)
                {     
                    PacketSender sender = new PacketSender();

                    System.out.println("Client sending message \"" + line + "\" to server");
                    sender.sendPacket(new MessagePacket(line, username), clientSocket);
                }
            }
            catch (Exception e) 
            {
                e.printStackTrace();
            }

        }

        scanner.close();
    }

    @Override
    public Side getSide() 
    {
        return Side.CLIENT;
    }
}

Server:

package packets.sidedcomputer;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;

import packets.Packet;
import packets.data.PacketData;
import packets.info.ClientInfo;
import packets.reciever.PacketReciever;
import packets.sender.PacketSender;
import packets.side.Side;

public class Server extends SidedComputer
{
    volatile boolean finished = false;

    public ServerSocket serverSocket;

    public volatile List<ClientInfo> clients = new ArrayList<ClientInfo>();

    public void stopServer()
    {
        finished = true;
    }

    public Server()
    {
        try 
        {
            serverSocket = new ServerSocket(10501);
        } 
        catch (IOException e)
        {
            e.printStackTrace();
        }
    }

    @Override
    public void run()
    {
        try 
        {
            while (!finished)
            {
                Socket clientSocket = serverSocket.accept();  

                if(clientSocket != null)
                {
                    ClientInfo clientInfo = new ClientInfo(clientSocket);

                    this.clients.add(clientInfo);

                    BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));

                    String dataString;

                    while((dataString = in.readLine()) != null)
                    {
                        PacketReciever packetReciever = new PacketReciever();

                        PacketData packetData = new PacketData();

                        packetData.decodeInto(dataString);

                        Packet packet = packetReciever.recievePacket(packetData, packetData.packetID, getSide(), clientSocket.getLocalAddress().getHostAddress().toString(), clientSocket.getLocalPort() + "");

                        PacketSender packetSender = new PacketSender();

                        for (ClientInfo client : this.clients)
                        {
                            PrintWriter out = new PrintWriter(client.socket.getOutputStream(), true);
                            packetSender.sendPacketToClient(packet, out);
                        }
                    }
                }
            }
        } 
        catch (Exception e) 
        {
            e.printStackTrace();
            System.exit(1);
        }
    }

    @Override
    public Side getSide() 
    {
        return Side.SERVER;
    }
}

Packet Sender:

package packets.sender;

import java.io.IOException;
import java.io.PrintWriter;
import java.net.Socket;

import packets.Packet;
import packets.data.PacketData;

public class PacketSender implements IPacketSender
{
    @Override
    public void sendPacket(Packet packet, Socket socket)
    {
        if(packet.getDefualtID() == 0)
        {
            PacketData packetData = new PacketData(packet.getDefualtID());

            packet.writeData(packetData);

            String data = packetData.encodeIntoString();

            sendData(socket, data);
        }
    }

    protected void sendData(Socket socket, String data)
    {
        try 
        {

            try 
            (
                PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
            ) 
            {
                out.println(data);
            } 
            catch (IOException e) 
            {
                System.err.println("Couldn't get I/O for the connection to " + socket);
                System.exit(1);
            } 
        }
        catch (Exception e) 
        {
            e.printStackTrace();
        }
    }

    public void sendPacketToClient(Packet packet, PrintWriter out)
    {
        PacketData packetData = new PacketData(packet.getDefualtID());

        packet.writeData(packetData);

        String data = packetData.encodeIntoString();

        out.println(data);
    }
}

Client Receiver:

package packets.sidedcomputer;

import java.io.BufferedReader;
import java.io.InputStreamReader;

import packets.data.PacketData;
import packets.reciever.PacketReciever;
import packets.side.Side;

public class ClientReciever extends Thread
{
    public Client client;

    public ClientReciever(Client client)
    {
        this.client = client;
    }

    volatile boolean running = true;

    public void stopRunning()
    {
        running = false;
    }

    @Override
    public void run()
    {
        while(running)
        {
            if(client.clientSocket != null)
            {
                try 
                {
                    BufferedReader in = new BufferedReader(new InputStreamReader(client.clientSocket.getInputStream()));
                    String line;

                    while((line = in.readLine()) != null)
                    {
                        PacketReciever reciever = new PacketReciever();

                        PacketData packetData = new PacketData();
                        packetData.decodeInto(line);

                        reciever.recievePacket(packetData, packetData.packetID, Side.CLIENT, client.clientSocket.getLocalAddress().getHostAddress().toString(), client.clientSocket.getPort() + "");
                    }
                }
                catch (Exception e)
                {
                    e.printStackTrace();
                }
            }

        }
    }
}

Packet Receiver:

package packets.reciever;

import packets.Packet;
import packets.MessagePacket;
import packets.data.PacketData;
import packets.side.Side;

public class PacketReciever implements IPacketReciever
{
    @Override
    public Packet recievePacket(PacketData packetData, int id, Side side, String hostName, String port) 
    {
        Packet packet = null;

        if(id == 0)
        {
            packet = new MessagePacket();

            packet.readData(packetData);

            packet.execute(side, hostName + ":" + port);
        }

        return packet;
    }
}
1
  • 1
    While the answer provided by Tim is likely to fix this particular problem, I would like to point out that your server code is completely broken and will be connected to a single client at a time, even though you seem to be making an effort to save states of clients (You may want to use more than one thread in a blocking context...) Commented Jul 18, 2014 at 17:57

1 Answer 1

3

I think the problem is your try-with-resources call in the sender, which will call close() at the end of the try block and hence close the Socket. Try using a single PrintWriter across all calls to sendData().

Sign up to request clarification or add additional context in comments.

5 Comments

This is correct. Closing a PrintWriter will close the underlying OutputStream, which will trigger closing the socket. This is very easy to verify. As a general rule you should only open/close streams and writers once per socket, not open every time you read.
@Tim where did you find try-with-resources?
@dit PacketSender has one in sendData, but it uses Egyptian braces, so you may have missed it
@Tim I tried having one PrintWriter, but now the Server never receives the data.
Are you calling PrintWriter.flush() after sending each packet? If not, the PrintWriter might be buffering up content before sending it... Also, can you update your question with your current code so we can see what might be wrong?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.