【问题标题】:Sockets - SocketException: Socket Closed - Java套接字 - SocketException:套接字已关闭 - Java
【发布时间】:2014-09-09 22:33:33
【问题描述】:

我最近一直在玩套接字,但我遇到了一个问题...... 当我从服务器接收数据时,我收到“java.net.SocketException:socket closed”异常。我没有在任何地方关闭套接字,事实上,我使用 close() 的唯一地方是在扫描仪上从 System.in 读取文本;

这是我的代码:

客户:

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;
    }
}

服务器:

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;
    }
}

数据包发送者:

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);
    }
}

客户接收方:

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();
                }
            }

        }
    }
}

数据包接收方:

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;
    }
}

【问题讨论】:

  • 虽然 Tim 提供的答案可能会解决这个特定问题,但我想指出您的服务器代码已完全损坏,并且一次将连接到单个客户端,即使您似乎正在努力保存客户端的状态(您可能希望在阻塞上下文中使用多个线程......)

标签: java sockets


【解决方案1】:

我认为问题在于您在发送方中的try-with-resources 调用,它将在try 块的末尾调用close() 并因此关闭套接字。尝试在对 sendData() 的所有调用中使用单个 PrintWriter

【讨论】:

  • 这是正确的。关闭PrintWriter 将关闭底层OutputStream,这将触发关闭套接字。这很容易验证。作为一般规则,您应该只打开/关闭每个套接字一次的流和编写器,而不是每次阅读时都打开。
  • @Tim 你在哪里找到了 try-with-resources?
  • @dit PacketSender 在sendData 中有一个,但是它使用了埃及大括号,所以你可能错过了
  • @Tim 我尝试拥有一个 PrintWriter,但现在服务器从未收到数据。
  • 发送每个数据包后,您是否拨打PrintWriter.flush()?如果没有,PrintWriter 可能会在发送内容之前对其进行缓冲...另外,您能否使用当前代码更新您的问题,以便我们查看可能有什么问题?
猜你喜欢
  • 2023-03-03
  • 1970-01-01
  • 2016-07-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-03-01
  • 2021-12-10
  • 1970-01-01
相关资源
最近更新 更多