计算机网络 --- 网络编程

x33g5p2x  于2022-05-05 转载在 其他  
字(17.8k)|赞(0)|评价(0)|浏览(1062)

1. 网络编程

1.1 什么是网络编程

网络编程 : 指网络上的主机,通过不同的进程,以编程的方式实现网络通信.
简单来说: 网络编程就是通过代码的方式来控制不同进程间能够进行数据交互.

1.2 发送端和接收端

发送端:数据的发送方进程,称为发送端。发送端主机即网络通信中的源主机。
接收端:数据的接收方进程,称为接收端。接收端主机即网络通信中的目的主机。
收发端发送端和接收端两端,也简称为收发端

1.3 请求和响应

请求(Request) : 客户端给服务端发送的数据
响应(Response) : 服务端给客户端返回的数据

1.4 客户端和服务端

客户端 : 主动发送请求的一方
服务端 : 被动接受请求的一方

客户端和服务端的交互方式:

  1. 一问一答,客户端发送一个请求,服务端给一个响应
  2. 一问多答,客户端发送一个请求,服务端给多个响应
  3. 多问一答,客户端发送多个请求,服务端给一个响应
  4. 多问多答,客户端发送多个请求,服务器端多个响应

2. Socket 套接字

Socket套接字,是由系统提供用于网络通信的技术,是基于TCP/IP协议的网络通信的基本操作单元。基于Socket套接字的网络程序开发就是网络编程.

2.1 分类

流套接字 : 使用传输层 TCP 协议

TCP协议,(Transmission Control Protocol)
TCP的特点:

  1. 有连接
  2. 可靠传输
  3. 面向字节流
  4. 有接收缓冲区,也有发送缓冲区
  5. 大小不限
  6. 全双工

数据报接字 : 使用传输层 UDP 协议

UDP协议,(User Datagram Protocl)
UDP的特点:

  1. 无连接
  2. 不可靠传输
  3. 面向数据报
  4. 有接收缓冲区,无发送缓冲区
  5. 大小受限: 一次最多传输64k
  6. 全双工

3. UDP数据报套接字编程

3.1 DatagramSocket API

DatagramSocket 是UDP Socket, 用于发送和接收UDP数据报.

构造方法

方法签名方法说明
DatagramSocket()创建一个UDP数据报套接字的Socket,绑定到本机任意一个随机端口(一般用于客户端)
DatagramSocket(int port)创建一个UDP数据报套接字的Socket,绑定到本机指定的端口(一般用于服务端)

方法

方法签名方法说明
void receive(DatagramPacket p)从此套接字接收数据报(如果没有接收到数据报,该方法会阻塞等待)
void send(DatagramPacket p)从此套接字发送数据报包(不会阻塞等待,直接发送)
void close()关闭此数据报套接字

3.2 DatagramPacket API

DatagramPacket是UDP Socket发送和接收的数据报.

构造方法

方法签名方法说明
DatagramPacket(byte[] buf, int length)构造一个DatagramPacket以用来接收数据报,接收的数据保存在字节数组(第一个参数buf)中,接收指定长度(第二个参数length)
DatagramPacket(byte[] buf, int offset, int length,SocketAddress address)构造一个DatagramPacket以用来发送数据报,发送的数据为字节数组(第一个参数buf)中,从0到指定长度(第二个参数length)。address指定目的主机的IP和端口号

方法

方法签名方法说明
InetAddress getAddress()从接收的数据报中,获取发送端主机IP地址;或从发送的数据报中,获取接收端主机IP地址
int getPort()从接收的数据报中,获取发送端主机的端口号;或从发送的数据报中,获取接收端主机端口号
byte[] getData()获取数据报中的数据

注: 构造UDP发送的数据报时,需要传入 SocketAddress ,该对象可以使用 InetSocketAddress 来创建。
InetSocketAddress的构造方法

方法签名方法说明
InetSocketAddress(InetAddress addr, int port)创建一个Socket地址,包含IP地址和端口号

3.3 基本使用方法:

服务端:

  1. 创建一个 DatagramSocket 对象,创建的同时关联一个端口号
  2. 读取请求 并解析
  3. 根据请求计算响应
  4. 把响应写回到客户端
  5. 打印日志

客户端

  1. 创建一个 DatagramSocket 对象,创建的同时指定服务器的ip和端口号
  2. 读取输入的数据
  3. 构造请求 并 发送给服务器
  4. 从服务器读取响应
  5. 把数据显示给用户

使用示例: 一发一收

代码示例: UdpServer

  1. import java.io.IOException;
  2. import java.net.DatagramPacket;
  3. import java.net.DatagramSocket;
  4. import java.net.SocketException;
  5. public class UdpEchoServer {
  6. private DatagramSocket socket = null;
  7. public UdpEchoServer(int port) throws SocketException {
  8. this.socket = new DatagramSocket(port);
  9. }
  10. public void start() throws IOException {
  11. System.out.println("服务器启动!");
  12. while (true) {
  13. // 1. 读取请求 并 解析
  14. DatagramPacket requestPacket = new DatagramPacket(new byte[4096],4096);
  15. socket.receive(requestPacket);
  16. String request = new String(requestPacket.getData(),0, requestPacket.getLength());
  17. // 2. 根据请求计算响应
  18. String response = process(request);
  19. // 3. 把响应写回到客户端
  20. DatagramPacket responsePacket = new DatagramPacket(response.getBytes(),response.getBytes().length,
  21. requestPacket.getSocketAddress());
  22. socket.send(responsePacket);
  23. // 4. 打印日志
  24. String log = String.format("[%s:%d] req: %s; resp: %s",requestPacket.getAddress().toString(),
  25. requestPacket.getPort(),request,response);
  26. System.out.println(log);
  27. }
  28. }
  29. private String process(String request) {
  30. return request;
  31. }
  32. public static void main(String[] args) throws IOException {
  33. UdpEchoServer server = new UdpEchoServer(9090);
  34. server.start();
  35. }
  36. }

代码示例: UdpClient

  1. import java.io.IOException;
  2. import java.net.*;
  3. import java.util.Scanner;
  4. public class UdpEchoClient {
  5. private DatagramSocket socket = null;
  6. private String serverIp;
  7. private int serverPort;
  8. public UdpEchoClient(String serverIp,int serverPort) throws SocketException {
  9. this.serverIp = serverIp;
  10. this.serverPort = serverPort;
  11. this.socket = new DatagramSocket();
  12. }
  13. public void start() throws IOException {
  14. while (true) {
  15. // 1. 读取输入数据
  16. System.out.print("->");
  17. Scanner sc = new Scanner(System.in);
  18. String request = sc.next();
  19. if(request.equals("exit")){
  20. System.out.println("exit");
  21. break;
  22. }
  23. // 2. 构造请求 并 发送给服务器
  24. DatagramPacket requestPacket = new DatagramPacket(request.getBytes(),0,request.getBytes().length,
  25. InetAddress.getByName(serverIp),serverPort);
  26. socket.send(requestPacket);
  27. // 3. 读取服务器的响应 并 解析
  28. DatagramPacket responsePacket = new DatagramPacket(new byte[4096],4096);
  29. socket.receive(responsePacket);
  30. String response = new String(responsePacket.getData(),0, responsePacket.getLength());
  31. // 4.显式给用户
  32. String log = String.format("req: %s; resp: %s",request,response);
  33. System.out.println(log);
  34. }
  35. }
  36. public static void main(String[] args) throws IOException {
  37. UdpEchoClient client = new UdpEchoClient("127.0.0.1",9090);
  38. client.start();
  39. }
  40. }

运行结果:

使用示例: 翻译程序

