一、實驗目的
- 練習 Java 多線程編程技術。
- 練習實現網絡併發服務的編程技術。
- 學習如何實現多線程間的相互同步和相互協作。
- 理解什麼是線程安全。
二. 設計要求
6. 功能概述:實現一個支持併發服務的網絡運算服務器程序。該服務器能夠同時接收來自
於多個客戶端的運算請求,然後根據運算類型和請求參數完成實際的運算,最後把運算結果返
回給客戶端。
7. 具體要求:
(1)至少支持加、減、乘、除四種基本運算。
(2)服務器端能夠分別記錄已經成功處理的不同運算類型請求的個數。
(2)客戶端與服務器端之間基於 UDP 協議進行通信。
(3)應用層協議自行設計。例如請求數據包、響應數據包可以採用如下格式:
(4)服務器端程序必須採用如下結構:
設計思想:
1.先解決通過UDP協議時接收來自客戶端的運算請求,然後根據運算類型和請求參數完成實際的運算,最後把運算結果返回給客戶端的問題:
設計請求數據包、響應數據包格式如下:
2.實現通過阻塞隊列夠和多線程使得服務端能同時接收來自於多個客戶端的運算請求,然後根據運算類型和請求參數完成實際的運算,最後把運算結果返回給客戶端的要求:
程序結構如下:
首先在主線程創建兩個裝DatagramPacket的阻塞隊列分別作爲輸入輸出隊列,然後起兩個線程(線程通過自己實現的繼承了Thread的ServerThread類創建)並把這兩個隊列傳給他們。主線程通過循環不斷將接收到的數據包放入輸入隊列;線程中實現了從傳入的輸入隊列取數據包並處理然後將結果打包放入輸出隊列中;最後主線程通過從輸出隊列取出數據包直接發送。
當輸入隊列爲空時工作線程都會阻塞等待,直到新的數據包被放入;當輸出隊列滿時工作線程也會阻塞等待,直到輸出隊列中又數據包被取出。
源碼
服務器端:
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.LinkedList;
import java.util.Scanner;
import java.util.concurrent.LinkedBlockingQueue;
import java.net.*;
import java.io.*;
public class Server2{
public static void main(String args[]) throws InterruptedException{
DatagramSocket aSocket = null;
int serverPort = 6789;
LinkedBlockingQueue<DatagramPacket> lbq1 = new LinkedBlockingQueue<DatagramPacket>();
LinkedBlockingQueue<DatagramPacket> lbq2 = new LinkedBlockingQueue<DatagramPacket>();
try{
aSocket = new DatagramSocket(serverPort);
byte[] buffer = new byte[1000];
new ServerThread(lbq1, lbq2).start();
new ServerThread(lbq1, lbq2).start();
while(true){
DatagramPacket request = new DatagramPacket(buffer, buffer.length);
aSocket.receive(request);
lbq1.put(request);
aSocket.send(lbq2.take());
System.out.println("處理加法請求個數:"+ServerThread.getSum1());
System.out.println("處理減法請求個數:"+ServerThread.getSum2());
System.out.println("處理乘法請求個數:"+ServerThread.getSum3());
System.out.println("處理除法請求個數:"+ServerThread.getSum4());
}
} catch (SocketException e){
System.out.println("Socket: " + e.getMessage());
} catch (IOException e) {
System.out.println("IO: " + e.getMessage());
} finally {
if (aSocket != null) aSocket.close();
}
}
}
ServerThread類實現:
import java.net.DatagramPacket;
import java.util.concurrent.LinkedBlockingQueue;
public class ServerThread extends Thread{
LinkedBlockingQueue<DatagramPacket> lbq1 = new LinkedBlockingQueue<DatagramPacket>();
LinkedBlockingQueue<DatagramPacket> lbq2 = new LinkedBlockingQueue<DatagramPacket>();
DatagramPacket request = null;
static int sum1=0,sum2=0,sum3=0,sum4=0;
public ServerThread(LinkedBlockingQueue<DatagramPacket> lbq1, LinkedBlockingQueue<DatagramPacket> lbq2) {
super();
this.lbq1 = lbq1;
this.lbq2 = lbq2;
}
public void run() {
while (true) {
try {
request = lbq1.take();
} catch (InterruptedException e) {
e.printStackTrace();
}
Integer sum = null;
String string = new String(request.getData(), 0, request.getLength());
String str[] = string.split(" ");
/* for (int i = 0; i < str.length; i++) {
System.out.println(str[1]);
}*/
if (str[1].equals("+")) {
sum = Integer.parseInt(str[0]) + Integer.parseInt(str[2]);
sum1++;
}
else if (str[1].equals("-")) {
sum = Integer.parseInt(str[0]) - Integer.parseInt(str[2]);
sum2++;
}
else if (str[1].equals("*")) {
sum = Integer.parseInt(str[0]) * Integer.parseInt(str[2]);
sum3++;
}
else if (str[1].equals("/")) {
sum = Integer.parseInt(str[0]) / Integer.parseInt(str[2]);
sum4++;
}
// System.out.println(sum);
byte[] m = sum.toString().getBytes();
DatagramPacket reply = new DatagramPacket(m, m.length, request.getAddress(), request.getPort());
try {
lbq2.put(reply);
} catch (InterruptedException e) {
// TODO 自動生成的 catch 塊
e.printStackTrace();
}
}
}
public static int getSum1() {
return sum1;
}
public static int getSum2() {
return sum2;
}
public static int getSum3() {
return sum3;
}
public static int getSum4() {
return sum4;
}
}
客戶端:
import java.net.*;
import java.util.Scanner;
import java.io.*;
public class CLIENT{
public static void main(String args[]){
// args give message contents and server hostname
DatagramSocket aSocket = null;
Scanner input = new Scanner(System.in);
try {
while(true) {
aSocket = new DatagramSocket();
//byte[] m = args[0].getBytes();
String str = input.nextLine();
byte[] m = str.getBytes();
InetAddress aHost = InetAddress.getByName("127.0.0.1");
int serverPort = 6789;
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(str+"= " + new String(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();
}
}
}