一、实验目的
- 练习 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();
}
}
}