客户端 输入需要查找的英文的请求
客户端 返回对应的英文翻译的响应
代码示例: UdpServer

  1. package Translation;
  2. import java.io.IOException;
  3. import java.net.DatagramPacket;
  4. import java.net.DatagramSocket;
  5. import java.net.SocketException;
  6. import java.util.HashMap;
  7. import java.util.Map;
  8. public class UdpTranslateServer {
  9. private DatagramSocket socket = null;
  10. private Map<String,String> map = new HashMap<>();
  11. public UdpTranslateServer(int port) throws SocketException {
  12. this.socket = new DatagramSocket(port);
  13. map.put("translate","翻译");
  14. map.put("china","中国");
  15. map.put("hello","你好");
  16. }
  17. public void start() throws IOException {
  18. System.out.println("服务器启动!");
  19. while (true) {
  20. // 1. 读取请求并解析
  21. DatagramPacket requestPacket = new DatagramPacket(new byte[4096],4096);
  22. socket.receive(requestPacket);
  23. String request = new String(requestPacket.getData(),0, requestPacket.getLength());
  24. // 2. 根据请求计算响应
  25. String response = process(request);
  26. // 3. 把响应写回给客户端
  27. DatagramPacket responsePacket = new DatagramPacket(response.getBytes(),response.getBytes().length,
  28. requestPacket.getSocketAddress());
  29. socket.send(responsePacket);
  30. // 4. 打印日志
  31. String log = String.format("[%s:%d] req: %s; resp: %s",requestPacket.getAddress().toString(),
  32. requestPacket.getPort(),request,response);
  33. System.out.println(log);
  34. }
  35. }
  36. private String process(String request) {
  37. return map.getOrDefault(request,"查无此单词");
  38. }
  39. public static void main(String[] args) throws IOException {
  40. UdpTranslateServer server = new UdpTranslateServer(9090);
  41. server.start();
  42. }
  43. }

代码示例: UDPClient

  1. package Translation;
  2. import java.io.IOException;
  3. import java.net.*;
  4. import java.util.Scanner;
  5. public class UdpTranslateClient {
  6. private DatagramSocket socket = null;
  7. private String serverIp;
  8. private int serverPort;
  9. public UdpTranslateClient (String serverIp,int serverPort) throws SocketException {
  10. this.serverIp = serverIp;
  11. this.serverPort = serverPort;
  12. socket = new DatagramSocket();
  13. }
  14. public void start() throws IOException {
  15. while (true) {
  16. System.out.print("->");
  17. Scanner sc = new Scanner(System.in);
  18. // 1. 根据用户的输入 构造请求
  19. String request = sc.next();
  20. if(request.equals("exit")){
  21. System.out.println("exit!");
  22. return;
  23. }
  24. // 2. 发送请求给服务器
  25. DatagramPacket requestPacket = new DatagramPacket(request.getBytes(),request.getBytes().length,
  26. InetAddress.getByName(serverIp),serverPort);
  27. socket.send(requestPacket);
  28. // 3. 读取服务器的响应
  29. DatagramPacket responsePacket = new DatagramPacket(new byte[4096],4096);
  30. socket.receive(responsePacket);
  31. String response = new String(responsePacket.getData(),0, responsePacket.getLength());
  32. System.out.println(response);
  33. // 4. 解析响应并显式
  34. String log = String.format("req: %s; resp: %s",request,response);
  35. System.out.println(log);
  36. }
  37. }
  38. public static void main(String[] args) throws IOException {
  39. UdpTranslateClient client = new UdpTranslateClient("127.0.0.1",9090);
  40. client.start();
  41. }
  42. }

运行结果:

4. TCP流套接字编程

4.1 ServerSocket API

构造方法

方法签名方法说明
ServerSocket(int port)创建一个服务端流套接字Socket,并绑定到指定端口

方法

方法签名方法说明
Socket accept()开始监听指定端口(创建时绑定的端口),有客户端连接后,返回一个服务端Socket对象,并基于该Socket建立与客户端的连接,否则阻塞等待
void close()关闭此套接字

4.2 Socket API

构造方法

方法签名方法说明
Socket(String host, int port)创建一个客户端流套接字Socket,并与对应IP的主机上,对应端口的进程建立连接

方法

方法签名方法说明
InetAddress getInetAddress()返回套接字所连接的地址
InputStream getInputStream()返回此套接字的输入流
OutputStream getOutputStream()返回此套接字的输出流

