【JavaEE】UDP、TCP的API介绍

目录

UDP数据报套接字编程

DatagramSocket API

DatagramPacket API

回显C/S示例

TIPS

TCP

ServerSocket API

Socket API

回显C/S示例


UDP数据报套接字编程

DatagramSocket API

        socket是操作系统中的一种概念,本质上是一种特殊的文件,socket属于是把“网卡”这个设备给抽象成文件,往socket文件中写数据,就相当于通过网卡发送数据,往socket文件读数据,就相当于通过网卡接收数据,在java中使用DatagramSocket来表示系统内部的socket文件。

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

DatagramSocket构造方法:

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

DatagramSocket方法:

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

DatagramPacket API

DatagramPacket表示一个udp数据报

DatagramPacket构造方法

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

 DatagramPacket方法

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

服务器和客户端都需要创建Socket对象,但是服务器的socket一般要显示手动指定一个端口号,而客户端的socket一般不能显式指定(不显式指定,此时系统会自动分配一个随机的端口),指定的话可能会与其他客户端冲突,系统自动分配可以避免冲突。

回显C/S示例

服务端代码

package network;

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

public class UdpEchoServer {

    private DatagramSocket socket=null;
    //指定服务器socket要绑定的端口
    private static final int PORT=9090;
    public UdpEchoServer(int port) throws SocketException {
        socket=new DatagramSocket(PORT);
    }

