Java 网络编程:Socket 与网络通信

1 引言

在古代,由于通信不便利,人们利用鸽子的飞行能力和方向辨识能力,驯化鸽子进行消息传递,即所谓的“飞鸽传书”。在现代计算机网络中,套接字(Socket)扮演了类似的角色。套接字是应用程序通过网络发送或接收数据的抽象层,允许应用程序将输入输出(I/O)操作应用于网络中,并与其他应用程序进行通信。

2 套接字(Socket)简介

套接字是 IP 地址与端口的组合,是网络通信的基础。通过套接字,应用程序可以像操作文件一样打开、读写和关闭网络连接。

3 网络调试工具:ping 与 telnet

在调试网络程序时,pingtelnet 是两个非常有用的工具。

  • ping:用于测试数据包能否通过 IP 协议到达特定主机。ping 会向目标主机发出一个 ICMP 请求回显数据包,并等待接收回显响应数据包。通过 ping 命令,可以检查网络连接是否正常。

    例如,我们 ping 一下百度。截图如下。
    在这里插入图片描述

  • telnet:用于远程登录到另一台计算机。通过 telnet,用户可以在本地计算机上登录到远程计算机,进行交互式操作。在 Windows 系统中,telnet 通常是默认安装但未激活的,可以通过控制面板启用。使用 telnet 时,远程计算机需要运行一个服务,该服务持续监听网络连接请求。当接收到客户端的连接请求时,服务器进程会被唤醒,并为两者建立连接,直到某一方中止连接。

  • 然而,由于 telnet 是明文传输协议,用户的所有内容(包括用户名和密码)都没有经过加密,因此在现代网络技术中,telnet 的安全性受到质疑,并不被广泛使用。
    例如,我们 telnet 一下火(shui)土(mu)社区。截图如下。
    在这里插入图片描述

4 Socket 实例:客户端

以下是一个简单的 Java 客户端套接字(Socket)示例,模拟 telnet 命令连接远程服务器并读取数据。

import java.io.InputStream;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;
import java.io.IOException;public class SocketClientExample {public static void main(String[] args) {try (Socket socket = new Socket("bbs.newsmth.net", 23)) {InputStream is = socket.getInputStream();Scanner scanner = new Scanner(is, "gbk");while (scanner.hasNextLine()) {String line = scanner.nextLine();System.out.println(line);}} catch (UnknownHostException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}}
}

4.1 代码解析:

  1. 建立套接字连接

    Socket socket = new Socket("bbs.newsmth.net", 23);
    
    • host 为主机名,port 为端口号(23 为默认的 telnet 端口号)。
    • 如果无法确定主机的 IP 地址,则抛出 UnknownHostException 异常;如果在创建套接字时发生 IO 错误,则抛出 IOException 异常。
    • 需要注意的是,套接字在建立的时候,如果远程主机不可访问,这段代码会阻塞很长时间,直到底层操作系统的限制而抛出异常。因此,通常会在套接字建立后设置一个超时时间:
      socket.setSoTimeout(10000); // 单位为毫秒
      
  2. 获取输入流并读取数据

    InputStream is = socket.getInputStream();
    Scanner scanner = new Scanner(is, "gbk");while (scanner.hasNextLine()) {String line = scanner.nextLine();System.out.println(line);
    }
    
    • 通过 java.net.Socket 类的 getInputStream() 方法获取输入流。

    • 使用 Scanner 类将输入流中的内容按行读取并打印出来。

    • 部分结果如下图所示(完整结果建议自己亲手实践一下):

      在这里插入图片描述

通过这种方式,我们可以模拟 telnet 命令的行为,直接与远程主机进行交互,体验网络通信的底层细节。

5 ServerSocket 实例:服务器端

以下是一个简单的 Java 服务器端套接字(ServerSocket)示例,模拟一个远程服务。

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;public class ServerSocketExample {public static void main(String[] args) {try (ServerSocket server = new ServerSocket(8888);Socket socket = server.accept();InputStream is = socket.getInputStream();OutputStream os = socket.getOutputStream();Scanner scanner = new Scanner(is)) {PrintWriter pw = new PrintWriter(new OutputStreamWriter(os, "gbk"), true);pw.println("你好啊,欢迎关注「沉默王二」公众号,回复关键字「2048」领取程序员进阶必读资料包");boolean done = false;while (!done && scanner.hasNextLine()) {String line = scanner.nextLine();System.out.println(line);if ("2048".equals(line)) {done = true;}}} catch (IOException e) {e.printStackTrace();}}
}