4.3 基本使用方法

服务器

  1. 创建ServerSocket 关联上一个端口号
  • 调用 ServerSocketaccept 方法

  • 目的是 建立连接

  • 会返回一个 Socket 实例,称为 clientSocket

  • 使用 clientSocketgetInputStreamgetOutputStream 得到字节流对象,进行读写和写入

  • 读取请求 并 解析

  • 根据请求计算响应

  • 把响应写回客户端

  • 打印日志

  • 当客户端断开连接之后,服务器就应该要及时的关闭 clientSocket. (防止出现文件泄露的情况)

客户端

  1. 创建一个 Socket 对象.创建的同时指定服务器的 ip端口
  • 客户端就可以通过 Socket 对象的 getInputStreamgetOutputStream 来和服务器进行通信

  • 从键盘上,读取用户输入的内容

  • 把这个读取的内容构造成请求,发送给服务端

  • 从服务器读取响应并解析

  • 把结构显示到界面上

使用示例1: 一发一收

这里的是普通版本 不能处理多个客户端

代码示例: TCPClient

  1. package TCP;
  2. import java.io.IOException;
  3. import java.io.InputStream;
  4. import java.io.OutputStream;
  5. import java.io.PrintWriter;
  6. import java.net.Socket;
  7. import java.util.Scanner;
  8. public class TcpEchoClient {
  9. private Socket socket = null;
  10. private String serverIp;
  11. private int serverPort;
  12. public TcpEchoClient(String serverIp,int serverPort) throws IOException {
  13. this.serverIp = serverIp;
  14. this.serverPort = serverPort;
  15. // 让 socket 创建的同时,就和服务器尝试建立连接
  16. this.socket = new Socket(serverIp,serverPort);
  17. }
  18. public void start() {
  19. Scanner scanner = new Scanner(System.in);
  20. try(InputStream inputStream = socket.getInputStream();
  21. OutputStream outputStream = socket.getOutputStream()){
  22. while (true) {
  23. // 1. 从键盘上,读取用户输入的内容
  24. System.out.print("->");
  25. String request = scanner.next();
  26. if (request.equals("exit")){
  27. break;
  28. }
  29. // 2. 把这个读取的内容构造成请求,发送给服务器
  30. PrintWriter printWriter = new PrintWriter(outputStream);
  31. printWriter.println(request);
  32. printWriter.flush();
  33. // 3. 从服务器读取响应并解析
  34. Scanner respScanner = new Scanner(inputStream);
  35. String response = respScanner.next();
  36. // 4. 把结果显示到界面上
  37. String log = String.format("req: %s; resp: %s",request,response);
  38. System.out.println(log);
  39. }
  40. } catch (IOException e) {
  41. e.printStackTrace();
  42. }
  43. }
  44. public static void main(String[] args) throws IOException {
  45. TcpEchoClient client = new TcpEchoClient("127.0.0.1",9090);
  46. client.start();
  47. }
  48. }