    public void start() throws IOException {
        System.out.println("服务器启动!");

        while(true)
        {
            DatagramPacket requestPacket=new DatagramPacket(new byte[4096],4096);
            socket.receive(requestPacket);
            //当完成receive之后,数据都是以二进制的形式存储在DatagramPacket中
            //因此我们需要先将这个二进制数据转成字符
            String request=new String(requestPacket.getData(),0,requestPacket.getLength());
            String response=process(request);

            DatagramPacket responsePacket=new DatagramPacket(response.getBytes(),response.getBytes().length,requestPacket.getSocketAddress());
            socket.send(responsePacket);
            System.out.printf("[%s:%d] req=%s, resp=%s\n",requestPacket.getAddress().toString(),responsePacket.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();
    }
}

客户端代码

package network;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.util.Scanner;

public class UdpEchoClient {
    private DatagramSocket socket=null;
    private String serverIP="";
    private int serverPort=0;
    public UdpEchoClient(String ip,int port) throws SocketException {
        socket=new DatagramSocket();
        serverIP=ip;
        serverPort=port;
    }

    public void start() throws IOException {
        System.out.println("客户端启动!");
        Scanner scanner=new Scanner(System.in);
        while(true)
        {
            System.out.println("-> ");
            String request=scanner.next();
            DatagramPacket requestPacket=new DatagramPacket(request.getBytes(),request.getBytes().length, InetAddress.getByName(serverIP),serverPort);
            socket.send(requestPacket);
            DatagramPacket responsePacket=new DatagramPacket(new byte[4096],4096);
            socket.receive(responsePacket);
            String response=new String(responsePacket.getData(),0,responsePacket.getLength());
            System.out.printf("%s\n",response);
        }

    }

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

效果如下: 

TIPS

1、new byte[4096],这个对象用来承载从网卡这边读到的数据,收到数据的时候,需要搞一个内存空间来保存这个数据,DatagramPacket内部不能自行分配内存空间,因此就需要我们手动把空间创建好,交给DatagramPacket进行处理。

2、服务器一旦启动,就会立即执行到这里的receive方法,此时,如果客户端的请求可能还没来呢,这种情况也没关系,receive就会直接阻塞,就会一直阻塞到客户端把请求发过来为止。

3、完成receive之后,数据都是以二进制的形式存储到DatagramPacket中,要想把这里的数据给显示出来,还需要把这个二进制数据给转成字符串

String request = new String(requestPacket.getData(),0,requestPacket.getLength());

  • 将0,requestPacket.getLength()区间内的字节,构造成一个String

4、response.getBytes().length()不能写成 response.length(),这涉及到字符集的问题,如果这个字符串的内容都是英文字符,此时字节和字符个数是一样的,但是如果包含中文,就不一样了 ,在网络传输时,都是以字节为单位

TCP

因为tcp是面向字节流的,传输的基本单位是byte,因此不需要像udp一样需要有一个数据报类表示传输的基本单位。

ServerSocket API

ServerSocket构造方法:

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

ServerSocket方法:

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

Socket API

Socket构造方法:

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

Socket方法: 

方法说明
getPort()获取对端的端口
getInetAddress()获取对端的ip
getLocalAddress()获取本地的ip
getLocalPort()获取本地的端口
InputStream getInputStream()返回此套接字的输入流(进行read操作,就是接收)
OutputStream getOutputStream()返回此套接字的输出流(进行write操作,就是发送)

前面udp中DatagramSocket和ServerSocket没写close,是因为程序中,只有这么一个对象,生命周期是贯穿整个程序的,而在服务端accept,与客户端连接,在服务端每次有新的客户端来建立连接,都会创建一个新的clientSocket,每个socket对象会占据文件描述符表的位置,因此我们要记得释放。

回显C/S示例

服务端代码:

        这里服务端处理连接时创建新线程处理一个客户端连接,因为tcp连接服务端和客户端交互时,需要保持连接,如果不新建线程进行处理,客户端不能多个同时与服务端进行交互,需要排队等待。

        为了减少线程创建销毁的开销,这里引入线程池的使用。

package Tcp;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;

public class TcpServer {
    private ServerSocket serverSocket=null;
    public TcpServer(int port) throws IOException {
        serverSocket=new ServerSocket(port);
    }
    public void start() throws IOException {
        System.out.println("服务端上线了!");
        ExecutorService service= Executors.newCachedThreadPool();
        while(true)
        {
            Socket clientSocket=serverSocket.accept();
            service.submit(new Runnable() {
                @Override
                public void run() {
                    try {
                        proccessConnection(clientSocket);
                    } catch (IOException e) {
                        throw new RuntimeException(e);
                    }
                }
            });
        }
    }
    public void proccessConnection(Socket clientSocket) throws IOException {
        //进入方法,先打印一个日志,表示当前有客户但上线了
        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、请求并解析
                String request=scanner.next();
                //2、根据请求,计算响应
                String response=proccess(request);

                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 {
            clientSocket.close();
        }

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

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

客户端代码:

package Tcp;

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 TcpClient {
    private Socket clientSocket=null;
    public TcpClient(String serverIP,int port) throws IOException {
        clientSocket=new Socket(serverIP,port);
    }
    public void start()
    {
        Scanner scaner=new Scanner(System.in);
        try(InputStream inputStream=clientSocket.getInputStream())
        {
            OutputStream outputStream=clientSocket.getOutputStream();
            PrintWriter printWriter=new PrintWriter(outputStream);
            Scanner scannerNetwork=new Scanner(inputStream);
            while(true)
            {
                //从控制台获取用户输入的内容
                System.out.println("-> ");
                String request=scaner.next();
                //把字符串作为请求,发送给服务器

                printWriter.println(request);
                printWriter.flush();

                //读取服务器返回的响应
                String response=scannerNetwork.next();
                System.out.println(response);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

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

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

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

相关文章

【专题】2024年11月新能源汽车、智能汽车行业报告汇总PDF洞察(附原数据表)

原文链接:https://tecdat.cn/?p38520 随着科技的飞速发展与社会的持续变革,新能源汽车与智能汽车行业正步入全新的发展阶段,成为全球瞩目的焦点领域。本报告深入且全面地剖析了 2024 年 11 月该行业的多方面状况。从汽车消费市场来看&#…

mysql重置root密码(适用于5.7和8.0)

今天出一期重置mysql root密码的教程,适用于5.7和8.0,在网上搜索了很多的教程发现都没有效果,浪费了很多时间,尝试了多次之后发现这种方式是最稳妥的,那么废话不多说,往下看: 目录 第一步&…

AI智能体Prompt预设词指令大全+GPTs应用使用

AI智能体使用指南 直接复制在AI工具助手中使用(提问前) 可前往SparkAi系统用户官网进行直接使用 SparkAI系统介绍文档:Docs 常见AI智能体GPTs应用大全在线使用 自定义添加制作AI智能体进行使用: 文章润色器 你是一位具有敏锐洞察…

linux 系统常用指令

1、查看内核版本 uname -r 2、列出占用空间最大的 10 个文件或目录 du -ah / | sort -rh | head -n 10 终于找到我虚拟机硬盘空间越来越少的原因了,类目......

[C++]继承

继承 概念使用方法继承方式子类的构造与析构 继承的成员继承成员在子类对象里的存放顺序成员变量普通成员变量静态成员变量 成员函数普通成员函数重定义(隐藏) 静态成员函数友元函数 单继承与多继承概念赋值转换(切片)多继承带来的…

MetaGPT 安装

1. 创建环境 conda create -n metagpt python3.10 && conda activate metagpt2. 可编辑方式安装 git clone --depth 1 https://github.com/geekan/MetaGPT.git cd MetaGPT pip install -e .3. 配置 metagpt --init-config运行命令,在C盘位置C:\Users\325…

ros项目dual_arm_pick-place(urdf文件可视化查看)

前言 一直想写一些项目的讲解,今天(2024.12.05)可以说正式开始了。 dual_arm_pick-place项目,是关于两个机械臂协同传递物品。 正文 这次的话,给大家讲一下里面的urdf文件。 这篇文章主要来看一下项目中的urdf文件…

如何在 IntelliJ IDEA 中为 Spring Boot 应用实现热部署

文章目录 1. 引言2. 准备工作3. 添加必要的依赖4. 配置 IntelliJ IDEA4.1 启用自动编译4.2 开启热部署策略 5. 测试热部署6. 高级技巧7. 注意事项8. 总结 随着现代开发工具的进步,开发者们越来越重视提高生产力的特性。对于 Java 开发者来说,能够在不重启…

工业-实时数据采集

1.编写新的 Flume 配置文件,将数据备份到 HDFS 目录 /user/test/flumebackup 下,要求所有主题 的数据使用同一个 Flume配置文件完成。 1. 配置概览 Flume 的主要任务是从多个来源(如日志文件)读取数据,经过处理后通过接收器(Sink)存储到目标系统(如 HDFS)。在此配置…

springSecurity认证流程

Spring Security 是spring家族中的一个安全管理框架。相比于另一个安全框架Shiro,它提供更丰富的功能和社区资源,但也较难上手。所以一般大项目用spring Security,小项目用Shiro。 一般web应用需要认证和授权,这也是spring Secur…

LinuxUDP编程

由于UDP是无连接、尽力传输的,所以Server端绑定完IP、端口号后,使用recvfrom可以阻塞等待客户端的数据,而且Client端通过sendto发送的数据包直接发送到互联网(也是基于IP、端口号)这种操作是不担保Server端是否收到的&…

Nginx基本介绍及conf文件的作用

文章目录 前言一、Nginx基本介绍1.1 what is Nginx ?1.2 Nginx中的三个概念1.3 nginx安装1.4 运行nginx 二、nginx配置文件conf2.1 conf文件组成部分2.1.1 全局块2.1.2 events块2.1.3 http块 三、其他概念3.1 nginx惊群3.2 负载均衡 总结 前言 本文将介绍nginx的基…

Docker打包SpringBoot项目

一、项目打成jar包 在进行docker打包之前,先确定一下,项目能够正常的打成JAR包,并且启动之后能够正常的访问。这一步看似是可有可无,但是能避免后期的一些无厘头问题。 二、Dockerfile 项目打包成功之后,需要编写Doc…

GitLab基础环境部署:Ubuntu 22.04.5系统在线安装GitLab 17.5.2实操手册

文章目录 GitLab基础环境部署:Ubuntu 22.04.5系统在线安装GitLab 17.5.2实操手册一、环境准备1.1 机器规划1.2 环境配置1.2.1 设置主机名1.2.2 停止和禁用防火墙1.2.3 更新系统 二、GitLab安装配置2.1 安装GitLab所需的依赖包2.2 添加GitLab存储库2.2.1 将GitLab存储…

【前端开发】HTML+CSS+JavaScript前端三剑客的基础知识体系了解

前言 🌟🌟本期讲解关于HTMLCSSJavaScript的基础知识,小编带领大家简单过一遍~~~ 🌈感兴趣的小伙伴看一看小编主页:GGBondlctrl-CSDN博客 🔥 你的点赞就是小编不断更新的最大动力 …

6. 一分钟读懂“抽象工厂模式”

6.1 模式介绍 书接上文,工厂方法模式只能搞定单一产品族,遇到需要生产多个产品族时就歇菜了。于是,在需求的“花式鞭策”下,程序员们再次绷紧脑细胞,创造出了更强大的抽象工厂模式,让工厂一次性打包多个产品…

数仓技术hive与oracle对比(五)

附录说明 附录是对测试过程中涉及到的一些操作进行记录和解析。 oracle清除缓存 alter system flush shared_pool; 将使library cache和data dictionary cache以前保存的sql执行计划全部清空,但不会清空共享sql区或者共享pl/sql区里面缓存的最近被执行的条目。刷…

CEEMDAN-CPO-VMD二次分解(CEEMDAN+冠豪猪优化算法CPO优化VMD)

CEEMDAN-CPO-VMD二次分解(CEEMDAN冠豪猪优化算法CPO优化VMD) 目录 CEEMDAN-CPO-VMD二次分解(CEEMDAN冠豪猪优化算法CPO优化VMD)效果一览基本介绍程序设计参考资料 效果一览 基本介绍 首先运用CEEMDAN对数据进行一次分解&#xff…

UG NX二次开发(Python)-UIStyler-选取点

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 1、前言2、设计一个UI界面3、创建长方体的代码4、需要引入的库5、测试验证1、前言 采用Python语言进行UG NX二次开发的资料比较少,我本来不是很认可采用Python进行二次开发的,但是近期有读者咨询…

后端-时间格式问题的解决办法

方法一:在需要的地方直接加 方法二:在全局写一个springmvc的消息转换器类