java 从 Socket 多次打开读/写流

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10962736/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 03:14:28  来源:igfitidea点击:

Opening read/write streams multiple times from a Socket

javasockets

提问by Kushal

In a class where I have ServerSocketlistening for incoming connections, following is the code:

在我ServerSocket监听传入连接的类中,以下是代码:

while(isRunning)
{
    try
    {
        Socket s = mysocketserver.accept();
        acknowledgeClient(s);
        new ClientHandler(s).start(); //Start new thread to serve the client, and get back to accept new connections.
    }
    catch(Exception ex)
    {
        ex.printStackTrace();
    }
}

And following is acknowledgeClient(Socket s)code.

以下是acknowledgeClient(Socket s)代码。

ObjectInputStream in = new ObjectInputStream(s.getInputStream);
ObjectOutputStream out = new ObjectOutputStream(s.getOutStream);
String msg = in.readObject().toString();
System.out.println(msg+" is Connected"); //Show who's connected
out.writeObject("success"); //Respond with success.
in.close();
out.close();

The run()method of the ClientHandler.

run()方法ClientHandler

try
{
    in = new ObjectInputStream(client.getInputStream());
    out = new ObjectOutputstream(client.getOutputStream());
    String msg = "";
    while(!msg.equalsIgnoreCase("bye"))
    {
        msg = in.readObject().toString();
        System.out.println("Client Says - "+msg);
        out.writeObject("success");
    }
    in.close();
    out.close();
}
catch(Exception ex)
{
    ex.printStackTrace();
}

And following is the way how client program communicates with this Echo Server.

以下是客户端程序如何与这个 Echo Server 通信的方式。

try
{
    int count = 10;
    client = new Socket("localhost",8666);
    in = new ObjectInputStream(client.getInputStream());
    out = new ObjectOutputstream(client.getOutputStream());
    out.writeObject("Foo");
    System.out.println("Connection Status : "+in.readObject().toString());
    while(count>0)
    {
        out.writeObject("Hello!");
        String resp = in.readObject().toString(); //Getting EOFException here.
        System.out.println("Sent with :"+resp);
        count--;
        Thread.sleep(1000);
    }
    out.close();
    in.close();
    client.close();
}
catch(Exception ex)
{
    ex.printStackTrace();
}

As you might have noticed that, after the client is acknowledged after connection, I close the read/write streams, and from new thread which is serving the client, I'm opening the stream again, and from the server reading/writing from the connected socket is started, but as soon as I attempt to read server's response on sending Hello!by client, it crashes with EOFExceptioninstead of getting success.

您可能已经注意到,在连接后确认客户端后,我关闭读/写流,并从为客户端提供服务的新线程再次打开流,并从服务器读取/写入连接的套接字已启动,但是一旦我尝试读取Hello!客户端发送时服务器的响应,它就会崩溃EOFException而不是获取success.

I know the causes for which EOF occurs but not getting the clue that why is it happening here, I'm not attempting to read socket that has nothing in its stream (it should have successas written by server).

我知道 EOF 发生的原因,但没有得到为什么会在这里发生的线索,我没有尝试读取流中没有任何内容的套接字(它应该success由服务器写入)。

Is it too early that client is attempting to read socket before server has printed Hello!on its end and written successas response?

在服务器端打印Hello!并写入success响应之前,客户端尝试读取套接字是否为时过早?

P.S. : I know its not a good way to ask question by putting so much code, we're expected here to get answers of the issue and understand it rather than having our problem fixed by others and get away. So, I've provided this much code to show all aspects from the problem.

PS:我知道通过放置这么多代码来提问不是一个好方法,我们希望在这里得到问题的答案并理解它,而不是让其他人解决我们的问题并逃脱。所以,我提供了这么多代码来显示问题的所有方面。

回答by Lai Xin Chu

I studied the source code of ObjectInputStream, and it appears that the reference to the original input stream s.getInputStream()is stored inside the ObjectInputStream.

我研究了 ObjectInputStream 的源代码,似乎原始输入流的引用s.getInputStream()存储在 ObjectInputStream 中。

When you close the ObjectInputStream, s.getInputStream()is closed as well.

当您关闭 ObjectInputStream 时,s.getInputStream()也会关闭。

Once an input stream is closed, it cannot be opened again. Thus, you get an EOFException, which indicates that you are at the end of the stream (since the stream could not be opened again).

输入流一旦关闭,就无法再次打开。因此,您会得到一个 EOFException,这表明您处于流的末尾(因为无法再次打开流)。

You should do something like this to acknowledge the client.

你应该做这样的事情来承认客户。