代码示例: TCPServer

  1. package TCP;
  2. import java.io.IOException;
  3. import java.io.InputStream;
  4. import java.io.OutputStream;
  5. import java.io.PrintWriter;
  6. import java.net.ServerSocket;
  7. import java.net.Socket;
  8. import java.util.Scanner;
  9. public class TcpEchoServer {
  10. private ServerSocket listenSocket = null;
  11. public TcpEchoServer(int port) throws IOException {
  12. listenSocket = new ServerSocket(port);
  13. }
  14. public void start() throws IOException {
  15. System.out.println("服务器启动!");
  16. while (true) {
  17. // 1. 建立连接
  18. Socket clientSocket = listenSocket.accept(); // 没有客户端来就会 阻塞等待
  19. processConnection(clientSocket);
  20. }
  21. }
  22. private void processConnection(Socket clientSocket) throws IOException {
  23. String log = String.format("[%s:%d] 客户端上线!",
  24. clientSocket.getInetAddress().toString(),clientSocket.getPort());
  25. System.out.println(log);
  26. try(InputStream inputStream = clientSocket.getInputStream();
  27. OutputStream outputStream = clientSocket.getOutputStream()) {
  28. while (true) {
  29. // 1. 读取请求并解析
  30. Scanner scanner = new Scanner(inputStream);
  31. if(!scanner.hasNext()){
  32. log = String.format("[%s:%d] 客户端下线",clientSocket.getInetAddress().toString(),clientSocket.getPort());
  33. System.out.println(log);
  34. break;
  35. }
  36. String request = scanner.next();
  37. // 2. 根据请求计算响应
  38. String response = process(request);
  39. // 3. 把响应写回给客户端
  40. PrintWriter writer = new PrintWriter(outputStream);
  41. writer.println(response);
  42. writer.flush();
  43. log = String.format("[%s:%d] req: %s; resp: %s",clientSocket.getInetAddress().toString(),
  44. clientSocket.getPort(),request,response);
  45. System.out.println(log);
  46. }
  47. } catch (IOException e) {
  48. e.printStackTrace();
  49. } finally {
  50. clientSocket.close();
  51. }
  52. }
  53. private String process(String request) {
  54. return request;
  55. }
  56. public static void main(String[] args) throws IOException {
  57. TcpEchoServer server = new TcpEchoServer(9090);
  58. server.start();
  59. }
  60. }

使用示例2: 多个客户端发 一个服务器收

多线程版本,能处理多个客户端,但是需要频繁的创建销毁线程
代码示例 TCPServer (客户端一致)

  1. package TCPThread;
  2. import java.io.IOException;
  3. import java.io.InputStream;
  4. import java.io.OutputStream;
  5. import java.io.PrintWriter;
  6. import java.net.ServerSocket;
  7. import java.net.Socket;
  8. import java.util.Scanner;
  9. public class TcpThreadEchoServer {
  10. private ServerSocket listenSocket = null;
  11. public TcpThreadEchoServer(int port) throws IOException {
  12. listenSocket = new ServerSocket(port);
  13. }
  14. public void start() throws IOException {
  15. System.out.println("服务器启动!");
  16. while (true) {
  17. Socket clientSocket = listenSocket.accept();
  18. // 创建一个线程来给这个客户提供服务
  19. Thread t = new Thread(){
  20. @Override
  21. public void run() {
  22. try {
  23. processConnection(clientSocket);
  24. } catch (IOException e) {
  25. e.printStackTrace();
  26. }
  27. }
  28. };
  29. t.start();
  30. }
  31. }
  32. public void processConnection(Socket clientSocket) throws IOException {
  33. // 1. 打印日志
  34. String log = String.format("[%s,%d] 客户端上线",clientSocket.getInetAddress().toString(),clientSocket.getPort());
  35. System.out.println(log);
  36. try (InputStream inputStream = clientSocket.getInputStream();
  37. OutputStream outputStream = clientSocket.getOutputStream()){
  38. while (true) {
  39. // 1. 读取 请求 并 解析
  40. Scanner sc = new Scanner(inputStream);
  41. if(!sc.hasNext()){
  42. log = String.format("[%s,%d] 客户端下线",clientSocket.getInetAddress().toString(),clientSocket.getPort());
  43. System.out.println(log);
  44. break;
  45. }
  46. String request = sc.next();
  47. // 2. 根据请求计算响应
  48. String response = process(request);
  49. // 3. 把响应写回客户端
  50. PrintWriter printWriter = new PrintWriter(outputStream);
  51. printWriter.println(response);
  52. printWriter.flush();
  53. // 4. 打印日志
  54. log = String.format("[%s:%d] req: %s; resp: %s",clientSocket.getInetAddress().toString(),
  55. clientSocket.getPort(),request,response);
  56. System.out.println(log);
  57. }
  58. } catch (IOException e) {
  59. e.printStackTrace();
  60. } finally {
  61. clientSocket.close();
  62. }
  63. }
  64. public String process(String request){
  65. return request;
  66. }
  67. public static void main(String[] args) throws IOException {
  68. TcpThreadEchoServer server = new TcpThreadEchoServer(9090);
  69. server.start();
  70. }
  71. }

