我開始學習與JDK中主要網絡包的聯網,在幾個示例之後,它非常簡單,容易。但是現在我有興趣創建像聊天系統這樣的多客戶端應用程序。Java從客戶端等待並獲取數據的最佳方式
我的想法結構到目前爲止是這樣的:
連接處理類,它處理傳入的連接,並持有客戶的名單。 如果找到新的連接,創建一個新的客戶端對象,啓動它的線程(Client對象將實現可運行的,因此它將啓動它自己的循環服務,它將循環接收新的數據包),並將其添加到列表中。
我爲每個客戶端創建一個新線程,而不是循環遍歷所有客戶端,因爲從客戶端進程讀取會停止整個執行並等待客戶端發送數據,這有點讓我很惱火,這是我的問題。
我已經創建了一個簡單的控制檯應用程序接收來自客戶端的消息,但現在我想檢測斷開連接。如果用戶沒有連接,我讀bufferedReader .read()方法返回-1,所以我想我可以循環,併爲每個客戶端每隔幾秒鐘執行一次,但事實是,客戶端必須發送一個數據包才能完成。讀()它,讓我們說如果你這樣做.read()它會等待&停止整個線程,直到收到數據包,(我認爲)。
這是我當前的代碼,從客戶端獲得消息:
public boolean isConnected() {
try {
this.in.read();
this.lastCheck = System.currentTimeMillis();
return true;
} catch (IOException e) {
if (!inConnection()) {
System.out.println("User disconnected");
try {
this.destruct();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
return false;
}
private boolean inConnection() {
return System.currentTimeMillis() - lastCheck < this.maxTime;
}
public void startClientService() throws IOException {
while(!this.session.isClosed()) {
if (System.currentTimeMillis() - this.checkTime > 600) {
System.out.println(System.currentTimeMillis() - this.checkTime);
if (this.isConnected()) {
int packetType = this.dataIn.readInt();
packets.getPacket(packetType);
}
}
}
}
public void destruct() throws IOException {
this.session.close();
this.connection.removeClient(this);
System.out.println("Session killed");
}
基本上這裏發生了什麼,我送從客戶端裝一個整數,我可能有許多事情要做所以因此我可以設置多唯一的數據包ID,所以如果我想接收和處理聊天消息,數據包ID是216,客戶端發送一個int 216,服務器讀取數據包,進入所有數據包ID的交換機循環,並檢測它是否真的是216,如果是的,它得到處理消息的打包類的實例&獲取接收消息的字節,如下所示:
public class Chat implements Packet {
@Override
public void processPacket(Session c) {
String message = readMessage(c);
System.out.println("Message: " + message);
}
private String readMessage(Session c) {
byte[] data = c.readBytes();
String message = null;
try {
message = new String(data, "UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return message;
}
}
這就是我如何讀取的字節:
public byte[] readBytes() {
int len;
byte[] data = null;
try {
len = this.dataIn.readInt();
data = new byte[len];
if (len > 0) {
this.dataIn.readFully(data);
}
} catch (IOException e) {
e.printStackTrace();
}
return data;
}
好了我的問題:
添加斷開檢測,當我把我的消息後,沒有任何反應。這可能是由於.read()它停止並正在等待響應。但是如果我再次寫一條消息,我會在服務器上收到消息。
這是我暫時的,醜陋的客戶:
public class Client {
public static void main(String[] args) throws UnknownHostException, IOException {
Socket socket = new Socket("127.0.0.1", 43594);
Scanner r = new Scanner(System.in);
PrintWriter out = new PrintWriter(socket.getOutputStream());
String input;
while(true) {
input = r.next();
if (input != null) {
sendMessage(input, out);
}
}
}
public static void sendMessage(String message, PrintWriter out) {
byte[] encoded = encode(message);
out.write(0);
out.println(encoded + "\n");
out.flush();
}
public static byte[] encode(String s) {
return DatatypeConverter.parseBase64Binary(s);
}
public static String decode(byte[] s) {
return DatatypeConverter.printBase64Binary(s);
}
}
我的問題是:什麼是讀取來自客戶端的數據,而不使應用程序等待它實際上循環每次一個更好的辦法?或者也許我應該有一個新的線程來檢查用戶是否在線,因此每個客戶端有2個線程?
如果有人需要我的會話對象(客戶端對象):
public class Session extends Thread implements Runnable {
private Socket session;
private Client client;
private PrintWriter out;
private BufferedReader in;
private PacketHandler packets;
private DataInputStream dataIn;
private ConnectionHandler connection;
private final int checkTime = 1600;
private final int maxTime = 22000;
private long lastCheck;
public Session(Socket session) {
this.session = session;
this.client = new Client(this);
try {
this.setStream();
} catch (IOException e) {
e.printStackTrace();
}
this.packets = new PacketHandler(this);
System.out.println("[New session created]: " + session.getRemoteSocketAddress());
}
public void setConnectionHandler(ConnectionHandler c) {
this.connection = c;
}
public void run() {
try {
this.startClientService();
} catch (IOException e) {
e.printStackTrace();
}
}
public void setStream() throws IOException {
this.out = new PrintWriter(this.session.getOutputStream());
this.in = new BufferedReader(new InputStreamReader(this.session.getInputStream()));
this.dataIn = new DataInputStream(this.session.getInputStream());
}
public Client getClient() {
return this.client;
}
public byte[] readBytes() {
int len;
byte[] data = null;
try {
len = this.dataIn.readInt();
data = new byte[len];
if (len > 0) {
this.dataIn.readFully(data);
}
} catch (IOException e) {
e.printStackTrace();
}
return data;
}
public String readMessage() {
try {
return this.in.readLine();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
public boolean isConnected() {
try {
this.in.read();
this.lastCheck = System.currentTimeMillis();
return true;
} catch (IOException e) {
if (!inConnection()) {
System.out.println("User disconnected");
try {
this.destruct();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
return false;
}
private boolean inConnection() {
return System.currentTimeMillis() - lastCheck < this.maxTime;
}
public void startClientService() throws IOException {
while(!this.session.isClosed()) {
if (System.currentTimeMillis() - this.checkTime > 600) {
System.out.println(System.currentTimeMillis() - this.checkTime);
if (this.isConnected()) {
int packetType = this.dataIn.readInt();
packets.getPacket(packetType);
}
}
}
}
public void destruct() throws IOException {
this.session.close();
this.connection.removeClient(this);
System.out.println("Session killed");
}
}
謝謝!
您是將此項目編寫爲學習練習還是解決問題? – chrylis
@chrylis學習,但不能真正解決這個問題tbh – Artemkller545