简体   繁体   English

客户端不从套接字读取数据?

[英]Client not reading data from socket?

I have spent a while reading other posts, and nobody seems to have the same case as me.我花了一段时间阅读其他帖子,似乎没有人和我有同样的情况。 I have tried all solutions I have read with no results, so I decided to create this question.我已经尝试了所有我读过的解决方案,但没有结果,所以我决定提出这个问题。

I have been working on a server/client application, and the client seems to not read data from the socket, but the server can read data the client sends.我一直在研究服务器/客户端应用程序,客户端似乎没有从套接字读取数据,但服务器可以读取客户端发送的数据。 The client freezes while trying to read the line.客户端在尝试读取该行时冻结。 Here's the code I have:这是我的代码:

Client:客户:

import java.io.IOException;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;
import java.util.Timer;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JLabel;

public class Main {

    public static Socket s = connect();

    public static void sendMessage(String msg) {
        if (s != null) {
            PrintWriter outWriter = null;
            try {
                outWriter = new PrintWriter(s.getOutputStream(), true);
                outWriter.println(msg);
                outWriter.flush();
            } catch (IOException ex) {
                Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
                outWriter.close();
            } finally {
            }
        } else {
            System.err.println("Error, socket is null!");
        }
    }

    public static String readMessage() {
        if (s != null) {
            Scanner in = null;
            try {
                in = new Scanner(s.getInputStream());
            } catch (IOException ex) {
                ex.printStackTrace();
            }
            String ss = "";
            while (in.hasNext()) {
                ss += in.next();
            }
            System.out.println("REPONSE:" + ss);
            return ss;
        } else {
            System.err.println("Error, socket is null!");
        }
        return "err/readMessage";
    }

    public static Socket connect() {
        try {
            Socket sss = new Socket("localhost", 25586);
            sss.setKeepAlive(true);
            return sss;
        } catch (IOException ex) {
            ex.printStackTrace();
            System.exit(-1);
        }
        return null;
    }

    public static void main(String args[]) {
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {

                Thread t = new Thread(new Runnable() {
                    @Override
                    public void run() {
                        sendMessage("HELO");
                        System.out.println("Thread initialized.");

                        while (true) {
                            try {
                                System.out.println("Awaiting message...");
                                Thread.sleep(100);
                                String messages = readMessage();
                                System.out.println("Message recieved! '" + messages + "'");
                                String[] message = messages.split("/");
                                System.out.println(messages);
                                if (message[0].equalsIgnoreCase("DERP")) {                                       // err/reason
                                    System.out.println("IT'S FINALLY WORKING!");
                                } else {
                                    System.out.println("Didn't work :( response:" + messages);
                                }
                            } catch (InterruptedException ex) {
                                ex.printStackTrace();
                            }

                        }
                    }
                });
                t.start();
            }
        });
    }
}

Server:服务器:

import java.util.List;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

public class Main { /* SERVER */


    public static List<EchoThread> list = new ArrayList<>();

    public static int PORT = 25586;

    public static void main(String[] args) throws IOException {
        new Main(PORT);
    }

    public Main(int port) throws IOException {
        this.PORT = port;
        ServerSocket serverSocket = null;
        Socket socket = null;

        try {
            serverSocket = new ServerSocket(PORT);
        } catch (IOException e) {
            e.printStackTrace();

        }
        while (true) {
            try {
                socket = serverSocket.accept();
            } catch (IOException e) {
                System.out.println("I/O error: " + e);
            }
            // new threa for a client
            EchoThread s = new EchoThread(socket);
            s.start();
            list.add(s);
        }
    }

    public static void sendMessageToAll(String ss) {
        for (EchoThread s : list) {
            s.allMessage(ss);
        }
    }
}

class EchoThread extends Thread {

    protected Socket socket;
    InputStream inp = null;
    BufferedReader brinp = null;

