【JavaEE】网络原理:UDP数据报套接字编程和TCP流套接字编程

目录

1.UDP数据报套接字编程

1.1 DatagramSocket

1.2 DatagramPacket

1.3 InetSocketAddress

1.4 基于UDP实现回响服务器

2.TCP流套接字编程

2.1 ServerSocket

2.2 Socket

2.3 基于TCP实现回响服务器


1.UDP数据报套接字编程

API 介绍

1.1 DatagramSocket

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

DatagramSocket 的构造方法:

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

DatagramSocket 的方法:

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

1.2 DatagramPacket

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发送的数据报时,需要传入SocketAddress ,该对象可以使用 InetSocketAddress 来创建。

1.3 InetSocketAddress

InetSocketAddress ( SocketAddress 的子类 )构造方法:

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

1.4 基于UDP实现回响服务器

服务器端代码:

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
import java.text.SimpleDateFormat;
import java.util.Calendar;

public class UdpEchoServer {
    private DatagramSocket socket = null;

    public UdpEchoServer(int port) throws SocketException {
        socket = new DatagramSocket(port);   //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);
            //把响应返回客户端
            // 构造一个 DatagramPacke 作为相应对象
            DatagramPacket responsePacket = new DatagramPacket(response.getBytes(),
                    0, response.getBytes().length,
                    requestPacket.getSocketAddress()); //得到 INetAddress 对象, 这个对象包含了 ip 和端口号
            socket.send(responsePacket);

            //打印日志
            Calendar calendar = Calendar.getInstance();
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            String dateTime = sdf.format(calendar.getTime());
            System.out.printf("[%s:%d time:%s] req: %s, resp: %s\n", requestPacket.getAddress().toString(),
                    requestPacket.getPort(),dateTime, request, response);
        }
    }

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

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

客户端代码

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

public class UdpEchoClient {
    private DatagramSocket socket = null;
    private String serverIp;
    private int serverPort;

    public UdpEchoClient(String serverIp, int serverPort) throws SocketException {
        this.serverIp = serverIp;
        this.serverPort = serverPort;
        socket = new DatagramSocket();
    }

    public void start() throws IOException {
        System.out.println("客户端启动!");
        Scanner scanner = new Scanner(System.in);
        while (true) {
            System.out.print("->"); //提示用户接下来要输入内容
            //1.从控制台读取要发送的数据
            if (!scanner.hasNext()) {
                break;
            }
            String request = scanner.next();
            //2.构造请求并发送
            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 response = new String(responsePacket.getData(), 0, responsePacket.getLength());
            System.out.println(response);
        }
    }

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

运行效果:

 编写⼀个英译汉的服务器. 只需要重写 process

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

//词典服务器
public class UdpDictServer extends UdpEchoServer {
    private HashMap<String, String> hashMap = new HashMap<>();

    public UdpDictServer(int port) throws SocketException {
        super(port);
        hashMap.put("cat", "小猫");
        hashMap.put("dog", "小狗");
        hashMap.put("chicken", "坤坤");
        hashMap.put("aaaaaaaaaa", "测试");
    }

    //start 方法完全从父类中继承下来即可
    //process 方法要进行重写,加入另外的业务逻辑,进行翻译
    @Override
    public String process(String request) {
        return hashMap.getOrDefault(request, "您查的单词不存在!");
    }

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