使用示例3: 多个客户端发 一个服务器收(优化版)

由于多线程版的创建销毁线程的开销太大,这里使用线程池的方法.

  1. package TCPThread;
  2. import java.io.IOException;
  3. import java.io.InputStream;
  4. import java.io.OutputStream;
  5. import java.io.PrintWriter;
  6. import java.net.ServerSocket;
  7. import java.net.Socket;
  8. import java.util.Scanner;
  9. import java.util.concurrent.ExecutorService;
  10. import java.util.concurrent.Executors;
  11. public class TcpThreadPoolEchoServer {
  12. private ServerSocket listenSocket = null;
  13. public TcpThreadPoolEchoServer(int port) throws IOException {
  14. listenSocket = new ServerSocket(port);
  15. }
  16. public void start() throws IOException {
  17. System.out.println("服务器启动");
  18. ExecutorService executorService = Executors.newCachedThreadPool();
  19. while (true) {
  20. Socket clientSocket = listenSocket.accept();
  21. // 使用线程池 来 处理当前的 processConnextion
  22. executorService.submit(()-> {
  23. try {
  24. processConnection(clientSocket);
  25. } catch (IOException e) {
  26. e.printStackTrace();
  27. }
  28. });
  29. }
  30. }
  31. public void processConnection(Socket clientSocket) throws IOException {
  32. // 1. 打印日志
  33. String log = String.format("[%s,%d] 客户端上线",clientSocket.getInetAddress().toString(),clientSocket.getPort());
  34. System.out.println(log);
  35. try (InputStream inputStream = clientSocket.getInputStream();
  36. OutputStream outputStream = clientSocket.getOutputStream()){
  37. while (true) {
  38. // 1. 读取 请求 并 解析
  39. Scanner sc = new Scanner(inputStream);
  40. if(!sc.hasNext()){
  41. log = String.format("[%s,%d] 客户端下线",clientSocket.getInetAddress().toString(),clientSocket.getPort());
  42. System.out.println(log);
  43. break;
  44. }
  45. String request = sc.next();
  46. // 2. 根据请求计算响应
  47. String response = process(request);
  48. // 3. 把响应写回客户端
  49. PrintWriter printWriter = new PrintWriter(outputStream);
  50. printWriter.println(response);
  51. printWriter.flush();
  52. // 4. 打印日志
  53. log = String.format("[%s:%d] req: %s; resp: %s",clientSocket.getInetAddress().toString(),
  54. clientSocket.getPort(),request,response);
  55. System.out.println(log);
  56. }
  57. } catch (IOException e) {
  58. e.printStackTrace();
  59. } finally {
  60. clientSocket.close();
  61. }
  62. }
  63. public String process(String request){
  64. return request;
  65. }
  66. }

运行结果

使用示例4: 翻译程序

代码示例: TCPServer (这里的客户端还是跟前面一样)

  1. package Translation;
  2. import TCPThread.TcpThreadPoolEchoServer;
  3. import java.io.IOException;
  4. import java.util.HashMap;
  5. // echo 和 translate 两个服务器之间,大多都是类似的
  6. public class TcpTranslateServer extends TcpThreadPoolEchoServer {
  7. private HashMap<String,String> map = new HashMap<>();
  8. public TcpTranslateServer(int port) throws IOException {
  9. super(port);
  10. map.put("china","中国");
  11. map.put("hello","你好");
  12. map.put("translate","翻译");
  13. }
  14. @Override
  15. public String process(String request) {
  16. return map.getOrDefault(request,"查无此单词!");
  17. }
  18. public static void main(String[] args) throws IOException {
  19. TcpTranslateServer server = new TcpTranslateServer(9090);
  20. server.start();
  21. }
  22. }

运行结果:

5. 网络计算器(自定义协议)

我们自定义协议
请求 : 字符串类型 操作数1;操作数2;运算符
响应 : 字符串类型 计算响应

