![](/img/trans.png)
[英]Server Socket Keeps Reading Data Until I close Socket from Client In Java
[英]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\n
和println
修復,但沒有一個奏效! ——感謝您的閱讀!
我很好奇客戶端和服務器的通信方法之間的差異。 例如,客戶端使用Scanner
讀取輸入,而服務器使用BufferedReader
(這是我個人的偏好)。 只是一個建議:保持一致。
現在——首先,客戶端只發送一條消息,然后開始無限循環地讀取。 看到您確切地知道服務器在您向其發送“HELO”后應該如何響應(它應該用一行“DERP”響應),沒有理由在任何類型的循環中從服務器讀取。
服務器上也存在同樣的問題。 就像客戶端現在一樣,它總是只會向服務器發送一行(“HELO”)。 因此,服務器應該只期望一行並且只讀取一行。 絕對沒有理由在循環中讀取輸入。 但是,實際問題僅存在於客戶端的代碼中:
您當前有while(in.hasNext())
作為客戶端從服務器讀取輸入多長時間的條件。 hasNext 方法的邏輯功能因通信方法而異。 在套接字通信的情況下, hasNext
需要一個流,因此,除非套接字關閉,否則它將始終返回 true。
通常避免在套接字通信中使用循環,除非您不知道要讀取多少行。 在這種情況下,您應該首先讓發送者向接收者發送某種數字,然后接收者應該在 for 循環中讀取后續行,讀取 'n' 次(其中 n 是接收到的數字)。
這是一個使用PrintWriters
和BufferedReaders.
客戶
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.