 运行效果

2.TCP流套接字编程

API 介绍

2.1 ServerSocket

ServerSocket 是创建TCP服务端Socket的API。

ServerSocket 构造方法:

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

ServerSocket 方法

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

2.2 Socket

Socket 是客户端 Socket,或服务端中接收到客户端建立连接(accept方法)的请求后,返回的服 务端Socket。

不管是客户端还是服务端Socket,都是双方建立连接以后,保存的对端信息,及用来与对方收发数据的。

Socket 构造方法:

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

Socket 方法:

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

2.3 基于TCP实现回响服务器

服务器端代码:

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class TcpEchoServer {
    private ServerSocket serverSocket = null;

    public TcpEchoServer(int port) throws IOException {
        serverSocket = new ServerSocket(port);
    }

    public void start() throws IOException {
        System.out.println("服务器启动!");
        // 创建线程池
        ExecutorService pool = Executors.newCachedThreadPool();
        while(true) {
            // 通过accept方法"接听电话",然后才能进行通信
            Socket clientSocket = serverSocket.accept();
            pool.submit(new Runnable() {
                @Override
                public void run() {
                    processConnection(clientSocket);
                }
            });
        }
    }

    //通过这个方法来处理一次连接, 连接建立过程中涉及到多次请求的响应交互
    private void processConnection(Socket clientSocket) {
        System.out.printf("[%s:%d] 客户端上线!\n",clientSocket.getInetAddress(),clientSocket.getPort());
        //循环的读取客户端的请求并返回响应
        try(InputStream inputStream = clientSocket.getInputStream();
            OutputStream outputStream = clientSocket.getOutputStream()) {
            Scanner scanner = new Scanner(inputStream);
            while(true) {
                if(!scanner.hasNext()) {
                    //读取完毕,客户端断开连接,就会产生读取完毕
                    System.out.printf("[%s:%d] 客户端下线!\n",clientSocket.getInetAddress(),clientSocket.getPort());
                    break;
                }
                //1.读取请求并解析 next要读到空白符才会结束
                String request = scanner.next();
                //2.根据请求计算响应
                String response =  process(request);
                //3.把响应返回给客户端
                //通过这种方法可以写回, 但是这种方法不方便给返回的响应中添加\n
                    //outputStream.write(response.getBytes(),0,response.getBytes().length);
                //也可以给 outputStream 套上一层,完成更方便的写入
                PrintWriter printWriter = new PrintWriter(outputStream);
                printWriter.println(response);
                printWriter.flush();

                System.out.printf("[%s:%d] req: %s, resp: %s \n",clientSocket.getInetAddress(),clientSocket.getPort(),
                        request,response);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            try {
                clientSocket.close();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    }

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

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

注意: 如果只是单个线程, 无法同时响应多个客户端. 此处给每个客户端都分配⼀个线程. 为了避免频繁创建销毁线程, 引入线程池

 

客户端代码:

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;

public class TcpEchoClient {
    private Socket socket = null;

    public TcpEchoClient(String serverIp,int serverPort) throws IOException {
        //此处可以把这里的ip和port直接传给socket对象
        //由于tcp是有连接的,因此 socket 里面就会保存这两信息
        socket = new Socket(serverIp,serverPort);
    }

    public void start() {
        System.out.println("客户端启动");

        try(InputStream inputStream = socket.getInputStream();
            OutputStream outputStream = socket.getOutputStream()) {
            Scanner scannerConsole = new Scanner(System.in);
            Scanner scannerNetWork = new Scanner(inputStream);
            PrintWriter writer = new PrintWriter(outputStream);
            while(true) {
                //这里的流程和 UDP 的客户端类似
                //1.从控制台读取输入的字符串
                System.out.print("-> ");
                if(!scannerConsole.hasNext()) {
                    break;
                }
                String request = scannerConsole.next();
                //2.把请求发给服务器, 这里需要使用println来发送, 为了让发送的请求末尾带有 \n
                writer.println(request);
                // 通过flush刷新缓冲区
                writer.flush();
                //3.从服务器读取响应
                String response = scannerNetWork.next();
                //4.把响应显示出来
                System.out.println(response);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

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

 使用PrintWrite记得手动刷新缓冲区:

 运行效果

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/360132.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Transformer 自然语言处理(三)

原文&#xff1a;Natural Language Processing with Transformers 译者&#xff1a;飞龙 协议&#xff1a;CC BY-NC-SA 4.0 第八章&#xff1a;使 transformers 在生产中更高效 在之前的章节中&#xff0c;您已经看到了 transformers 如何被微调以在各种任务上产生出色的结果。…

[机器学习]TF-IDF算法

一.TF-IDF算法概述 什么是TF-IDF&#xff1f; 词频-逆文档频率&#xff08;Term Frequency-Inverse Document Frequency&#xff0c;TF-IDF&#xff09;是一种常用于文本处理的统计方法&#xff0c;可以评估一个单词在一份文档中的重要程度。简单来说就是可以用于文档关键词的提…

k8s 1.29 一键安装脚本, 丝滑致极

博客原文 文章目录 集群配置配置清单集群规划集群网络规划 环境初始化主机配置 安装脚本需要魔法的脚本不需要魔法的脚本配置自动补全加入其余节点 验证集群 高可用版本: 高可用 k8s 1.29 一键安装脚本 集群配置 配置清单 OS&#xff1a; ubuntu 20.04kubernetes&#xff1a;…

“国潮风”带火年货消费,新中式服装在抖音电商销量同比增长超21倍

1月31日&#xff0c;抖音电商发布“抖音商城好物年货节”数据报告&#xff0c;展现龙年春节年货市场消费趋势及大众购买偏好。数据显示&#xff0c;1月13日至28日&#xff0c;货架场抖音商城日均GMV比去年年货节增长了98%&#xff0c;年货节电商直播累计时长达4385万小时&#…

Next.js如何正确处理跨域问题?

以前一直使用Vue来写前端。去年下半年接手了一个基于React Next.js的项目&#xff0c;于是顺带学习了一下Next.js。由于Next.js的特点&#xff0c;这个项目的前后端是放在一起的。一开始没什么问题&#xff0c;看了半天文档就上手了。 上周我们需要在另一个网页项目中&#x…

添加了gateway之后远程调用失败

前端提示500&#xff0c;后端提示[400 ] during [GET] to [http://userservice/user/1] 原因是这个&#xff0c;因为在请求地址写了两个参数&#xff0c;实际上只传了一个参数 解决方案&#xff1a;加上(required false)并重启所有相关服务

单元/集成测试服务

服务概述 单元/集成测试旨在证明被测软件实现其单元/架构设计规范、证明被测软件不包含非预期功能。经纬恒润测试团队拥有丰富的研发经验、严格的流程管控&#xff0c;依据ISO26262/ASPICE等开展符合要求的单元测试/集成测试工作。 在ISO 26262 - part6 部分产品开发&#xff…

最全前端 HTML 面试知识点

一、HTML 1.1 HTML 1.1.1 定义 超文本标记语言&#xff08;英语&#xff1a;HyperTextMarkupLanguage&#xff0c;简称&#xff1a;HTML&#xff09;是一种用于创建网页的标准标记语言 HTML元素是构建网站的基石 标记语言&#xff08;markup language &#xff09; 由无数个…

解读4篇混合类型文件Polyglot相关的论文

0. 引入 Polyglot文件指的是混合类型文件&#xff0c;关于混合类型文件的基础&#xff0c;请参考文末给出的第一个链接&#xff08;参考1&#xff09;。 1. Toward the Detection of Polyglot Files 1.1 主题 这篇2022年的论文&#xff0c;提出了Polyglot文件的检测方法。虽…

git操作之本地代码修改后想回退成当前最新版本

这张图很关键&#xff0c;取自https://www.cnblogs.com/cblx/p/12467083.html 我们的vscode就是workspace&#xff0c;我们提交代码需要三步&#xff0c;add&#xff0c;commit&#xff0c;push&#xff0c;其中我们想拉取代码有两种方式&#xff0c;git pull或者git fetch/cl…

QCM6125 UEFI XBL显示开机Logo不居中

QCM6125 UEFI XBL显示开机Logo在竖直方向不是居中显示,如果显示屏是正向安装到产品的话可能没有什么问题,但是如果产品的显示屏是90、180、270度旋转后安装到产品上的话显示开机Logo会有一些问题,并且大多数的平台以及产品开机Logo都是水平竖直方向都是居中显示,所以修改成…

【开源操作系统】上海道宁为您带来稳定、安全、开源和易用的操作系统——Ubuntu,为您的数字化生活保驾护航

Ubuntu是 源于非洲的一种传统价值观 意为“人性、关爱和共享” 这种价值观在 开源、稳定、安全、易用的 Ubuntu操作系统中 得到了完美的体现 除此之外&#xff0c;Ubuntu还具有 强大的安全性 它自带了诸多安全功能 如防火墙、加密文件系统等 可以有效地保护用户的隐私…

uniapp基于Android平台的校园生活服务交流论坛系统(二手,失物招领 -跑腿) 小程序hbuiderx

作为一款APP的校园论坛系统&#xff0c;面向的是大多数学者&#xff0c;软件的界面设计简洁清晰&#xff0c;用户可轻松掌握使用技巧。在调查之后&#xff0c;获得用户以下需求&#xff1a; &#xff08;1&#xff09;用户注册登录后&#xff0c;可进入系统解锁更多功能&#x…

【Java基础】之进程与线程

进程与线程 1. 线程与进程1.1 概念1.2 区别与联系 2. 线程的5种状态和切换2.1 简单介绍2.2 状态切换2.2.1 重点情况 3. 线程中常见的方法4. 线程池 1. 线程与进程 1.1 概念 进程&#xff1a;资源分配的基本单元&#xff0c;如QQ音乐 线程&#xff1a;资源调度的基本单元&…

第38期 | GPTSecurity周报

GPTSecurity是一个涵盖了前沿学术研究和实践经验分享的社区&#xff0c;集成了生成预训练Transformer&#xff08;GPT&#xff09;、人工智能生成内容&#xff08;AIGC&#xff09;以及大型语言模型&#xff08;LLM&#xff09;等安全领域应用的知识。在这里&#xff0c;您可以…

泰迪智能科技生成式人工智能(AIGC)实验室解决方案

AIGC&#xff08;Artificial Intelligence Generated Content&#xff0c;生成式人工智能&#xff09;是一种新的人工智能技术&#xff0c;指的是利用人工智能技术来生成内容。这种技术可以自动生成文本、图像、音频和视频等多种类型的内容&#xff0c;而且内容的质量较高&…

Python武器库开发-武器库篇之pdf文件暴力破解(五十二)

Python武器库开发-武器库篇之pdf文件暴力破解(五十二) PDF&#xff08;Portable Document Format&#xff0c;便携式文档格式&#xff09;是由Adobe公司开发的一种文件格式。PDF文件被广泛用于以可靠方式共享和传输电子文档。它能够保留文档的原始格式&#xff0c;包括字体、图…

基于YOLOv8的船舶目标检测系统(Python源码+Pyqt6界面+数据集)

博主简介 AI小怪兽&#xff0c;YOLO骨灰级玩家&#xff0c;1&#xff09;YOLOv5、v7、v8优化创新&#xff0c;轻松涨点和模型轻量化&#xff1b;2&#xff09;目标检测、语义分割、OCR、分类等技术孵化&#xff0c;赋能智能制造&#xff0c;工业项目落地经验丰富&#xff1b; …

KYOSAN电源维修RFK150ZDTG1电源控制器BKW-100

维修范围&#xff1a;刻蚀、RIE、平行板、ICP、pecvd、射频溅射、CVD 和PVD等系统&#xff0c;工业系统中感应加热和电介质加热设备的电源&#xff0c;烘干、塑化、接、硅晶体生长和平板显示器领域应用电源&#xff0c;直流偏压和硬镀膜&#xff0c;信息技术设备(ITE)及轻工业系…

医院安全(不良)事件报告系统源码,不良事件处理的全过程管理,实现11大类不良事件类型的报告上报、流转审批、跟踪改进及统计分析功能。

医院安全&#xff08;不良&#xff09;事件报告系统源码&#xff0c;不良事件上报系统源码&#xff0c;PHP源码 医院安全&#xff08;不良&#xff09;事件报告系统提供11大类不良事件的上报、事件审核处理、时间按分析、事件跟踪与持续改进&#xff0c;事件提醒、权限控制、外…