0
点赞
收藏
分享

微信扫一扫

【JavaEE】UDP数据报套接字—实现回显服务器(网络编程)

本篇文章将带你了解什么是网络编程?

网络编程,指网络上的主机,通过不同的进程,以编程的方式实现网络通信(或称为网络数据传输)。

网络编程中需要有发送端,接收端,也就是服务器和客户端进行数据交互。


目录

文章目录

一、Socket套接字

1.1 概念

1.2 分类

1.3 TCP和UDP的特点

二、DatagramSocket API

三、DatagramPacket API

四、基于UDP Socket实现回显服务器

4.1 服务器端

4.1.1 创建Socket对象

 4.1.2 绑定端口号

4.1.3 启动服务器主逻辑

4.2 客户端

 五、Socket文件怎么是存储数据的

 六、测试udp回显服务器

 七、udp英语查询服务器


一、Socket套接字

1.1 概念

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

程序猿写网络程序,主要编写的应用层代码!!

真正要发送这个数据,需要上层协议,调用下层协议,应用层需要调用传输层。(想了解协议分层,请看【JavaEE】网络通信中的一些基本概念及协议分层_xyk:的博客-CSDN博客

传输层给应用层提供一组api,统称为socket api

1.2 分类

系统给程序猿提供了两组socket api

1.基于UDP的api(User Datagram Protocol)

2.基于TCP的api(Transmission Control Protocol)

1.3 TCP和UDP的特点

半双工:

二、DatagramSocket API

  • Socket ==> 数据报的Socket对象
  • Packet ==> 这个对象就是一个UDP数据报

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

Socket,说明这个对象是一个socket对象,相当于对应到系统中一个特殊的文件(socket文件)

socket文件并非对应到硬盘上的某个数据存储区域,而是对应到,网卡这个硬件设备

(cmd中输出ipconfig查看):

有线网卡:

 

所以想要进行网络通信,就需要有socket文件这样的对象

借助这个socket文件对象,才能间接的操作网卡(遥控器)

DatagramSocket 构造方法:

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

举例说明一下:

DatagramSocket 方法:

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

三、DatagramPacket API

DatagramPacket是UDP Socket发送和接收的数据报
DatagramPacket 构造方法:

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

DatagramPacket 方法

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

四、基于UDP Socket实现回显服务器

回显服务器(echo server)

客户端发了个请求,服务器返回一个一模一样的响应~~

三个核心工作:

  1. 读取请求并解析
  2. 根据请求求得对应响应(回显服务器 无此操作)
  3. 把响应返回给客户端

4.1 服务器端

4.1.1 创建Socket对象

 4.1.2 绑定端口号

4.1.3 启动服务器主逻辑

需要先构造一个空饭盒并接收:

此时,如果还没有客户端发来的数据,怎么办?

  • receive阻塞等待就行了,直到客户端发来真的数据请求
  • 有点类似于阻塞队列~~

为了方便处理,把数据报转成String

根据请求计算响应(此处省略这个步骤)

 

 把响应结果写回客户端,并打印日志

完整代码:

package network;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;

/**
 * @author xyk的电脑
 * @version 1.0
 * @description: TODO
 * @date 2023/4/6 16:48
 */
public class UdpEchoServer {
    //需要先定义一个 socket 对象
    //通过网络通信,必须要使用 socket对象
    private DatagramSocket socket = null;

    // 绑定一个端口, 不一定能成功!!
    // 如果某个端口已经被别的进程占用了, 此时这里的绑定操作就会出错.
    // 同一个主机上, 一个端口, 同一时刻, 只能被一个进程绑定.
    public UdpEchoServer(int port) throws SocketException {
        socket = new DatagramSocket(port);
    }

    //启动服务器的主逻辑
    public void start() throws IOException {
        System.out.println("服务器启动!");
        while (true){
            // 每次循环, 要做三件事情:
            // 1. 读取请求并解析
            //    构造空饭盒
            DatagramPacket requestPacket = new DatagramPacket(new byte[4096],4096);
            //    食堂大妈给饭盒里面盛饭(饭从网卡上来的)
            socket.receive(requestPacket);
            //    为了方便处理这个请求, 把数据包转成 String
            String request = new String(requestPacket.getData(),0,
                    requestPacket.getLength());
            // 2. 根据请求计算响应(此处省略这个步骤)
            String response = process(request);
            // 3. 把响应结果写回到客户端
            //    根据 response 字符串, 构造一个 DatagramPacket .
            //    和请求 packet 不同, 此处构造响应的时候, 需要指定这个包要发给谁.
            DatagramPacket responsePacket = new DatagramPacket(response.getBytes(),
                    // requestPacket 是从客户端这里收来的. getSocketAddress 就会得到客户端的 ip 和 端口
                    response.getBytes().length,requestPacket.getSocketAddress());
            socket.send(responsePacket);
            System.out.printf("[%s:%d] req: %s, resp: %s\n",
                    requestPacket.getAddress().toString(),requestPacket.getPort(),
                    request,response);
        }
    }

    public String process(String request) {
        return request;
    }

    public static void main(String[] args) throws IOException {
        UdpEchoServer udpEchoServer = new UdpEchoServer(9090);
        udpEchoServer.start();
    }
}

4.2 客户端

4.2.1 客户端启动,需要知道服务器在哪里!!

4.2.2 用户输入内容

 4.2.3 把字符串构造成 UDP packet, 并进行发送.

4.2.4 把响应数据转换成 String 显示出来.


完整代码:

package network;

import java.io.IOException;
import java.net.*;
import java.util.Scanner;

/**
 * @author xyk的电脑
 * @version 1.0
 * @description: TODO
 * @date 2023/4/6 16:48
 */
public class UdpEchoClient {
    private DatagramSocket socket = null;
    private String serverIp;
    private int serverPort;

    // 客户端启动, 需要知道服务器在哪里!!
    public UdpEchoClient(String serverIp,int serverPort) throws SocketException {
        // 对于客户端来说, 不需要显示关联端口.
        // 不代表没有端口, 而是系统自动分配了个空闲的端口.
        socket = new DatagramSocket();
        this.serverIp = serverIp;
        this.serverPort = serverPort;
    }

    public void start() throws IOException {
        Scanner scanner = new Scanner(System.in);
        while (true){
            // 1. 先从控制台, 读取一个字符串过来
            //    先打印一个提示符, 提示用户要输入内容
            System.out.print("-> ");
            String request = scanner.next();
            // 2. 把字符串构造成 UDP packet, 并进行发送.
            DatagramPacket requestPacket = new DatagramPacket(request.getBytes(),
                    request.getBytes().length,
                    InetAddress.getByName(serverIp),serverPort);
            socket.send(requestPacket);
            // 3. 客户端尝试读取服务器返回的响应
            DatagramPacket responsePacket = new DatagramPacket(new byte[4096],4096);
            socket.receive(responsePacket);
            // 4. 把响应数据转换成 String 显示出来.
            String response = new String(responsePacket.getData(),
                    0, responsePacket.getLength());
            System.out.printf("req: %s, resp: %s\n", request, response);
        }
    }

    public static void main(String[] args) throws IOException {
        UdpEchoClient udpEchoClient = new UdpEchoClient("127.0.0.1",9090);
        udpEchoClient.start();
    }

}

小结:

五、Socket文件怎么是存储数据的

 六、测试udp回显服务器

 

 七、udp英语查询服务器

package network;

import java.io.IOException;
import java.net.SocketException;
import java.util.HashMap;
import java.util.Map;

/**
 * @author xyk的电脑
 * @version 1.0
 * @description: TODO
 * @date 2023/4/9 21:39
 */
public class UdpDictServer extends UdpEchoServer {
    private Map<String,String> dict = new HashMap<>();

    public UdpDictServer(int port) throws SocketException {
        super(port);

        dict.put("dog","小狗");
        dict.put("cat","小猫");
        dict.put("fuck","卧槽");
    }

    @Override
    public String process(String request){
        return dict.getOrDefault(request,"该单词没有查到! ");
    }

    public static void main(String[] args) throws IOException {
        UdpDictServer udpDictServer = new UdpDictServer(9090);
        udpDictServer.start();
    }
}

 

举报

相关推荐

0 条评论