5.1 代码解析:

  1. 建立服务器端的套接字

    ServerSocket server = new ServerSocket(8888);
    
    • 创建一个 ServerSocket 对象,并指定端口号 8888。端口号 0~1023 通常被系统预留,因此我们选择了一个大于 1023 的端口号。
  2. 等待客户端套接字的连接请求

    Socket socket = server.accept();
    InputStream is = socket.getInputStream();
    OutputStream os = socket.getOutputStream();
    
    • 调用 ServerSocket 对象的 accept() 方法,等待客户端的连接请求。一旦有客户端连接,accept() 方法会返回一个 Socket 对象,表示连接已建立。
    • 通过 Socket 对象获取输入流和输出流,分别用于读取客户端发送的数据和向客户端发送数据。
  3. 向客户端发送消息

    PrintWriter pw = new PrintWriter(new OutputStreamWriter(os, "gbk"), true);
    pw.println("你好啊,欢迎关注「沉默王二」 公众号,回复关键字「2048」 领取程序员进阶必读资料包");
    
    • 使用 PrintWriter 将消息发送到客户端。PrintWriter 的构造函数中使用了 OutputStreamWriter 来指定字符编码为 gbk,并且第二个参数 true 表示自动刷新缓冲区。
  4. 读取客户端发送的消息

    Scanner scanner = new Scanner(is);
    boolean done = false;
    while (!done && scanner.hasNextLine()) {String line = scanner.nextLine();System.out.println(line);if ("2048".equals(line)) {done = true;}
    }
    
    • 使用 Scanner 读取客户端发送的每一行数据。
    • 当客户端发送字符串 "2048" 时,服务器端会中断连接,客户端会显示“遗失对主机的连接”。

5.2 运行服务并测试:

  1. 运行服务器端代码

    • 在命令行或 IDE 中运行上述 ServerSocketExample 类。
  2. 使用 telnet 连接服务器

    • 打开一个新的命令行窗口,输入以下命令连接到服务器:
      telnet localhost 8888
      
    • 连接成功后,你会看到服务器发送的消息:
      你好啊,欢迎关注「沉默王二」 公众号,回复关键字「2048」 领取程序员进阶必读资料包
      
    • telnet 窗口中输入 2048,服务器端会中断连接,telnet 窗口会显示“遗失对主机的连接”。
      在这里插入图片描述

通过这种方式,我们可以模拟一个简单的远程服务,并通过 telnet 进行测试和交互。

6 为多个客户端服务

在这里插入图片描述
。以下是优化后的代码示例:

服务器端代码(MultiThreadedServer.java)

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;public class MultiThreadedServer {public static void main(String[] args) throws IOException {int port = 12345;ServerSocket serverSocket = new ServerSocket(port);System.out.println("Server is listening on port " + port);while (true) {Socket socket = serverSocket.accept();System.out.println("Client connected");new ClientHandler(socket).start();}}
}class ClientHandler extends Thread {private Socket socket;public ClientHandler(Socket socket) {this.socket = socket;}public void run() {try {InputStream input = socket.getInputStream();BufferedReader reader = new BufferedReader(new InputStreamReader(input));OutputStream output = socket.getOutputStream();PrintWriter writer = new PrintWriter(output, true);String line;while ((line = reader.readLine()) != null) {System.out.println("Received: " + line);writer.println("Server: " + line);}socket.close();} catch (IOException e) {System.out.println("Client disconnected");}}
}

客户端代码(Client.java)

import java.io.*;
import java.net.Socket;public class Client {public static void main(String[] args) throws IOException {String hostname = "localhost";int port = 12345;Socket socket = new Socket(hostname, port);System.out.println("Connected to the server");InputStream input = socket.getInputStream();BufferedReader reader = new BufferedReader(new InputStreamReader(input));OutputStream output = socket.getOutputStream();PrintWriter writer = new PrintWriter(output, true);writer.println("Hello, server!");String response = reader.readLine();System.out.println("Server response: " + response);socket.close();}
}

