從0開始 2.多執行緒 - MUD Game

Gary avatar
By Gary
at 2019-12-05T13:36

Table of Contents

今天我們要來正式進入 multi-thread (多執行緒)的部分了
觀察之前的程式片段可以發現到有兩個 while 迴圈
一個負責建立連線, 另一個負責 echo


// 建立連線的迴圈
while (true) {
socket = server.accept();
BufferedReader in = new BufferedReader(new InputStreamReader(
socket.getInputStream()));
PrintStream out = new PrintStream(socket.getOutputStream());
out.println("歡迎來到 telnet echo server!");

// 負責與使用者互動的迴圈
String input;
while ((input = in.readLine()) != null) {
if ("quit".equalsIgnoreCase(input)) {
out.println("Bye! 歡迎下次再來");
socket.close();
break;
}
out.println("Echo: " + input);
}
}


所以我們把負責與使用者互動的部分程式抽離出來
建立一個新的 Player class, 讓原本的 ChatServer 專心處理連線就好

// Player.class
// ✂--------------請沿虛線剪下--------------
package core;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.Socket;

// java 中程式要支援多執行緒需要實作 Runnable 介面
public class Player implements Runnable {
private Socket socket;
private BufferedReader in;
private PrintStream out;

// 建構子, 讓每個 Player 負責管理自己的 Socket 物件
public Player(Socket socket) throws IOException {
this.socket = socket;
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
out = new PrintStream(socket.getOutputStream());
}

// override Runnable.run() 在裡面實作我們需要的邏輯
// 其實就是之前第二個 while 迴圈的內容
@Override
public void run() {
write("歡迎來到 telnet echo server! (多執行續版本)");
try {
while (true) {
String input = read();
if ("quit".equalsIgnoreCase(input)) {
socket.close();
break;
}
write("Echo: " + input);
}
} catch (IOException ignored) {}
}

// 把之前的 in.readLine() 與 out.println() 包裝起來, 方便後續使用
public String read() throws IOException {
return in.readLine();
}

public void write(String message) {
out.println(message);
}

}
// ✂--------------請沿虛線剪下--------------


Player 實作完之後
原本的 ChatServer 的程式碼也變得比較乾淨了

// ChatServer.class
// ✂--------------請沿虛線剪下--------------
package service;

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

import core.Player;

public class ChatServer {
static final int PORT = 4000;

public static void main(String[] args) {
Socket socket;
try (ServerSocket server = new ServerSocket(PORT)) {
System.out.println("Server is listening port: " + PORT + " now");
while (true) {
socket = server.accept();
Player player = new Player(socket);
Thread thread = new Thread(player);
thread.start();
}
} catch (IOException e) {
e.printStackTrace();
}
}

}
// ✂--------------請沿虛線剪下--------------

java 中只要新建一個 Thread 物件
並在建立時傳入剛才已經實作 Runnable 的 Player
接著再呼叫 thread.start(), Thread 就會去開一個新的執行緒去執行 player.run()

你現在可以嘗試多開幾個 client 試著連線到 localhost:4000
我們的 server 已經有能力同時服務許多使用者了

--
╔═ ═╦╦═════╦═════╗
◤◤◤ ╠╣飛鳥ももこ╠═╗ ║
║╚═════╝ ╚═╦═╣
║╔══════╗╔═╩═╣
█◤ ╠╣Momoko Asuka╠╝ ║
◣◢◣◢╩╩══════╩════╝

--
Tags: 線上

All Comments

Ida avatar
By Ida
at 2019-12-07T17:11
建議改用 java.nio 處理 io
Lauren avatar
By Lauren
at 2019-12-09T20:47
多執行緒在系統做大,會有很多雜事
需要處理

請問該如何賺寶石最划算

Daph Bay avatar
By Daph Bay
at 2019-12-05T13:08
最近去買了30張底紫去合 雖然沒紫保 但都有配寶石合 爆了26張QQ 想說484人品問題 又買4張底黑 配寶石合也全爆 這樣噴了4000多QQ 寶石算一算才2萬顆 想要寶石真的一定要有保存卷嗎 還是一定要買包卡划算QQ 看到一堆本隊的雷公黑 都拉不到嗚嗚 - ...

OWL 2020 隊伍不精確總移動里程數

Dorothy avatar
By Dorothy
at 2019-12-04T23:16
看到明年OWL要全球開戰,好奇心起來想要看看哪隊最爽哪隊最累,於是用Excel跟Great Circle Mapper手工算了一下距離。 http://i.imgur.com/y4XFSJT.jpg 結論:東區不是很爽就是很累,歐洲隊伍會飛機坐到升天,亞洲四隊因為有特別安排反而沒想像中移動那麼多。 不過 ...

馬爾杜克道具店

Dorothy avatar
By Dorothy
at 2019-12-04T22:18
https://www.youtube.com/watch?v=zXPa32fVrKo https://i.imgur.com/5k7XUpi.png 一個over kill的概念,如果一般的道具店是差不多斬20點, 馬爾杜克道具店的斬殺的上限應該是你的牌堆總數量+回合上限時間 前置作業是用索羅門抽個0費馬爾 ...

這次修正控球

Hamiltion avatar
By Hamiltion
at 2019-12-04T19:41
這次控球修正到底是在搞啥? 有些卡有上修;有些卡沒動;有些卡還下修 稍微花了點時間整理,拜託辣椒看一下, 或是有大戶跟小幫手回報一下,非常感恩 (上修紅色;沒動或持平不上色;下修綠色) 中信兄弟 萊福力 BB/9 2.5,這次沒動維持82 (對比羅里奇 整個問號?) 紐維拉 BB/9 2.1,這次沒動維持 ...

19道奇貝林傑

Puput avatar
By Puput
at 2019-12-04T14:39
新卡已經丟大廳囉,希望有需要的人趕快搶吧~ https://i.imgur.com/5R3C3w1.jpg - ...