    public EchoThread(Socket clientSocket) {
        this.socket = clientSocket;
        try {
            inp = socket.getInputStream();
            brinp = new BufferedReader(new InputStreamReader(inp));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void run() {
        String line;
        while (true) {
            try {
                line = brinp.readLine();
                if ((line == null) || line.equalsIgnoreCase("EXIT")) {
                    socket.close();
                    return;
                } else {
                    handle(line);
                }
            } catch (IOException e) {
                e.printStackTrace();
                return;
            }
        }
    }

    public void handle(String s) {
        String[] keys = s.split("/");
        System.out.println("random: Handling request\"" + s + "\"");
        System.out.println("Response: DERP");
        if (s.equalsIgnoreCase("HELO")) {
            System.out.println("Message recieved:" + s);
        }
        respond("DERP");
    }

    public void respond(String s) {
        try {
            System.out.println("Response_WILLBE:" + s);
            OutputStream os = socket.getOutputStream();
            PrintWriter pw = new PrintWriter(os, true);
            pw.println(s);
            pw.flush();
            System.out.println("Message sent!");
        } catch (Exception ex) {
            Logger.getLogger(EchoThread.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public void allMessage(String s) {
        respond(s);
    }
}

I tried the flush() code and \r\n and println fixes, but none worked!我尝试了flush()代码和\r\nprintln修复,但没有一个奏效! -- Thank you for reading! ——感谢您的阅读!

I'm very curious about the differences between the client's and server's methods of communication.我很好奇客户端和服务器的通信方法之间的差异。 For instance, the client uses a Scanner to read input while the server uses a BufferedReader (which is my personal preference).例如,客户端使用Scanner读取输入,而服务器使用BufferedReader (这是我个人的偏好)。 Just a suggestion: be consistent.只是一个建议:保持一致。

Now -- firstly, the client only sends one message, but then begins to read indefinitely in an infinite loop.现在——首先,客户端只发送一条消息,然后开始无限循环地读取。 Seeing as you know exactly how the server should respond after you send "HELO" to it (it should respond with one line, "DERP"), there is no reason to read from the server in any sort of loop.看到您确切地知道服务器在您向其发送“HELO”后应该如何响应(它应该用一行“DERP”响应),没有理由在任何类型的循环中从服务器读取。

The same issue exists on the server.服务器上也存在同样的问题。 As the client is right now, it will always only send one line to the server ("HELO").就像客户端现在一样,它总是只会向服务器发送一行(“HELO”)。 Consequently, the server should only expect one line and only read one line.因此,服务器应该只期望一行并且只读取一行。 There is absolutely no reason to read input within a loop.绝对没有理由在循环中读取输入。 However, the actual issue persists only in the client's code:但是,实际问题仅存在于客户端的代码中:

You currently have while(in.hasNext()) as a conditional as to how long the client will read input from the server.您当前有while(in.hasNext())作为客户端从服务器读取输入多长时间的条件。 The hasNext method differs in logical function depending on the method of communication. hasNext 方法的逻辑功能因通信方法而异。 In the case of socket communication, hasNext expects a stream and, as such, will always return true unless the socket is closed.在套接字通信的情况下, hasNext需要一个流,因此,除非套接字关闭,否则它将始终返回 true。

Avoid using loops in socket communication in general unless you don't know how many lines to read.通常避免在套接字通信中使用循环,除非您不知道要读取多少行。 In such a scenario, you should first have the sender send some sort of number to the receiver, and then the receiver should read the subsequent lines in a for loop reading 'n' number of times (where n is the received number).在这种情况下,您应该首先让发送者向接收者发送某种数字,然后接收者应该在 for 循环中读取后续行,读取 'n' 次(其中 n 是接收到的数字)。

Here's a very basic client / server communication program using PrintWriters and BufferedReaders.这是一个使用PrintWritersBufferedReaders.

Client客户

public static void main(String[] args){
    try{
        Socket socket = new Socket("localhost", 12345);
        PrintWriter out = new PrintWriter(socket.getOutputStream());
        BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        out.write("HELO\n"); //print("HELO\n") and println("HELO") should work too.
        out.flush();
        System.out.println("Server says " + in.readLine());
        in.close();
        out.close();
        socket.close();
    }catch(IOException e){e.printStackTrace();}
}

Server服务器

public static void main(String[] args){
    try{
        ServerSocket serverSocket = new ServerSocket(12345);
        while(true){
            new Thread(new ClientConnectionThread(serverSocket.accept())).start();
        }
    }catch(IOException e){e.printStackTrace();}
}

private class ClientConnectionThread implements Runnable{
    private Socket socket;
    public ClientConnectionThread(Socket socket){
        this.socket = socket;
    }
    @Override
    public void run(){
        try{
            BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            PrintWriter out = new PrintWriter(socket.getOutputStream());
            System.out.println("Client says " + in.readLine());
            out.write("HELO Back!\n"); //again, print("HELO Back!\n") and
                //println("HELO Back!") should also work
            out.flush();
            out.close();
            in.close();
            socket.close();
        }catch(IOException e){e.printStackTrace();}
    }
}

Notice that no loops are necessary in the actual communication.请注意,在实际通信中不需要循环。

As @zapl commented your client is far to greedy when reading data from the server.正如@zapl 评论的那样,您的客户端在从服务器读取数据时非常贪婪。 Lets look at the process you use to read data from the server:让我们看看你用来从服务器读取数据的过程:

String ss = "";
while (in.hasNext()) {
    ss += in.next();
}
System.out.println("REPONSE:" + ss);

This code will continually pull data from the server until the stream is closed.此代码将不断从服务器拉取数据,直到流关闭。 You probably use this type of code block when reading data from a file or parsing a string which is perfect for those cases because you want all the data from the stream into your string.在从文件读取数据或解析字符串时,您可能会使用这种类型的代码块,这非常适合这些情况,因为您希望将流中的所有数据都放入您的字符串中。

What you are looking to do is read the first resposne from the server designated by a new line \n .您要做的是从新行\n指定的服务器读取第一个响应。 Instead of doing while(in.hasNext()) instead you should just check if in.hasNext() and if so then get that as the response.而不是做while(in.hasNext())而不是你应该只检查 if in.hasNext() ,如果是,那么将其作为响应。

String ss = "";
if (in.hasNext()) {
    ss += in.next();
}
System.out.println("REPONSE:" + ss);

Or maybe more elegantly或者更优雅

if (in.hasNext()) {
    String response = in.next();
    System.out.println("REPONSE:" + response);
    return response;
}
....

First, with sockets, I always like to run the server and telnet into it via localhost.首先,对于套接字,我总是喜欢通过 localhost 运行服务器并 telnet 进入它。 When I do that with yours, I get the back and forth no problem.当我用你的那样做时,我来回没有问题。 So now it's just a matter of fixing your client.因此,现在只需修复您的客户即可。

For the client, get rid of (for the time being) your usage of the Scanner class.对于客户端,(暂时)摆脱对 Scanner 类的使用。 This class has a whole other set of usages that can cause problems.这个类还有一整套可能导致问题的用法。 Instead, keep it simple.相反,保持简单。

Change your client to use a BufferedReader.更改您的客户端以使用 BufferedReader。 Here is your new readMessage() method:这是您的新 readMessage() 方法:

    public  String readMessage() {
        if (s != null) {
            BufferedReader in = null;
            try {
                System.out.println("Creating reader");
                in = new BufferedReader(new InputStreamReader(s.getInputStream()));
            } catch (IOException ex) {
            }
            String ss = "";
            try {
                ss = in.readLine();
            } catch (IOException e) {
            }
            System.out.println("REPONSE:" + ss);
            return ss;

Your client will now work (it does for me), which means you are having issues with the Scanner usage.您的客户端现在可以工作(对我有用),这意味着您在使用 Scanner 时遇到问题。

I will leave you to debug that since that isn't really what your question is about.我会让你调试它,因为这不是你的问题。 Have fun!玩得开心! ;) ;)

Stumbled upon this while looking for something else.在寻找其他东西时偶然发现了这一点。

Alexander Guyer, the thing is that the sockets are meant to be completely duplex .. you can have a client sending messages to server on and on and on, without the server responding even once. Alexander Guyer,问题是套接字是完全双工的......你可以让客户端不断地向服务器发送消息,而服务器甚至没有响应一次。 Maybe you meant that, but I read it differently.也许你的意思是,但我读的不同。 If you are referring to request - response mechanism, it is more like Http messages, where the sender expects a response.如果您指的是请求 - 响应机制,它更像是 Http 消息,发送者期望响应。 Socket is an underlying protocol. Socket 是一种底层协议。

That being said, I created a simple example to teach the new-bees in my workplace.话虽如此,我创建了一个简单的例子来教我工作场所的新手。 It is like this.就像这样。 You can change the sleep param, compile and spawn different clients.您可以更改睡眠参数,编译和生成不同的客户端。 There are some exceptions that gets generated, but you have to remember that this is a VERY SIMPLE example.会生成一些异常,但您必须记住这是一个非常简单的示例。 Meant for folks new to socket programming.适用于套接字编程新手。

You can of course change the server/port to IP Address and port to a different server, I just went ahead with localhost.您当然可以将服务器/端口更改为 IP 地址并将端口更改为不同的服务器,我只是继续使用 localhost。

Source code:源代码:

Server.java服务器.java

package com.example.practice.sockets;

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

public class Server {

    public static void main(String[] args) throws IOException {
        Server s = new Server();
        s.startTheProcess();
    }

    private void startTheProcess() throws IOException {
        Common c = new Common();
        Socket s;
        ServerSocket sc = new ServerSocket(9999);
        System.out.println("Waiting for connection ");

        for (;;) {
            try {
                s = sc.accept();
                System.out.println(Thread.currentThread().getName() + " A new client connected " + s);
                handleSocket(s, c);
            } catch (IOException e1) {
                e1.printStackTrace();
            }
        }
    }

    private void handleSocket(Socket s, Common c) {
        Thread readMessage = new Thread(new Runnable() {
            @Override
            public void run() {
                c.readFromSocketContinuously(s);
            }
        });

        Thread writeMessage = new Thread(new Runnable() {
            @Override
            public void run() {
                c.writeToSocketContinuously(s, "Server writes: ");
            }
        });

        writeMessage.start();
        readMessage.start();
    }
}

Client.java客户端.java

package com.example.practice.sockets;

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

public class Client extends Thread {

    public static void main(String[] args) throws IOException {
        Client s = new Client();
        s.startTheProcess();
    }

    private void startTheProcess() throws IOException {
        Common c = new Common();
        Socket s;
        s = new Socket("localhost", 9999);

        handleSocket(s, c);
    }

    private void handleSocket(Socket s, Common c) {
        Thread readMessage = new Thread(new Runnable() {
            @Override
            public void run() {
                c.readFromSocketContinuously(s);
            }
        });

        Thread writeMessage = new Thread(new Runnable() {
            @Override
            public void run() {
                c.writeToSocketContinuously(s, "Client writes: ");
            }
        });

        writeMessage.start();
        readMessage.start();
    }
}

Common.java通用.java

package com.example.practice.sockets;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;

public class Common {
    
    public void readFromSocketContinuously(Socket s) {
        try {
            for(;s.getKeepAlive() || !s.isClosed();) {
                BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
                String name = br.readLine();
                System.out.println(Thread.currentThread().getName() + " readFromSocketContinuously " + name + "\r\n");
                if ( name == null )
                    break;
            }           
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void writeToSocketContinuously(Socket s, String serverOrClient) {
        try {
            for (int count = 0;s.getKeepAlive() || !s.isClosed(); count++) {
                String dataToWrite = serverOrClient + " From socket " + count + "\r\n";
                BufferedOutputStream out = new BufferedOutputStream(s.getOutputStream());
                if (out != null && !s.isClosed()) {
                    out.write(dataToWrite.getBytes());
                    out.flush();
                    System.out.println(Thread.currentThread().getName() + " writeToSocketContinuously " + dataToWrite);
                    Thread.sleep(500);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM