分佈式作業二:java多線程編程技術

題目

1. 功能概述

實現一個支持併發服務的網絡運算服務器程序。該服務器能夠同時接收來自於多個客戶端的運算請求,然後根據運算類型和請求參數完成實際的運算,最後把運算結果返
回給客戶端。

2. 具體要求

(1)至少支持加、減、乘、除四種基本運算。
(2)服務器端能夠分別記錄已經成功處理的不同運算類型請求的個數。
(2)客戶端與服務器端之間基於 UDP 協議進行通信。
(3)應用層協議自行設計。

源碼

// 服務端程序
import java.net.*;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;


class Counter {                                             //運算符數目類
    private int counter;
    public Counter() {
        counter=0;
    }
    public synchronized void increase() {
        counter++;
    }

    public int getCounter() {
        return counter;
    }
}
class ThreadCounter {                                       //線程數目類
    private int counter;
    public ThreadCounter() {
        counter=0;
    }
    public synchronized void increase() {
        counter++;
    }
    public synchronized void decrease() {
        counter--;
    }
    public synchronized boolean compare(int n){             // 比較線程數目
        return counter < n;
    }
    public void print(){
        System.out.println("當前進程數目:"+ counter);
    }

}

class PacketType{                   // 數據包類型
    private String op;              // 運算符
    private int num1;
    private int num2;
    public PacketType(String a,int b, int c) {
        op = a;
        num1 = b;
        num2 = c;
    }
    public double computer(){
        try {
            if (op.equals("+")) {
                UDPServer.operator[0].increase();
                return num1 + num2;
            }
            if (op.equals("-")) {
                UDPServer.operator[1].increase();
                return num1 - num2;
            }
            if (op.equals("*")) {
                UDPServer.operator[2].increase();
                return num1 * num2;
            }
            if (op.equals("/")) {
                UDPServer.operator[3].increase();
                return (double) num1 / num2;
            }
        }catch (Exception e){
            e.printStackTrace();
            return -1;
        }
        System.out.println("Error Input");
        return -1;
    }
}

class WorkThread implements Runnable {          //工作線程
    public static byte[] double2Bytes(double d) {          // 將浮點數類型轉換爲字節數組
        long value = Double.doubleToRawLongBits(d);
        byte[] byteRet = new byte[8];
        for (int i = 0; i < 8; i++) {
            byteRet[i] = (byte) ((value >> 8 * i) & 0xff);
        }
        return byteRet;
    }
    public void run() {
        try {
            while (true) {
                DatagramPacket m = UDPServer.InputQueue.take();
                String t = new String(m.getData()).substring(0,m.getLength());
                String[] s = t.split("t");
                String op = s[0];
                int num1 = Integer.parseInt(s[1]);
                int num2 = Integer.parseInt(s[2]);
                PacketType n = new PacketType(op, num1, num2);
                double ans = n.computer();
                byte[] ans_byte = double2Bytes(ans);
                System.out.println("此次運算結果: " + ans);
                DatagramPacket res = new DatagramPacket(ans_byte, ans_byte.length,m.getAddress(),m.getPort());
                UDPServer.OutputQueue.put(res);
            }
        } catch (Exception e) {
           e.printStackTrace();
        }finally {
            UDPServer.ThreadNumber.decrease();
        }

    }
}
class SendThread implements Runnable {                      //發送線程

    public void run() {
        while(true) {
            try {
                DatagramPacket m = UDPServer.OutputQueue.take();
                UDPServer.bSocket.send(m);
                // 打印當前接受的運算符數目

                int [] num = new int[4];
                for (int i = 0; i < 4; i++) {
                    num[i] = UDPServer.operator[i].getCounter();
                }
                UDPServer.ThreadNumber.print();
                System.out.println("運算符數目如下");
                System.out.println("+:"+num[0]);
                System.out.println("-:"+num[1]);
                System.out.println("*:"+num[2]);
                System.out.println("/:"+num[3]);
            } catch (Exception e) {
               e.printStackTrace();
            }
        }
    }
}

public class UDPServer{
    // 全局變量的聲明以及定義
    public static Counter[] operator = new Counter[4];      // 運算符計數器
    public static ThreadCounter ThreadNumber = new ThreadCounter();

    public static int MaxThreadNumber = 2;                 // 定義最大線程數

    @SuppressWarnings("unchecked")
    public static BlockingQueue<DatagramPacket> InputQueue = new LinkedBlockingQueue();
    @SuppressWarnings("unchecked")
    public static BlockingQueue<DatagramPacket> OutputQueue = new LinkedBlockingQueue();

    public  static DatagramSocket aSocket = null;

    public  static DatagramSocket bSocket = null;
    public static void main(String args[]){
        for(int i=0;i<4;i++){
            operator[i] = new Counter();
        }

        try{
            // DatagramPacket 公用一個buffer 可能出現意想不到的bug(例如之後讀出數據時getData() 方法的坑)
            byte[] buffer = new byte[1000];
            /*
                aSocket:主線程接受報文,監聽6789端口
                bSocket: 發送線程發送報文,使用隨機端口
             */
            aSocket = new DatagramSocket(6789);
            bSocket = new DatagramSocket();
            SendThread sendthread = new SendThread();
            Thread sendt = new Thread(sendthread);                         // 發送線程開始工作
            sendt.start();
            while(true){
                //接受請求
                DatagramPacket request = new DatagramPacket(buffer, buffer.length);
                aSocket.receive(request);
                // 請求入隊
               InputQueue.put(request);

                //創建工作線程 執行運算任務
                if (ThreadNumber.compare(MaxThreadNumber)) {
                    WorkThread workthread = new WorkThread();
                    Thread workt = new Thread(workthread);
                    workt.start();
                    ThreadNumber.increase();
                }
            }
        } catch (Exception e){
            e.printStackTrace();
        }  finally {
            if (aSocket != null) aSocket.close();


        }
    }
}
// 客戶端程序
import java.net.*;
import java.io.*;

public class UDPClient{

    public static double bytes2Double(byte[] arr) {    // 字節數組轉換爲double類型
        long value = 0;
        for (int i = 0; i < 8; i++) {
            value |= ((long) (arr[i] & 0xff)) << (8 * i);
        }
        return Double.longBitsToDouble(value);
    }
    public static void main(String args[]){
        DatagramSocket aSocket = null;
        String userInput = null;
        try {
            BufferedReader stdIn = new BufferedReader(new InputStreamReader(System.in));
            aSocket = new DatagramSocket();
            InetAddress aHost = InetAddress.getByName("127.0.0.1");
            int serverPort = 6789;
            while(!(userInput=stdIn.readLine()).equals("quit")) {           // 輸入quit時退出客戶端程序
                byte[] m = userInput.getBytes();
                // 創建發送報文
                DatagramPacket request = new DatagramPacket(m, m.length, aHost, serverPort);
                aSocket.send(request);
                byte[] buffer = new byte[1000];
                // 準備接收報文
                DatagramPacket reply = new DatagramPacket(buffer, buffer.length);
                aSocket.receive(reply);
                System.out.println("Reply: " + bytes2Double(reply.getData()));
            }
        } catch (SocketException e){
            System.out.println("Socket: " + e.getMessage());
        } catch (IOException e){
            System.out.println("IO: " + e.getMessage());
        } finally {
            if(aSocket != null) aSocket.close();
        }
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章