![](/img/trans.png)
[英]Best way to import/export data from Elasticsearch using Java client
[英]Java the best way of waiting & getting data from your client
我開始使用JDK中的主要網絡軟件包學習網絡,在舉幾個例子之后,這非常簡單。 但是現在,我對制作像聊天系統這樣的多客戶端應用程序很感興趣。
到目前為止,我的結構思想是這樣的:
連接處理程序類,用於處理傳入的連接並保存客戶端列表。 如果找到了新的連接,則創建一個新的客戶端對象,啟動它的線程(Client對象將實現可運行,因此它將啟動它自己的循環服務,它將為收到的新數據包循環),並將其添加到列表中。
我為每個客戶端創建一個新線程,而不是遍歷所有客戶端,因為從客戶端進程中讀取將停止整個執行過程,並且將等待客戶端發送數據,這讓我很煩,這是我的問題。
我創建了一個簡單的控制台應用程序,可以接收來自客戶端的消息,但是現在我想檢測斷開連接。 我讀到的是,如果用戶未連接,則bufferedReader .read()方法將返回-1,因此我認為我可以循環執行此操作,並且每隔數秒便對每個客戶端進行一次操作,但事實是,客戶端必須向發送一個數據包。 read(),所以,如果您執行.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);
}
}
我的問題是:有什么更好的方法從客戶端讀取數據,而無需讓應用程序等待數據並實際上每次循環? 或者,也許我應該有一個新線程來檢查用戶是否在線,所以每1個客戶端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");
}
}
謝謝!
雖然我沒有時間查看所有代碼,但是有兩點可以幫助您。
1)使用定義的消息頭。 定義客戶端將發送到服務器的每個消息的X字節數。 使用這些字節來定義消息將持續多長時間以及消息的類型。 服務器知道此標頭的長度和布局,並使用它以特定方式處理消息。 示例可能是一個字節的標頭。 值1可能是我已連接的消息。 2可能是我即將斷開連接。 3可能是我當前不在,4可能是傳入的聊天消息。
2)有兩種方法可以處理輸入。 首先是使用阻塞IO,並創建一個單獨的線程來接收來自每個客戶端的消息。 我相信這就是您當前正在做的事情。 第二個是使用非阻塞IO,並在打開的套接字上迭代一個單獨的線程並進行讀取。 非阻塞將檢查是否有要讀取的數據,但如果沒有,線程將繼續執行。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.