簡體   English   中英

客戶端不從套接字讀取數據?

[英]Client not reading data from socket?

我花了一段時間閱讀其他帖子,似乎沒有人和我有同樣的情況。 我已經嘗試了所有我讀過的解決方案,但沒有結果,所以我決定提出這個問題。

我一直在研究服務器/客戶端應用程序,客戶端似乎沒有從套接字讀取數據,但服務器可以讀取客戶端發送的數據。 客戶端在嘗試讀取該行時凍結。 這是我的代碼:

客戶:

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

服務器:

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

我嘗試了flush()代碼和\r\nprintln修復,但沒有一個奏效! ——感謝您的閱讀!

我很好奇客戶端和服務器的通信方法之間的差異。 例如,客戶端使用Scanner讀取輸入,而服務器使用BufferedReader (這是我個人的偏好)。 只是一個建議:保持一致。

現在——首先,客戶端只發送一條消息,然后開始無限循環地讀取。 看到您確切地知道服務器在您向其發送“HELO”后應該如何響應(它應該用一行“DERP”響應),沒有理由在任何類型的循環中從服務器讀取。

服務器上也存在同樣的問題。 就像客戶端現在一樣,它總是只會向服務器發送一行(“HELO”)。 因此,服務器應該只期望一行並且只讀取一行。 絕對沒有理由在循環中讀取輸入。 但是,實際問題僅存在於客戶端的代碼中:

您當前有while(in.hasNext())作為客戶端從服務器讀取輸入多長時間的條件。 hasNext 方法的邏輯功能因通信方法而異。 在套接字通信的情況下, hasNext需要一個流,因此,除非套接字關閉,否則它將始終返回 true。

通常避免在套接字通信中使用循環,除非您不知道要讀取多少行。 在這種情況下,您應該首先讓發送者向接收者發送某種數字,然后接收者應該在 for 循環中讀取后續行,讀取 'n' 次(其中 n 是接收到的數字)。

這是一個使用PrintWritersBufferedReaders.

客戶

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

服務器

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

請注意,在實際通信中不需要循環。

正如@zapl 評論的那樣,您的客戶端在從服務器讀取數據時非常貪婪。 讓我們看看你用來從服務器讀取數據的過程:

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

此代碼將不斷從服務器拉取數據,直到流關閉。 在從文件讀取數據或解析字符串時,您可能會使用這種類型的代碼塊,這非常適合這些情況,因為您希望將流中的所有數據都放入您的字符串中。

您要做的是從新行\n指定的服務器讀取第一個響應。 而不是做while(in.hasNext())而不是你應該只檢查 if in.hasNext() ,如果是,那么將其作為響應。

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

或者更優雅

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

首先,對於套接字,我總是喜歡通過 localhost 運行服務器並 telnet 進入它。 當我用你的那樣做時,我來回沒有問題。 因此,現在只需修復您的客戶即可。

對於客戶端,(暫時)擺脫對 Scanner 類的使用。 這個類還有一整套可能導致問題的用法。 相反,保持簡單。

更改您的客戶端以使用 BufferedReader。 這是您的新 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;

您的客戶端現在可以工作(對我有用),這意味着您在使用 Scanner 時遇到問題。

我會讓你調試它,因為這不是你的問題。 玩得開心! ;)

在尋找其他東西時偶然發現了這一點。

Alexander Guyer,問題是套接字是完全雙工的......你可以讓客戶端不斷地向服務器發送消息,而服務器甚至沒有響應一次。 也許你的意思是,但我讀的不同。 如果您指的是請求 - 響應機制,它更像是 Http 消息,發送者期望響應。 Socket 是一種底層協議。

話雖如此,我創建了一個簡單的例子來教我工作場所的新手。 就像這樣。 您可以更改睡眠參數,編譯和生成不同的客戶端。 會生成一些異常,但您必須記住這是一個非常簡單的示例。 適用於套接字編程新手。

您當然可以將服務器/端口更改為 IP 地址並將端口更改為不同的服務器,我只是繼續使用 localhost。

源代碼:

服務器.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();
    }
}

客戶端.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();
    }
}

通用.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