[JAVAEE] 网络编程

目录

一. 什么是socket套接字

二. socket套接字

2.1 socket套接字根据传输层协议分类

2.2 TCP流套接字 UDP数据报套接字主要特点

三. UDP数据报套接字编程

3.1 DatagramSocket 是UDP socket, 用于发送和接受数据报

3.2 DatagramPacket 是UDP socket 发送和接收的数据报

3.3 练习案例

回显服务器

 回显客户端

四. TCP字节流套接字编程

4.1 ServerSocket 

4.2 Socket

 4.3 练习案例

回显服务器

回显客户端

注意: 


一. 什么是socket套接字

socket套接字是由系统提供用于网络通信的技术, 是基于TCP/IP协议的网络通信的基本操作单元.

基于Socket套接字的网络程序开发就是网络编程.

简单来说, socket就是网络编程套接字, 用来对网卡进行操作.

读网卡就是从网上上收数据, 写网卡就是让网卡发数据.


二. socket套接字

2.1 socket套接字根据传输层协议分类

socket套接字根据传输层协议分类:

1. 字节流套接字 使用传输层TCP协议 Transmission Control Protocol(传输控制协议)

2. 数据报套接字 使用传输层UDP协议  User Datagram Protocol(⽤⼾数据报协议)

2.2 TCP流套接字 UDP数据报套接字主要特点

TCP流套接字: 有连接, 可靠传输, 面向字节流, 全双工

UDP数据报套接字: 无连接, 不可靠传输, 面向数据报, 全双工

1. 有连接 vs 无连接

TCP, 保存通信双方信息 (例如: A与B通信, A与B建立连接)

UDP, 不保存通信双方信息, 但是可以自己实现代码来保存双端信息.

2. 可靠传输 vs 不可靠传输

TCP, 尽可能提高传输成功的概率, 如果出现丢包, 可以感知到.

UDP, 只要把数据发送了, 就不管了.

3. 面向字节流 vs 面向数据报

TCP, 以字节为单位, 读写数据.

UDP, 以数据报为单位, 读写数据.

4. 全双工 vs 半双工

一个通信链路中, 支持双向通信(能读也能写) => TCP/UDP

~, 支持单向通信(要么读, 要么写)

三. UDP数据报套接字编程

3.1 DatagramSocket 是UDP socket, 用于发送和接受数据报

构造方法

成员方法

3.2 DatagramPacket 是UDP socket 发送和接收的数据报

构造方法

成员方法

        

3.3 练习案例

回显服务器

