【Java网络编程】

news2024/11/15 16:26:09

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

Java是一种广泛应用于网络编程的编程语言。通过Java的网络编程能力,我们可以构建强大的网络应用程序。本文将介绍Java网络编程的基础知识、常用API和一些实践技巧,帮助读者更好地理解和应用Java网络编程。


一、Java网络编程基础

在开始探讨Java网络编程之前,我们需要了解一些基本概念和术语。网络编程是指通过计算机网络进行数据交换和通信的过程。Java提供了一套完善的网络编程API,涵盖了各种协议和服务,如TCP/IP、HTTP、UDP等。
1.网络应用模型

  1. **C/S:**这里的C是指Client,即客户端。而S是指Server,即服务端。网络上的的应用本质上就是两台计算机上的软件进行交互。而客户端和服务端就是对应的两个应用程序,即客户端应用程序和服务端应用程序

  2. **B/S:**这里的B是Browser,即浏览器,而S是指Server。浏览器是一个通用的客户端,可以与不同的服务端进行交互。但是本质上B/S还是C/S结构,只不过浏览器是一个通用的客户端而已。
    2.可靠传输与不可靠传输
    TCP协议与UDP协议都是传输协议,客户端程序与服务端程序基于这些协议完成网络间的数据交互。

  3. TCP是可靠传输协议,是面向连接的协议,保证数据传输中的可靠性和完整性。
    TCP保证可靠传输,但是传输效率低,占用带宽高。

  4. UDP是不可靠传输协议,不保证数据传输的完整性。
    UDP不保证可靠传输,但是传输速度块,占用带宽小
    3.Socket与ServerSocket
    - java.net.Socket
    Socket(套接字)封装了TCP协议的通讯细节,是的我们使用它可以与服务端建立网络链接,并通过 它获取两个流(一个输入一个输出),然后使用这两个流的读写操作完成与服务端的数据交互
    java.net.ServerSocket

  5. ServerSocket运行在服务端,作用有两个:

    • 向系统申请服务端口,客户端的Socket就是通过这个端口与服务端建立连接的。
    • 监听服务端口,一旦一个客户端通过该端口建立连接则会自动创建一个Socket,并通过该Socket与客户端进行数据交互。
      在这里插入图片描述

二、Java网络编程常用API

1.Socket类:Socket类是Java网络编程中最常用的类之一,它提供了创建客户端套接字的方法和与服务器进行通信的能力。通过Socket,可以建立与远程服务器的连接,并进行数据传输。
Socket提供了两个重要的方法:

  • OutputStream getOutputStream()
    该方法会获取一个字节输出流,通过这个输出流写出的字节数据会通过网络发送给对方。
  • InputStream getInputStream()
    通过该方法获取的字节输入流读取的是远端计算机发送过来的数据。
    原理图
    在这里插入图片描述

例:

String host = "127.0.0.1";
int port = 8080;

// 创建Socket对象并连接服务器
Socket socket = new Socket(host, port);

// 获取输入流和输出流进行数据传输
InputStream inputStream = socket.getInputStream();
OutputStream outputStream = socket.getOutputStream();

// 向服务器发送数据
String message = "Hello, Server!";
outputStream.write(message.getBytes());

// 从服务器接收数据
byte[] buffer = new byte[1024];
int length = inputStream.read(buffer);
String response = new String(buffer, 0, length);

// 关闭资源
outputStream.close();
inputStream.close();
socket.close();

2.ServerSocket类:ServerSocket类用于创建服务器套接字,接受来自客户端的连接请求,并创建对应的Socket对象进行通信。通过ServerSocket,可以监听指定的端口,等待客户端的连接。

int port = 8080;

// 创建ServerSocket对象并监听指定端口
ServerSocket serverSocket = new ServerSocket(port);

// 接受客户端的连接请求
Socket socket = serverSocket.accept();

// 获取输入流和输出流进行数据传输
InputStream inputStream = socket.getInputStream();
OutputStream outputStream = socket.getOutputStream();

// 接收客户端发送的数据
byte[] buffer = new byte[1024];
int length = inputStream.read(buffer);
String request = new String(buffer, 0, length);

// 处理请求并返回响应数据
String response = "Hello, Client!";
outputStream.write(response.getBytes());

// 关闭资源
outputStream.close();
inputStream.close();
socket.close();
serverSocket.close();

3.URL类:URL类提供了对统一资源定位符(URL)的解析和处理能力,它可以用于打开和读取网络资源。通过URL,可以创建一个表示网络资源的对象,并获取资源的各种属性信息。

String urlString = "https://www.example.com";

// 创建URL对象
URL url = new URL(urlString);

// 打开连接并获取输入流
InputStream inputStream = url.openStream();

// 读取数据
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
String line;
StringBuilder responseBuilder = new StringBuilder();
while ((line = reader.readLine()) != null) {
    responseBuilder.append(line);
}

// 关闭资源
reader.close();
inputStream.close();

4.HttpURLConnection类:HttpURLConnection类是一种常用的建立HTTP连接的方式,它继承自URLConnection类,在Java中用于发送HTTP请求和接收HTTP响应。通过HttpURLConnection,可以设置请求头、发送请求参数,以及获取服务器返回的响应数据。

String urlString = "https://www.example.com";

// 创建URL对象
URL url = new URL(urlString);

// 打开连接
HttpURLConnection connection = (HttpURLConnection) url.openConnection();

// 设置请求方法
connection.setRequestMethod("GET");

// 发送请求并获取响应码
int responseCode = connection.getResponseCode();

// 读取响应数据
BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String line;
StringBuilder responseBuilder = new StringBuilder();
while ((line = reader.readLine()) != null) {
    responseBuilder.append(line);
}

// 关闭资源
reader.close();
connection.disconnect();

5.DatagramSocket类:DatagramSocket类用于进行UDP数据包的发送和接收,适用于一些实时性要求较高的应用场景。通过DatagramSocket,可以实现基于UDP协议的数据传输。
1.发送数据报文

String host = "127.0.0.1";
int port = 9999;

// 创建DatagramSocket对象
DatagramSocket socket = new DatagramSocket();

// 准备数据
String message = "Hello, Server!";
byte[] data = message.getBytes();

// 创建DatagramPacket对象并设置目标地址和端口号
DatagramPacket packet = new DatagramPacket(data, data.length, InetAddress.getByName(host), port);

// 发送数据报文
socket.send(packet);

// 关闭资源
socket.close();

2.接收数据报文

int port = 9999;

// 创建DatagramSocket对象并监听指定端口
DatagramSocket socket = new DatagramSocket(port);

// 准备接收数据
byte[] buffer = new byte[1024];
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);

// 接收数据报文
socket.receive(packet);

// 处理接收到的数据
String request = new String(packet.getData(), 0, packet.getLength());

// 关闭资源
socket.close();

三、Java网络编程实践技巧

与服务端建立连接案例
例:聊天室

package socket;

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

/**
 * 聊天室客户端
 */
public class Client {
    /*
java.net.Socket 套接字
Socket封装了TCP协议的通讯细节,我们通过它可以与远端计算机建立链接,
并通过它获取两个流(一个输入,一个输出),然后对两个流的数据读写完成
与远端计算机的数据交互工作。
我们可以把Socket想象成是一个电话,电话有一个听筒(输入流),一个麦克
风(输出流),通过它们就可以与对方交流了。
*/
    private Socket socket;