6.1 代码解析:

  1. 服务器端代码

    • MultiThreadedServer 类创建一个 ServerSocket 并监听指定端口(12345)。
    • 使用 while (true) 循环不断接受客户端的连接请求。
    • 每当有新的客户端连接时,创建一个新的 ClientHandler 线程来处理该连接。
  2. ClientHandler 类

    • ClientHandler 类继承自 Thread 类,用于处理单个客户端的连接。
    • run() 方法中,处理客户端的输入输出流,并向客户端发送消息。
    • 当客户端断开连接时,捕获 IOException 并打印“Client disconnected”。
  3. 客户端代码

    • Client 类创建一个 Socket 并连接到服务器。
    • 通过输入输出流与服务器进行通信。
    • 向服务器发送消息并接收服务器的响应。

6.2 运行服务并测试:

  1. 运行服务器端代码

    • 在命令行或 IDE 中运行 MultiThreadedServer 类。
  2. 运行多个客户端

    • 在多个命令行窗口中分别运行 Client 类。
    • 每个客户端都会连接到服务器,并向服务器发送消息。
    • 服务器会接收客户端的消息,并返回响应。
      在这里插入图片描述

通过这种方式,服务器端可以同时为多个客户端提供服务,每个客户端连接由一个独立的线程处理。这使得服务器能够高效地处理并发连接,满足一对多的需求。

7 UDP 通信:DatagramSocket 实例

UDP 是一种无连接的传输协议,适用于对可靠性要求不高但对速度要求较高的场景。以下是一个简单的 UDP 通信示例。

服务器端代码(UDPServer.java)

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;public class UDPServer {public static void main(String[] args) throws IOException {int port = 12345;DatagramSocket serverSocket = new DatagramSocket(port);System.out.println("Server is listening on port " + port);byte[] buffer = new byte[1024];DatagramPacket packet = new DatagramPacket(buffer, buffer.length);serverSocket.receive(packet);String message = new String(packet.getData(), 0, packet.getLength());System.out.println("Received: " + message);serverSocket.close();}
}

客户端代码(UDPClient.java)

import java.io.IOException;
import java.net.*;public class UDPClient {public static void main(String[] args) throws IOException {String hostname = "localhost";int port = 12345;InetAddress address = InetAddress.getByName(hostname);DatagramSocket clientSocket = new DatagramSocket();String message = "Hello, server!";byte[] buffer = message.getBytes();DatagramPacket packet = new DatagramPacket(buffer, buffer.length, address, port);clientSocket.send(packet);System.out.println("Message sent");clientSocket.close();}
}

7.1 代码解析:

  1. 服务器端代码

    • UDPServer 类创建一个 DatagramSocket 并监听指定端口(12345)。
    • 创建一个 DatagramPacket 对象,用于存储接收到的数据包。
    • 使用 serverSocket.receive(packet) 方法阻塞,直到收到一个数据包。
    • 收到数据包后,从数据包中提取消息并打印。
    • 最后关闭 DatagramSocket
  2. 客户端代码

    • UDPClient 类解析服务器的 IP 地址。
    • 创建一个 DatagramSocket 对象。
    • 将要发送的消息转换为字节数组,并创建一个 DatagramPacket 对象,指定目标地址和端口。
    • 使用 clientSocket.send(packet) 方法发送数据包。
    • 最后关闭 DatagramSocket

7.2 运行结果:

  1. 运行服务器端代码

    • 在命令行或 IDE 中运行 UDPServer 类。
    • 服务器启动并监听端口 12345,输出:
      Server is listening on port 12345
      
  2. 运行客户端代码

    • 在命令行或 IDE 中运行 UDPClient 类。
    • 客户端发送消息到服务器,输出:
      Message sent
      
  3. 服务器端接收消息

    • 服务器接收到客户端发送的消息,输出:
      Received: Hello, server!
      