Inside the run() method of the ClientHandler:

在 ClientHandler 的 run() 方法中:

try {
    // acknowledge client
    ObjectInputStream in = new ObjectInputStream(s.getInputStream());
    ObjectOutputStream out = new ObjectOutputStream(s.getOutStream());
    String msg = in.readObject().toString();
    System.out.println(msg+" is Connected"); //Show who's connected
    out.writeObject("success"); //Respond with success.
    // end acknowledge client

    String msg = "";
    while(!msg.equalsIgnoreCase("bye"))
    {
        msg = in.readObject().toString();
        System.out.println("Client Says - "+msg);
        out.writeObject("success");
    }
    in.close();
    out.close();
}
catch(Exception ex)
{
    ex.printStackTrace();
}

If you want to isolate the acknowledge code in a seperate method, just be sure to maintain a proper reference to the same ObjectInputStream without closing the stream, then pass the reference around.

如果您想在单独的方法中隔离确认代码,只需确保在不关闭流的情况下维护对同一 ObjectInputStream 的正确引用,然后传递引用。

回答by Peter Lawrey

I'm opening the stream again, and from the server reading/writing from the connected socket is started,

我再次打开流,并从服务器开始从连接的套接字读取/写入,

Once a stream is close, you can't open it again. In fact you can't use two Object stream on the same stream this way at all.

一旦流关闭,您将无法再次打开它。实际上,您根本不能以这种方式在同一个流上使用两个对象流。

Instead you should create an object stream for input and output once and only once and not close it until you have finished.

相反,您应该一次且仅一次为输入和输出创建一个对象流,并且在完成之前不要关闭它。

回答by Kumar Vivek Mitra

Well take a look at this program, i wrote it to understand multiple clients and server communication, your question is answered in this program.

看看这个程序,我写它是为了理解多个客户端和服务器的通信,你的问题在这个程序中得到了回答。

The Client side code

客户端代码

public class ClientWala {

    public static void main(String[] args) throws Exception{

        Boolean b = true;
    Socket s = new Socket("127.0.0.1", 4444);

    System.out.println("connected: "+s.isConnected());


    OutputStream output = s.getOutputStream();
    PrintWriter pw = new PrintWriter(output,true);

    // to write data to server
    while(b){

        if (!b){

             System.exit(0);
        }

        else {
            pw.write(new Scanner(System.in).nextLine());
        }
    }


    // to read data from server
    InputStream input   = s.getInputStream();
    InputStreamReader isr = new InputStreamReader(input);
    BufferedReader br = new BufferedReader(isr);
    String data = null;

    while ((data = br.readLine())!=null){

        // Print it using sysout, or do whatever you want with the incoming data from server

    }




    }
}

Server Side code

服务器端代码

public class ServerTest {

    ServerSocket s;

    public void go() {

        try {
            s = new ServerSocket(44457);

            while (true) {

                Socket incoming = s.accept();
                Thread t = new Thread(new MyCon(incoming));
                t.start();
            }
        } catch (IOException e) {

            e.printStackTrace();
        }

    }

    class MyCon implements Runnable {

        Socket incoming;

        public MyCon(Socket incoming) {

            this.incoming = incoming;
        }

        @Override
        public void run() {

            try {
                PrintWriter pw = new PrintWriter(incoming.getOutputStream(),
                        true);
                InputStreamReader isr = new InputStreamReader(
                        incoming.getInputStream());
                BufferedReader br = new BufferedReader(isr);
                String inp = null;

                boolean isDone = true;

                System.out.println("TYPE : BYE");
                System.out.println();
                while (isDone && ((inp = br.readLine()) != null)) {

                    System.out.println(inp);
                    if (inp.trim().equals("BYE")) {
                        System.out
                                .println("THANKS FOR CONNECTING...Bye for now");
                        isDone = false;
                        s.close();
                    }

                }
            } catch (IOException e) {
                // TODO Auto-generated catch block
                try {
                    s.close();
                } catch (IOException e1) {
                    // TODO Auto-generated catch block
                    e1.printStackTrace();
                }
                e.printStackTrace();
            }

        }

    }

    public static void main(String[] args) {

        new ServerTest().go();

    }

}

回答by user207421

Closing any input stream or output stream or reader or writer around a socket stream closes the socket, and by implication the other streams, readers, and writers.

关闭套接字流周围的任何输入流或输出流或读取器或写入器将关闭套接字,并暗示其他流、读取器和写入器。

Use the same streams, readers, writers for the life of the socket.

在套接字的生命周期中使用相同的流、读取器、写入器。