    /**
     * 构造方法,用来初始化客户端
     */
    public Client() {
        try {
            System.out.println("正在连接服务器......");
            /*
        实例化Socket时要传入两个参数
        参数1:服务端的地址信息
        可以是IP地址,如果链接本机可以写"localhost"
        参数2:服务端开启的服务端口
        我们通过IP找到网络上的服务端计算机,通过端口链接运行在该机器上
        的服务端应用程序。
        实例化的过程就是链接的过程,如果链接失败会抛出异常:
        java.net.ConnectException: Connection refused: connect
        */
            socket = new Socket("localhost",8088);
            System.out.println("与服务器建立连接了!");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 客户端开始工作的方法
     */
    public void start() {
        try {
            /*
            Socket提供了一个方法:
            OutputStream getOutputStream()
            该方法获取的字节输出流写出的字节会通过网络发送给对方计算机。
            */
            //低级流,将字节通过网络发送给对方
            OutputStream out = socket.getOutputStream();
            //高级流,负责衔接字节流与字符流,并将写出的字符按指定字符集转字节
            OutputStreamWriter osw = new OutputStreamWriter(out,"UTF-8");
            //高级流,负责块写文本数据加速
            BufferedWriter bw = new BufferedWriter(osw);
            //高级流,负责按行写出字符串,自动行刷新
            PrintWriter pw = new PrintWriter(bw,true);

            Scanner scanner = new Scanner(System.in);
            while(true) {
                String line = scanner.nextLine();
                if("exit".equalsIgnoreCase(line)) {
                    break;
                }
                pw.println(line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                /*
                通讯完毕后调用socket的close方法。
                该方法会给对方发送断开信号。
                */
                socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        Client client = new Client();
        client.start();
    }
}

package socket;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.charset.StandardCharsets;

/**
 * 聊天室服务器
 */
public class Server {
    /**
     * 运行在服务端的ServerSocket主要完成两个工作:
     * 1:向服务端操作系统申请服务端口,客户端就是通过这个端口与ServerSocket建立链接
     * 2:监听端口,一旦一个客户端建立链接,会立即返回一个Socket。通过这个Socket
     * 就可以和该客户端交互了
     *
     * 我们可以把ServerSocket想象成某客服的"总机"。用户打电话到总机,总机分配一个
     * 电话使得服务端与你沟通。
     */
    private ServerSocket serverSocket;

    /**
     * 服务端构造方法,用来初始化
     */
    public Server() {
        try {
            /*
            ServerSocket实例化的同时指定服务端口
            如果该端口被其他程序占用则会抛出异常:
            java.net.BindException:address already in use
            此时我们需要更换端口,或者杀死占用该端口的进程。
            端口号范围:0-65535
            */
            System.out.println("正在启动服务......");
            /*
            实例化ServerSocket时要指定服务端口,该端口不能与操作系统其他
            应用程序占用的端口相同,否则会抛出异常:
            java.net.BindException:address already in use
            端口是一个数字,取值范围:0-65535之间。
            6000之前的的端口不要使用,密集绑定系统应用和流行应用程序。
            */
            serverSocket = new ServerSocket(8088);
            System.out.println("服务器启动完毕!");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    /**
     * 服务端开始工作的方法
     */
    public void start() {

        try {
            /*
            ServerSocket的一个重要方法:
            Socket accept()
            该方法用于接受客户端的连接。这是一个阻塞方法,调用后会"卡住",直到
            一个客户端与ServerSocket连接,此时该方法会立即返回一个Socket实例
            通过这个Socket实例与该客户端对等连接并进行通讯。
            相当于"接电话"的动作
            */
            while(true){
                System.out.println("等待客户端连接......");
                Socket socket = serverSocket.accept();
                System.out.println("一个客户端连接了!");
                //启动一个线程负责与客户端交互
                ClientHandler handler = new ClientHandler(socket);
                //创建线程
                Thread t = new Thread(handler);
                //启动线程
                t.start();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        Server server = new Server();
        server.start();
    }

    /**
     * 创建线程的方式:实现Runnable接口单独定义线程任务
     * 这个线程任务就是让一个线程与指定的客户端进行交互
     */
    private class ClientHandler implements Runnable{
        private Socket socket;

        public ClientHandler(Socket socket) {
            this.socket = socket;
        }
        @Override
        public void run() {

            try {
                InputStream in = socket.getInputStream();
                InputStreamReader isr = new InputStreamReader(in,StandardCharsets.UTF_8);
                BufferedReader br = new BufferedReader(isr);
                String line;
                while((line = br.readLine()) != null){
                    System.out.println("客户端说:" + line);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

需要注意的几个点:

  • 当客户端不再与服务端通讯时,需要调用socket.close()断开链接,此时会发送断开链接的信号给服
    务端。这时服务端的br.readLine()方法会返回null,表示客户端断开了链接。
  • 当客户端链接后不输入信息发送给服务端时,服务端的br.readLine()方法是出于阻塞状态的,直到
    读取了一行来自客户端发送的字符串。
    在这里插入图片描述

总结

通过深入理解Java网络编程,我们可以构建强大的网络应用程序,满足不同的业务需求。希望读者通过本文的学习,能够掌握Java网络编程的核心概念和技术,提升自己的开发能力。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

nginx目录穿越

测试nginx版本为nginx/1.23.3 location /file {alias /home/;} 在/usr跟目录下新建a.txt测试文件 通过访问 http://{ip}:{端口}/file../test.txt 实现目录穿越 防护:location与alias的值都加上/或不加/

MongoDB实践

MongoDB学习 MongoDB简介 MongoDB 是一种流行的文档型 NoSQL 数据库,它具有以下特点和应用场景: 文档型数据库:MongoDB 使用 BSON(Binary JSON)格式的文档来存储数据。每个文档可以具有不同的字段,这使得…

山西电力市场日前价格预测【2023-10-12】

日前价格预测 预测说明: 如上图所示,预测明日(2023-10-12)山西电力市场全天平均日前电价为506.23元/MWh。其中,最高日前电价为841.91元/MWh,预计出现在18: 30。最低日前电价为351.76元/MWh,预计…

关键词搜索速卖通商品列表接口,速卖通商品列表数据接口

在网页抓取方面,可以使用 Python、Java 等编程语言编写程序,通过模拟 HTTP 请求,获取速卖通网站上的商品页面。在数据提取方面,可以使用正则表达式、XPath 等方式从 HTML 代码中提取出有用的信息。值得注意的是,速卖通…

PowerDesinger导入保险业excel数据模型(代码亲测可用)

一、Excel表 按如下结构填充建表所需的数据(附 Excel 表模板): 二、PowerDesigner 新建模型 点击:File——>New Model——>Model types——>Physical Data Mode 三、PowerDesigner 导入 Excel 脚本 按住Ctrl+Shift+X进入脚本运行界面,导入以下脚本并运行: 注…

牛客 明明的随机数

HJ3 明明的随机数 原题思路代码运行截图收获 原题 HJ3 明明的随机数 思路 如果是C的话直接用set结构体就可以自动排序GO&#xff1a;用一个501的数组存储是否出现&#xff0c;最后从头开始输出出现过的数字 代码 #include <iostream> #include <set> using na…

css怎么实现文字描边

有时&#xff0c;我们会遇到UI稿有文字描边的效果&#xff0c;比如下图的效果。 一、给需要描边的文字加一个id选择器 例如&#xff1a; 二、css写法&#xff1a; number,{//这个是实现文字描边的关键&#xff0c;也就是‘空心文字’&#xff0c;这个是定义文字字符的描边的宽…

向量的运算

向量加法 实质是坐标加法。如下图&#xff1a; 向量减法 实质是坐标减法。如下图&#xff1a; 向量乘法 分为点乘和叉乘&#xff0c;点乘是计算平行四边形的面积&#xff0c;叉乘是计算投影&#xff0c;点乘为标量&#xff0c;叉乘为向量。

Git 使用技巧:5个提高效率的命令,不再只会pull和push

前言 使用 Git 作为代码版本管理&#xff0c;早已是现在开发工程师必备的技能。可大多数工程师还是只会最基本的保存、拉取、推送&#xff0c;遇到一些commit管理的问题就束手无策&#xff0c;或者用一些不优雅的方式解决。 本文分享我在开发工作中实践过的实用命令。这些都能…

【1】MongoDB的安装以及连接

今天是2023年10月11日&#xff0c;MongoDB最新版本是7.0.2 最近闲着没事学习一下MongoDB这个NoSQL数据库&#xff0c;有时间就顺手记录一下我学习的笔记吧~ 学习笔记来自黑马程序员《MongoDB基础入门到高级进阶&#xff0c;一套搞定mongodb》 配套资料&#xff1a;点此资料链接…

Android 面经总结分享(相当走心)

背景描述 这是来自一位粉丝朋友的面经分享&#xff0c;他在 「Android 开发行业」 摸爬滚打5年多的开发&#xff0c;呆过的互联网公司有三家&#xff0c;均从事的Android 开发的工作。最后离职的一家公司也是做的最久的一家&#xff0c;工作了将近3年多时光。 废话不多说了&a…

机器学习 - 似然函数:概念、应用与代码实例

目录 一、概要二、什么是似然函数数学定义似然与概率的区别重要性举例 三、似然函数与概率密度函数似然函数&#xff08;Likelihood Function&#xff09;定义例子 概率密度函数&#xff08;Probability Density Function, PDF&#xff09;定义 区别与联系 四、最大似然估计&am…

Haskell网络编程:从数据采集到图片分析

概述 爬虫技术在当今信息时代中发挥着关键作用&#xff0c;用于从互联网上获取数据并进行分析。本文将介绍如何使用Haskell进行网络编程&#xff0c;从数据采集到图片分析&#xff0c;为你提供一个清晰的指南。我们将探讨如何使用亿牛云爬虫代理来确保高效、可靠的数据获取&am…

写爬虫?前端er何必用python

前言 说起网络爬虫,很多人第一时间想到python,但爬虫并非只能用python实现,虽然网上大部分爬虫文章都在说python爬虫,但对于前端程序员来说,我觉得js才是最屌的(对于简单爬取任务来说,复杂的我暂时没碰到~),下面说说我的经验(是的,仅限本人经验),希望能给各位前…

Qt 常用控件按钮Button 案例分析

目录 常用控件按钮 1.QPushButton 2.QToolButton 3.QRadioButton 4.QCheckBox 5.QCommandLinkButton 6.QDialogButtonBox 常用控件按钮 Push Button: 命令按钮。 Tool Button:工具按钮。 Radio Button:单选按钮。 Check Box: 复选框按钮 Command Link Button: 命今链…

2023年中国自动化微生物样本处理系统竞争现状及行业市场规模分析[图]

微生物检测能够对感染性疾病的病原体或者代谢物进行检测分析&#xff0c;是IVD的细分领域之一。2022年中国体外诊断市场规模1424亿元。 2015-2022年中国体外诊断市场规模 资料来源&#xff1a;共研产业咨询&#xff08;共研网&#xff09; 微生物检测由于样本类型多样&#xf…

HttpServletResponse对象

1.介绍 在Servlet API中&#xff0c;定义了一个HttpServletResponse接口&#xff0c;它继承自ServletResponse接口&#xff0c;专门用来封装HTTP响应消息。由于HTTP响应消息分为状态行、响应消息头、消息体三部分&#xff0c;因此&#xff0c;在HttpServletResponse接口中定义…

Netty RPC 实现

1 概念 RPC&#xff0c;即 Remote Procedure Call&#xff08;远程过程调用&#xff09;&#xff0c;调用远程计算机上的服务&#xff0c;就像调用本地服务一样。RPC 可以很好的解耦系统&#xff0c;如 WebService 就是一种基于 Http 协议的 RPC。这个 RPC 整体框架如下&#…

优盘中毒了怎么办?资料如何恢复

在现代社会中&#xff0c;优盘成为我们日常生活与工作中必备的便携式存储设备。然而&#xff0c;正是由于其便携性&#xff0c;优盘也成为病毒感染的主要目标之一。本篇文章将帮助读者了解如何应对优盘中毒的情况&#xff0c;以及如何恢复因病毒感染丢失的资料。 ▶优盘为什么…

【Java】 DirectByteBuffer堆外内存回收

PhantomReference虚引用 在分析堆外内存回收之前&#xff0c;先了解下PhantomReference虚引用。 PhantomReference需要与ReferenceQueue引用队列结合使用&#xff0c;在GC进行垃圾回收的时候&#xff0c;如果发现一个对象只有虚引用在引用它&#xff0c;则认为该对象需要被回…