通过这个示例,我们可以看到如何使用 DatagramSocket 类实现基于 UDP 协议的通信。UDP 是一种无连接的协议,因此不需要建立连接,发送和接收数据包的速度通常比 TCP 更快,但可靠性较低。

8 总结

掌握 Java Socket 编程对于理解网络通信机制至关重要。通过编写简单的客户端和服务器端程序,可以更好地理解网络通信的基本原理和实现方式。无论是基于 TCP 的 Socket 和 ServerSocket,还是基于 UDP 的 DatagramSocket,都是网络编程中不可或缺的工具。通过实践,可以进一步提升网络编程技能,为开发更复杂的网络应用打下坚实基础。

9 思维导图

在这里插入图片描述

10 参考链接

Java Socket:飞鸽传书的网络套接字

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

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

相关文章

编程之路,从0开始:结构体详解

目录 前言 正文 1、结构体引入 2、结构体的声明 3、typedef 4、结构体的匿名声明 5、结构的自引用 (1)链表 (2)自引用 6、结构体内存对齐 (1)对齐规则 (2)题目 &#x…

Flink监控checkpoint

Flink的web界面提供了一个选项卡来监控作业的检查点。这些统计信息在任务终止后也可用。有四个选项卡可以显示关于检查点的信息:概述(Overview)、历史(History)、摘要(Summary)和配置(Configuration)。下面依次来看这几个选项。 Overview Tab Overview选项卡列出了以…

04-转录组下游分析-标准化、聚类、差异分析

