Java中通过UDP的简单计算器
网络是主机和服务器之间的双向通信,而不是信息交换。任何服务器都设置为响应客户端请求的特定查询。根据它们提供给用户的实用程序,有许多不同类型的服务器。一些示例包括文件服务器、应用程序服务器、域服务器等。
让我们举一个例子来演示如何在客户端-服务器通信模型中处理任何客户端的请求。假设有一家 X 公司有数百名员工,每个员工都在自己的系统上工作,他们中的大多数人使用打印机打印一些报告或发票等。在每个系统上安装打印机并不是解决提供打印问题的一个非常经济的解决方案为用户提供便利。另一种方法是设置打印服务器并在该系统上安装打印机。当员工想要打印某些东西时,他或她可以向服务器发送请求,要求为他/她保留打印机。服务器收到请求后,客户端编程会根据打印机的可用性、传入请求的速率等许多因素做出决定,最后响应请求,告诉客户端打印机的状态。任何服务器的一个基本方面是它应该是特定的,而不是通用的。它不能对每个请求生成类似的响应,而是根据请求的性质、响应的客户端等进行响应。
本文是通过 UDP 实现一个简单的计算器服务器,其中客户端将数学方程发送到服务器,服务器将响应方程的答案。
首先讨论客户端编程,然后是服务器端编程。从客户端编程开始,如下所示:
A.客户端编程
对于通过 Internet 发送或接收,需要知道侦听实体的套接字地址,即侦听器的 IP 地址和端口号。通常,客户端知道或服务器中继它正在侦听的套接字地址。所以在客户端,代码部分几乎没有什么变化。
客户端不仅调用了 send() 调用,还调用了 receive() 调用。休息所有步骤保持不变。
涉及的步骤如下:
- DatagramSocket 的创建:首先,创建一个 datagramSocket 对象以将数据包传送到目的地,并在服务器发送任何数据时接收它。
- 创建DatagramPacket:在此步骤中,创建用于通过datagramSocket 发送/接收数据的数据包。
注意:创建用于发送和接收数据的数据报包的构造函数有所不同 - 调用 socket 对象的 send() 调用:这会将携带等式的请求发送到服务器进行处理。
- 在 socket 对象上调用 receive() 调用:这用于在处理我们的请求后接收服务器发送的数据。如果花费太多时间,这将冻结我们的程序,直到服务器响应或抛出错误。
示例 1
Java
// Java Program to illustrate Client Side implementation
// of Simple Calculator using UDP
// Importing required classes
import java.io.IOException;
// Importing classes fromjava.nio package as
// this package is responsible for networking
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Scanner;
// Main class
// Calc_Client_UDP
public class GFG {
// Main driver method
public static void main(String args[])
throws IOException
{
// Creating an object of Scanner class to read user
// input
Scanner sc = new Scanner(System.in);
// Step 1
// Create the socket object for carrying data
DatagramSocket ds = new DatagramSocket();
InetAddress ip = InetAddress.getLocalHost();
byte buf[] = null;
// loop while user not enters "bye"
while (true) {
System.out.print(
"Enter the equation in the format:");
System.out.println(
"'operand1 operator operand2'");
// Awaiting from entered input
String inp = sc.nextLine();
buf = new byte[65535];
// Converting the String input into the byte
// array
buf = inp.getBytes();
// Step 2
// Creating the datagramPacket for sending the
// data.
DatagramPacket DpSend = new DatagramPacket(
buf, buf.length, ip, 1234);
// Invoking the send call to actually send the
// data.
ds.send(DpSend);
// Break the loop if user enters "bye"
// using the break keyword
if (inp.equals("bye"))
break;
buf = new byte[65535];
// Creating an object of DatagramPacket class
DatagramPacket DpReceive
= new DatagramPacket(buf, buf.length);
ds.receive(DpReceive);
// Print and display command
System.out.println(
"Answer = "
+ new String(buf, 0, buf.length));
}
}
}
Java
// Java Program Illustrating Server Side Implementation
// of Simple Calculator using UDP
// Importing required classes
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.StringTokenizer;
// Main class
// Calc_Server_UDP
class GFG {
// MAin driver method
public static void main(String[] args)
throws IOException
{
// Creating a socket to listen at port 1234
DatagramSocket ds = new DatagramSocket(1234);
byte[] buf = null;
// Initializing them initially with null
DatagramPacket DpReceive = null;
DatagramPacket DpSend = null;
while (true) {
buf = new byte[65535];
// Creating a DatagramPacket to receive the data.
DpReceive = new DatagramPacket(buf, buf.length);
// Receiving the data in byte buffer.
ds.receive(DpReceive);
String inp = new String(buf, 0, buf.length);
// Using trim() method to
// remove extra spaces.
inp = inp.trim();
System.out.println("Equation Received:- "
+ inp);
// Exit the server if the client sends "bye"
if (inp.equals("bye")) {
System.out.println(
"Client sent bye.....EXITING");
// Exit from program here itself without
// checking further
break;
}
int result;
// Use StringTokenizer to break the
// equation into operand and operation
StringTokenizer st = new StringTokenizer(inp);
int oprnd1 = Integer.parseInt(st.nextToken());
String operation = st.nextToken();
int oprnd2 = Integer.parseInt(st.nextToken());
// Perform the required operation
if (operation.equals("+"))
result = oprnd1 + oprnd2;
else if (operation.equals("-"))
result = oprnd1 - oprnd2;
else if (operation.equals("*"))
result = oprnd1 * oprnd2;
else
result = oprnd1 / oprnd2;
System.out.println("Sending the result...");
String res = Integer.toString(result);
// Clearing the buffer after every message
buf = res.getBytes();
// Getting the port of client
int port = DpReceive.getPort();
DpSend = new DatagramPacket(
buf, buf.length, InetAddress.getLocalHost(),
port);
ds.send(DpSend);
}
}
}
输出:
Enter the equation in the form: 'operand operator operand'
5 * 6
Answer=30
Enter the equation in the form: 'operand operator operand'
5 + 6
Answer=11
Enter the equation in the form: 'operand operator operand'
9 / 3
Answer=3
B. 服务器端编程
由于需要套接字地址才能通过 Internet 进行通信,因此服务器必须知道客户端发送请求的地址。让我们一步一步看服务器如何处理端口号问题并响应客户端的查询。
客户端涉及的步骤如下:
- 建立套接字连接。
- 处理来自客户端的方程:在服务器端,我们同时打开 inputStream 和 outputStream。收到方程式后,我们对其进行处理并保存结果以发送回客户端。
- 创建用于发送结果的数据包:此步骤会给服务器带来问题,因为它不知道客户端的端口号。要获取端口,我们使用 DatagramPacket 类的以下方法。
公共 int getPort()
句法:
public int getPort()
Returns the port number to which the specified datagram packet is being sent to or
from which the packet is received.
Note: Lastly do remember to close the connection to avoid any memory leakage issue.
例子
Java
// Java Program Illustrating Server Side Implementation
// of Simple Calculator using UDP
// Importing required classes
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.StringTokenizer;
// Main class
// Calc_Server_UDP
class GFG {
// MAin driver method
public static void main(String[] args)
throws IOException
{
// Creating a socket to listen at port 1234
DatagramSocket ds = new DatagramSocket(1234);
byte[] buf = null;
// Initializing them initially with null
DatagramPacket DpReceive = null;
DatagramPacket DpSend = null;
while (true) {
buf = new byte[65535];
// Creating a DatagramPacket to receive the data.
DpReceive = new DatagramPacket(buf, buf.length);
// Receiving the data in byte buffer.
ds.receive(DpReceive);
String inp = new String(buf, 0, buf.length);
// Using trim() method to
// remove extra spaces.
inp = inp.trim();
System.out.println("Equation Received:- "
+ inp);
// Exit the server if the client sends "bye"
if (inp.equals("bye")) {
System.out.println(
"Client sent bye.....EXITING");
// Exit from program here itself without
// checking further
break;
}
int result;
// Use StringTokenizer to break the
// equation into operand and operation
StringTokenizer st = new StringTokenizer(inp);
int oprnd1 = Integer.parseInt(st.nextToken());
String operation = st.nextToken();
int oprnd2 = Integer.parseInt(st.nextToken());
// Perform the required operation
if (operation.equals("+"))
result = oprnd1 + oprnd2;
else if (operation.equals("-"))
result = oprnd1 - oprnd2;
else if (operation.equals("*"))
result = oprnd1 * oprnd2;
else
result = oprnd1 / oprnd2;
System.out.println("Sending the result...");
String res = Integer.toString(result);
// Clearing the buffer after every message
buf = res.getBytes();
// Getting the port of client
int port = DpReceive.getPort();
DpSend = new DatagramPacket(
buf, buf.length, InetAddress.getLocalHost(),
port);
ds.send(DpSend);
}
}
}
输出:
Equation received:-5 * 6
Sending the result...
Equation received:-5 + 6
Sending the result...
Equation received:-9 / 3
Sending the result...
Note: In order to test the above programs on the system, please make sure that you run the server program first and then the client one. Make sure you are in the client console and from there enter the equation in the format-“operand1 operator operand2” and press Enter. Answer to the requested equation will be shown in the client console only. Finally to terminate the communication, type “bye” (without quotes) and hit enter.