服务端代码

  1. package Calculator;
  2. import java.io.IOException;
  3. import java.net.DatagramPacket;
  4. import java.net.DatagramSocket;
  5. import java.net.InetAddress;
  6. import java.net.SocketException;
  7. public class CalcServer {
  8. private DatagramSocket socket = null;
  9. public CalcServer(int port) throws SocketException {
  10. socket = new DatagramSocket(port);
  11. }
  12. public void start() throws IOException {
  13. System.out.println("服务器启动!");
  14. while (true){
  15. // 1. 读取请求并解析
  16. DatagramPacket requestPacket = new DatagramPacket(new byte[4096],4096);
  17. socket.receive(requestPacket);
  18. String request = new String(requestPacket.getData(),0,requestPacket.getLength());
  19. // 2. 跟据请求计算响应
  20. String response = process(request);
  21. // 3. 把响应写回给客户端
  22. DatagramPacket responsePacket = new DatagramPacket(response.getBytes(),response.getBytes().length,
  23. requestPacket.getSocketAddress());
  24. socket.send(responsePacket);
  25. // 4. 打印日志
  26. String log = String.format("[%s:%d] req: %s; resp: %s",requestPacket.getAddress().toString(),
  27. requestPacket.getPort(),request,response);
  28. System.out.println(log);
  29. }
  30. }
  31. private String process(String request) {
  32. // 分离
  33. String[] str = request.split(";");
  34. if(str.length != 3) return "[请求的格式出错!]";
  35. int num1 = Integer.parseInt(str[0]);
  36. int num2 = Integer.parseInt(str[1]);
  37. if(str[2].equals("+")){
  38. return num1+num2+"";
  39. }else if(str[2].equals("-")){
  40. return num1-num2+"";
  41. }else if(str[2].equals("*")){
  42. return (num1 * num2)+"";
  43. }else if(str[2].equals("/")){
  44. return (num1 / num2)+"";
  45. }
  46. return "[请求格式出错!操作符不支持!]";
  47. }
  48. public static void main(String[] args) throws IOException {
  49. CalcServer server = new CalcServer(9090);
  50. server.start();
  51. }
  52. }

客户端代码

  1. package Calculator;
  2. import java.io.IOException;
  3. import java.net.DatagramPacket;
  4. import java.net.DatagramSocket;
  5. import java.net.InetAddress;
  6. import java.net.SocketException;
  7. import java.util.Scanner;
  8. public class CalcClient {
  9. private String serverIp;
  10. private int serverPort;
  11. private DatagramSocket socket = null;
  12. public CalcClient(String serverIp,int serverPort) throws SocketException {
  13. this.serverIp = serverIp;
  14. this.serverPort = serverPort;
  15. socket = new DatagramSocket();
  16. }
  17. public void start() throws IOException {
  18. Scanner sc = new Scanner(System.in);
  19. while (true) {
  20. // 1. 用户输入的请求
  21. System.out.print("请输入操作数1: ");
  22. int num1 = sc.nextInt();
  23. System.out.print("请输入操作数2: ");
  24. int num2 = sc.nextInt();
  25. System.out.print("请输入运算符: ");
  26. String operator = sc.next();
  27. String request = num1+";"+num2+";"+operator;
  28. // 2. 构造请求,并发给服务器
  29. DatagramPacket requestPacket = new DatagramPacket(request.getBytes(),0,request.getBytes().length,
  30. InetAddress.getByName(serverIp),serverPort);
  31. socket.send(requestPacket);
  32. // 3. 从服务器中读取响应
  33. DatagramPacket responsePacket = new DatagramPacket(new byte[4096],4096);
  34. socket.receive(responsePacket);
  35. String response = new String(responsePacket.getData(),0,responsePacket.getLength());
  36. // 4. 将结果显示到屏幕上
  37. String log = String.format("req: %s; resp: %s",request,response);
  38. System.out.println(log);
  39. }
  40. }
  41. public static void main(String[] args) throws IOException {
  42. CalcClient client = new CalcClient("127.0.0.1",9090);
  43. client.start();
  44. }
  45. }

运行结果:

相关文章