准备工作 1.数据标准化 标准化前需要进行数据预处理 过滤低表达的基因,并检查是否有异常样本 以下是常见的几种过滤方式(过滤的标准都可以自己调整) 1:在至少在75%的样本中都表达的基因(表达是指在某个样本中count值…

常见网络厂商设备默认用户名/密码大全

常见网络厂商的默认用户名/密码 01 思科 (Cisco) 设备类型:路由器、交换机、防火墙、无线控制器 默认用户名:cisco 默认密码:cisco 设备类型:网管型交换机 默认用户名:admin 默认密码:admin 02 华…

Spring 与 Spring MVC 与 Spring Boot三者之间的区别与联系

一.什么是Spring?它解决了什么问题? 1.1什么是Spring? Spring,一般指代的是Spring Framework 它是一个开源的应用程序框架,提供了一个简易的开发方式,通过这种开发方式,将避免那些可能致使代码…

【热门主题】000055 网络安全:构筑数字时代的坚固防线

前言:哈喽,大家好,今天给大家分享一篇文章!并提供具体代码帮助大家深入理解,彻底掌握!创作不易,如果能帮助到大家或者给大家一些灵感和启发,欢迎收藏关注哦 💕 目录 【热…

鸿蒙中位置权限和相机权限

1.module.json5中添加相关权限和string.json中配置信息 2. import { hilog } from kit.PerformanceAnalysisKit; import { TAG } from ohos/hypium/src/main/Constant; import { bundleManager, common } from kit.AbilityKit; import { abilityAccessCtrl } from kit.Ability…

2024.6使用 UMLS 集成的基于 CNN 的文本索引增强医学图像检索

Enhancing Medical Image Retrieval with UMLS-Integrated CNN-Based Text Indexing 问题 医疗图像检索中,图像与相关文本的一致性问题,如患者有病症但影像可能无明显异常,影响图像检索系统准确性。传统的基于文本的医学图像检索&#xff0…

H.264/H.265播放器EasyPlayer.js网页直播/点播播放器关于播放的时候就有声音

EasyPlayer.js H5播放器,是一款能够同时支持HTTP、HTTP-FLV、HLS(m3u8)、WS、WEBRTC、FMP4视频直播与视频点播等多种协议,支持H.264、H.265、AAC、G711A、Mp3等多种音视频编码格式,支持MSE、WASM、WebCodec等多种解码方…

Redis 的代理类注入失败,连不上 redis

在测试 redis 是否成功连接时&#xff0c;发现 bean 没有被创建成功&#xff0c;导致报错 根据报错提示&#xff0c;需要我们添加依赖&#xff1a; <dependency><groupId>org.apache.commons</groupId><artifactId>commons-pool2</artifactId>&l…

Prometheus结合K8s(一)搭建

公司之前K8s集群没有监控&#xff0c;top查看机器cpu使用率很高&#xff0c;为了监控pod的cpu和内存&#xff0c;集群外的mysql资源&#xff0c;初步搭建了Prometheus监控系统 提前准备镜像 docker.io/grafana/grafana 10.4.4 docker.io/prom/prometheus v2.47.2 docker.io/…

Vscode/Code-server无网环境安装通义灵码

Date: 2024-11-18 参考材料&#xff1a;https://help.aliyun.com/zh/lingma/user-guide/individual-edition-login-tongyi-lingma?spma2c4g.11186623.0.i0 1. 首先在vscode/code-server插件市场中安装通义插件&#xff0c;这步就不细说了。如果服务器没网&#xff0c;会问你要…

【划分型DP-约束划分个数】力扣813. 最大平均值和的分组

给定数组 nums 和一个整数 k 。我们将给定的数组 nums 分成 最多 k 个非空子数组&#xff0c;且数组内部是连续的 。 分数 由每个子数组内的平均值的总和构成。 注意我们必须使用 nums 数组中的每一个数进行分组&#xff0c;并且分数不一定需要是整数。 返回我们所能得到的最…

IDEA:2023版远程服务器debug

很简单&#xff0c;但是很多文档没有写清楚&#xff0c;wocao 一、首先新建一个远程jvm 二、配置 三、把上面的参数复制出来 -agentlib:jdwptransportdt_socket,servery,suspendn,address5005 四、然后把这串代码放到服务器中 /www/server/java/jdk1.8.0_371/bin/java -agentl…

centos安装jenkins

本机使用虚拟机centos 7.9.2009 安装gitlab&#xff0c;本机的虚拟机ip地址是 192.168.60.151&#xff0c; 步骤记录如下 1、下载jenkins&#xff0c;安装jenkins之前需要安装jdk jdk和jenkins的版本对应关系参考&#xff1a;Redhat Jenkins Packages Index of /redhat-stable…

蜀道山CTF<最高的山最长的河>出题记录

出这道题的最开始感觉就是,因为现在逆向的形式好多,我最开始学习的时候,经常因为很多工具,或者手段完全不知道,就很懵逼,很多师傅都出了各种类型的,我就想着给以前的"自己"出一道正常exe,慢慢调的题,为了不那么简单,我就选择了C(究极混淆,可能比rust好点),让大家无聊…

中伟视界:AI智能分析算法如何针对非煤矿山的特定需求,提供定制化的安全生产解决方案

非煤矿山智能化改造&#xff0c;除了政策文件&#xff0c;上级监管单位需要安装的AI智能分析算法功能之外的&#xff0c;矿方真正关心的&#xff0c;能解决矿方安全生产隐患的AI智能分析算法功能有哪些呢&#xff1f; 经过与矿方的现场交流沟通&#xff0c;收集第一现场人员对安…

如何生成python项目需要的最小requirements.txt文件?

今天咱们来聊聊 Python 项目中如何生成一个“最小的” requirements.txt 文件。我们都知道&#xff0c;当我们开发一个 Python 项目的时候&#xff0c;很多时候都会在一个虚拟环境中进行&#xff0c;这样一来&#xff0c;就能避免不同项目之间的依赖冲突。 可有时候&#xff0c…

每日论文22-24ESSERC一种54.6-65.1GHz多路径同步16振荡器

《A 54.6-65.1 GHz Multi-Path-Synchronized 16-Core Oscillator Achieving −131.4 dBc/Hz PN and 195.8 dBc/Hz FoMT at 10 MHz Offset in 65nm CMOS》24欧洲固态 本文是在60GHz 16核VCO的工作&#xff0c;主要亮点在于每一组中四个VCO之间的三路同步拓扑结构&#xff0c;有…

web——upload-labs——第十一关——黑名单验证,双写绕过

还是查看源码&#xff0c; $file_name str_ireplace($deny_ext,"", $file_name); 该语句的作用是&#xff1a;从 $file_name 中去除所有出现在 $deny_ext 数组中的元素&#xff0c;替换为空字符串&#xff08;即删除这些元素&#xff09;。str_ireplace() 在处理时…