package UDPNet;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class UDPEchoServer {
    DatagramSocket socket = null;
    public UDPEchoServer(int serverPort) throws IOException {
        socket = new DatagramSocket(serverPort); // 指定服务器端口号
    }
    public void start() throws IOException {
        System.out.println("服务器启动");
        ExecutorService executorService = Executors.newCachedThreadPool();
        while (true) {
            executorService.submit(() -> {
                while (true) { // 客户端发送多次请求
                    // 1. 接收请求并解析
                    DatagramPacket requestPacket = new DatagramPacket(new byte[4096], 4096);
                    socket.receive(requestPacket); // 输出型参数
                    String request = new String(requestPacket.getData(), 0, requestPacket.getLength());
                    // 2. 计算响应
                    String response = process(request);
                    // 3. 返回响应
                    DatagramPacket responsePacket = new DatagramPacket(response.getBytes(), 0, response.getBytes().length,
                            requestPacket.getSocketAddress());
                    socket.send(responsePacket);
                    // 打印日志
                    System.out.printf("[%s:%d] req:%s res:%s\n", requestPacket.getAddress(), requestPacket.getPort(), request, response);
                }
            });
        }
    }
    public String process(String request) {
        return request;
    }

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

 回显客户端

package UDPNet;

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

public class UDPEchoClient {
    DatagramSocket socket = null;
    String serverIP;
    int serverPort;
    UDPEchoClient(String serverIP, int serverPort) throws IOException {
        this.serverIP = serverIP;
        this.serverPort = serverPort;
        socket = new DatagramSocket();
    }
    public void start() throws IOException {
        Scanner scanner = new Scanner(System.in);
        while (true) {
            // 1. 接收用户输入
            String request = scanner.nextLine();
            // 2. 将请求发送到客户端
            DatagramPacket requestPacket = new DatagramPacket(request.getBytes(), 0, request.getBytes().length,
                    InetAddress.getByName(serverIP), serverPort);
            socket.send(requestPacket);
            // 3. 接收服务器响应并解析
            DatagramPacket responsePacket = new DatagramPacket(new byte[4096], 4096);
            socket.receive(responsePacket);
            String response = new String(responsePacket.getData(), 0, responsePacket.getLength());
            System.out.println("服务器的响应为: " + response);
        }
    }

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

四. TCP字节流套接字编程

4.1 ServerSocket 

用于创建TCP服务端socket.

构造方法

成员方法

4.2 Socket

用于创建TCP客户端socket, 或者是服务端与客户端建立连接(accept)后返回的服务端socket.

构造方法

成员方法

 

 4.3 练习案例

回显服务器

package TCPNet;

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 {
    // ServerSocket 服务器使用
    // socket 服务器和客户端都使用
    private ServerSocket serverSocket = new ServerSocket();
    public TCPEchoServer(int port) throws IOException {
        serverSocket = new ServerSocket(port); // 给服务器分配端口号
    }
    public void start() throws IOException {
        System.out.println("服务器启动!");
        ExecutorService executors = Executors.newCachedThreadPool();
        while (true) { // 服务器可能与多个客户端建立连接
            Socket socket = serverSocket.accept(); // 服务器与客户端建立连接, 返回的是服务端socket
            // socket.getInetAddress 返回的是与服务器连接的客户端的IP地址.
            // socket.getPort 返回的是与服务器建立连接的客户端的Port端口号
            System.out.printf("[%s:%d] 客户端上线!\n", socket.getInetAddress(), socket.getPort());
            executors.submit(() -> {
                try {
                    processConnection(socket); // 处理一次连接
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            });
        }
    }
    private void processConnection(Socket socket) throws IOException {
        try (socket; InputStream inputStream = socket.getInputStream();
             OutputStream outputStream = socket.getOutputStream()) {
            Scanner scannerNet = new Scanner(inputStream);
            PrintWriter writerNet = new PrintWriter(outputStream);
            while (true) { // 一次连接中可能会有多次请求
                if (!scannerNet.hasNextLine()) { // 从网卡中读不到数据了
                    System.out.printf("[%s:%d] 客户端下线!\n", socket.getInetAddress(), socket.getPort());
                    break;
                }
                // 1. 接收请求并解析
                String request = scannerNet.nextLine();
                // 2. 计算响应
                String response = process(request);
                // 3. 返回响应
                writerNet.println(response); // 将response放在内存缓冲区中, 并没有让网卡发送数据到客户端
                // 为什么要放在内存缓冲区中呢?
                // 因为TCP是面向字节流的, 数据是零散的, 放在缓冲区中等数据达到一定数量再发送.
                // 平衡了IO速度, 减少了发送次数, 提高了程序效率
                writerNet.flush(); // 刷新缓冲区, 让网卡发送数据到客户端
                // 打印日志
                System.out.printf("[%s:%d] req:%s res:%s\n", socket.getInetAddress(), socket.getPort(), request, response);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        // 一个客户端断开连接, 关闭客户端
        // 没有使用finally, 而是使用try with
    }
    private String process(String request) {
        return request;
    }

    public static void main(String[] args) throws IOException{
        TCPEchoServer tcpEchoServer = new TCPEchoServer(9999);
        tcpEchoServer.start();
    }
}

回显客户端

package TCPNet;

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;

public class TCPEchoClient {
    Socket socket = null;
    public TCPEchoClient(String serverIP, int serverPort) throws IOException {
        socket = new Socket(serverIP, serverPort);
    }
    public void start() throws IOException{
        Scanner scanner = new Scanner(System.in);
        try (InputStream inputStream = socket.getInputStream();
             OutputStream outputStream = socket.getOutputStream()) {
            Scanner scannerNet = new Scanner(inputStream);
            PrintWriter writerNet = new PrintWriter(outputStream);
            while (true) { // 一次连接中多次请求
                // 1. 用户输入请求
                String request = scanner.nextLine();
                // 2. 将请求发送到服务器
                writerNet.println(request);
                writerNet.flush();
                // 3. 接收响应
                String response = scannerNet.nextLine();
                // 打印响应
                System.out.println("服务器的响应为: " + response);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    public static void main(String[] args) throws IOException{
        TCPEchoClient tcpEchoClient = new TCPEchoClient("127.0.0.1", 9999);
        tcpEchoClient.start();
    }
}

注意: 

(1) 问题

如果只是单线程, 则服务器无法连接多个客户端, 这是因为服务端中的scannerNet.hasNextLine()阻塞, 导致不能进入外层循环, 服务器无法与其他客户端建立连接(accept).

(2) 解决

引入多线程和线程池, 把processConnection操作作为一个任务提交到线程池中. 就意味着一个客户端的连接相当于一个任务, 任务之间互不冲突. 

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

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

相关文章

GNN入门案例——KarateClub结点分类

文章目录 一、任务描述二、环境配置三、加载数据四、定义网络结构五、训练模型 一、任务描述 Karate Club 图任务是一个经典的图结构学习问题,通常用于社交网络分析和社区检测。该数据集是由 Wayne W. Zachary 在1977年收集的,描述了一个美国的空手道俱…

173. 二叉搜索树迭代器【 力扣(LeetCode) 】

文章目录 零、原题链接一、题目描述二、测试用例三、解题思路四、参考代码 零、原题链接 173. 二叉搜索树迭代器 一、题目描述 实现一个二叉搜索树迭代器类BSTIterator ,表示一个按中序遍历二叉搜索树(BST)的迭代器: BSTIterato…

【lamafactory BLEU ROUGLE L评测】

1、BLEU/ROUGLE评测界面 2、这个是用BLEU 和ROUGL来评测 目录:saves/Qwen2-7B-Chat/lora/eval_2024-11-14-16-28-19/ 在saves文件夹 生成的文件如下 all_results.json文件 说明模型在这个测试集上是不好的 3、可以查看预测结果的文件 predict_result.json

前端开发中常用的包管理器(npm、yarn、pnpm、bower、parcel)

文章目录 1. npm (Node Package Manager)2. Yarn (Yarn Package Manager)3. pnpm4. Bower5. Parcel总结 前端开发中常用的包管理器主要有以下几个: 1. npm (Node Package Manager) 简介: npm 是 Node.js 的默认包管理器,也是最广泛使用的包…

Python爬虫项目 | 一、网易云音乐热歌榜歌曲

文章目录 1.文章概要1.1 实现方法1.2 实现代码1.3 最终效果 2.具体讲解2.1 使用的Python库2.2 代码说明2.2.1 创建目录保存文件2.2.2 爬取网易云音乐热歌榜单歌曲 2.3 过程展示 3 总结 1.文章概要 学习Python爬虫知识,实现简单的一个小案例,网易云音乐热…

SHELL脚本(Linux)

声明 学习视频来自 B 站UP主泷羽sec,如涉及侵权马上删除文章。 笔记的只是方便各位师傅学习知识,以下网站只涉及学习内容,其他的都与本人无关,切莫逾越法律红线,否则后果自负。 ✍🏻作者简介:致…

reduce-scatter:适合分布式计算;Reduce、LayerNorm和Broadcast算子的执行顺序对计算结果的影响,以及它们对资源消耗的影响

目录 Gather Scatter Reduce reduce-scatter:适合分布式计算 Reduce、LayerNorm和Broadcast算子的执行顺序对计算结果的影响,以及它们对资源消耗的影响 计算结果理论正确性 资源消耗方面 Gather 这个也很好理解,就是把多个进程的数据拼凑在一起。 Scatter 不同于Br…

arkUI:水果选择与管理:基于 ArkUI 的长按编辑功能实现

水果选择与管理:基于 ArkUI 的长按编辑功能实现 1 主要内容说明2 相关内容2.1 相关内容2.1.1 源码1内容的相关说明2.1.1.1 数据结构与状态管理2.1.1.2 添加水果功能2.1.1.3 水果列表展示2.1.1.4 长按进入编辑模式2.1.1.5 复选框的多选功能2.1.1.6 删除水果功能2.1.1…

(时序论文阅读)TimeMixer: Decomposable Multiscale Mixing for Time Series Forecasting

来源论文iclr2024 论文地址:https://arxiv.org/abs/2405.14616 源码地址: https://github.com/kwuking/TimeMixer 背景 数据是有连续性,周期性,趋势性的。我们这篇文章主要围绕的是用MLP结构来预测数据的周期性具体为&#xff…

聊天服务器(8)用户登录业务

目录 登录状态业务层代码数据模型层代码记录用户的连接信息以及线程安全问题客户端异常退出业务 登录状态 登录且状态变为online 业务层代码 #include "chatservice.hpp" #include "public.hpp" #include <string> #include <muduo/base/Loggi…

18.UE5怪物视野、AI感知、攻击范围、散弹技能

2-20 怪物视野、AI感知、攻击范围、散弹技能_哔哩哔哩_bilibili 目录 1.AI感知组件 2.AI感知更新的函数 3.攻击范围 4.散弹技能 4.1创建发射物 4.2创建远程攻击方式 4.3散弹自定义事件的实现 4.4动画通知实现攻击 1.AI感知组件 为怪物蓝图添加AI感知组件&#xff0c;…

单片机智能家居火灾环境安全检测

目录 前言 一、本设计主要实现哪些很“开门”功能&#xff1f; 二、电路设计原理图 电路图采用Altium Designer进行设计&#xff1a; 三、实物设计图 四、程序源代码设计 五、获取资料内容 前言 在现代社会&#xff0c;火灾安全始终是人们关注的重点问题。随着科技的不…

安全见闻1-5

涵盖了编程语言、软件程序类型、操作系统、网络通讯、硬件设备、web前后端、脚本语言、病毒种类、服务器程序、人工智能等基本知识&#xff0c;有助于全面了解计算机科学和网络技术的各个方面。 安全见闻1 1.编程语言简要概述 C语言&#xff1a;面向过程&#xff0c;适用于系统…

【计算机网络】TCP协议特点3

心跳机制 什么是心跳机制 心跳机制是在计算机系统、网络通信和许多其他技术领域广泛应用的一种机制&#xff0c;用于检测两个实体之间的连接是否仍然活跃&#xff0c;或者设备是否还在正常运行。就是每隔一段时间发送一个固定的消息给服务端&#xff0c;服务端回复一个固定…

HarmonyOs DevEco Studio小技巧31--画布组件Canvas

那天我们用画布实现了文字颜色的渐变&#xff0c;实际上画布还有很多好玩的功能&#xff0c;接下来让我们一起试一下画布怎么玩 Canvas 提供画布组件&#xff0c;用于自定义绘制图形。 接口 Canvas Canvas(context?: CanvasRenderingContext2D | DrawingRenderingContext…

蓝桥杯每日真题 - 第10天

题目&#xff1a;&#xff08;班级活动&#xff09; 题目描述&#xff08;14届 C&C B组C题&#xff09; 解题思路&#xff1a; 题目要求我们找到最小的修改次数&#xff0c;使得任意一名同学的 ID 都与另一名同学的 ID 不相同。可以总结出这是一个寻找“重复数字最少修改…

HTML5实现俄罗斯方块小游戏

文章目录 1.设计来源1.1 主界面1.2 皮肤风格1.2 游戏中界面1.3 游戏结束界面 2.效果和源码2.1 动态效果2.2 源代码 源码下载 作者&#xff1a;xcLeigh 文章地址&#xff1a;https://blog.csdn.net/weixin_43151418/article/details/143788449 HTML5实现俄罗斯方块小游戏&#x…

外网访问 WebDav 服务

从外部网络环境&#xff08;比如异地和家中网络&#xff09;来访问公司内网的 WebDav 服务&#xff08;基于 IIS &#xff09;并映射成本地虚拟磁盘。 步骤如下 第一步 在公司内网的电脑上设置 webDav。 1&#xff0c;找到【控制面板】&#xff0c;双击进入。 2&#xff0c…

深度学习每周学习总结J5(DenseNet-121 +SE 算法实战与解析 - 猴痘识别)

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 | 接辅导、项目定制 0. 总结 数据导入及处理部分&#xff1a;本次数据导入没有使用torchvision自带的数据集&#xff0c;需要将原始数据进行处理包括数据导入…

【玩具蛇——DFS】

题目 代码 #include <bits/stdc.h> using namespace std; int g[5][5]; int dx[] {0, 0, -1, 1}, dy[] {-1, 1, 0, 0}; int ans; void dfs(int x, int y, int t) {g[x][y] t;if (t > 16){ans;g[x][y] 0;return;}for (int i 0; i < 4; i){int nx x dx[i], n…