Socket套接字(TCP流)篇

Socket套接字

  • ServerSocket
  • Socket
  • 案例演示
  • 小结

ServerSocket

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

ServerSocket构造方法:

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

ServerSocket方法:

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

Socket

Socket是客户端Socket,或者是服务端中收到客户端建立连接的请求后,返回的服务端Socket.

Socket的构造方法:

方法签名方法说明
Socket(String host, int port)创建一个客户端套接字Socket, 并与对应主机,对应ip建立连接

Socket方法:

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

案例演示

TCP回显服务器

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("服务器启动!");
        while (true) {
            // 1. 处理客户端的连接
            // 把内核中的连接获取到应用程序中了,连接相当于一个个任务,放在队列中
            // 类似于生产者消费者模型
            // 如果没有客户端连接成功,就会进入阻塞.
            // 从队列中出序号最前面的连接, 与三次握手没有关系
            Socket clientSocket = serverSocket.accept();
            Thread thread = new Thread(() -> {
                try {
                    processConnection(clientSocket);
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            });
            thread.start();
        }
    }

    private void processConnection(Socket clientSocket) throws IOException {
        System.out.printf("[%s:%d] 客户端上线!\n", clientSocket.getInetAddress().toString(), clientSocket.getPort());
        // 读取请求 计算响应  返回性相应
        // Socket 对象内部包含了两个字节流对象, 可以把这俩字节流对象获取到, 完成后续的读写工作
        try(InputStream inputStream = clientSocket.getInputStream();
            OutputStream outputStream = clientSocket.getOutputStream()) {
            // 一次连接中,可能会涉及多次请求和响应
            while (true) {
                // 1. 读取请求并解析, 为了读取方便,直接使用scanner
                Scanner scanner = new Scanner(inputStream);
                if(!scanner.hasNext()) {
                    System.out.printf("[%s:%d] 客户端下线\n", clientSocket.getInetAddress().toString(), clientSocket.getPort());
                    break;
                }
                // 客户端发送的数据,得是文本数据
                // next()读取数据,一直读到空白符结束(换行,回车,空格,制表符,垂直制表符)
                String request = scanner.next();
                // 2. 根据请求计算响应
                String response = process(request);
                // 3. 把响应写回给客户端,把outputStream用PrintWriter包裹一下,方便发送数据
                PrintWriter writer = new PrintWriter(outputStream);
                // 使用 PrintWriter的println方法,把响应返回给客户端
                // 在结尾加上'\n', 客户端就可以用scanner.next()访问了
                writer.println(response);
                // 刷新缓冲区
                writer.flush();
                // 日志, 打印当前的请求信息
                System.out.printf("[%s:%d] req: %s, resp: %s\n",clientSocket.getInetAddress().toString(), clientSocket.getPort(),
                        request, response);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            // 不关闭会内存泄漏
            // 在finally中加入close方法,确保socket被关闭
            clientSocket.close();
        }
    }

    public String process(String request) {
        // 回显服务器
        return request;
    }

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

TCP客户端

public class TcpEchoClient {
    private Socket socket = null;

    public TcpEchoClient(String serverIp, int serverPort) throws IOException {
        // new操作后,就完成了tcp连接的建立
        // 建立了三次握手
        socket = new Socket(serverIp, serverPort);
    }

    public void start() throws IOException {
        //
        System.out.println("客户端启动");
        Scanner scannerConsole = new Scanner(System.in);
        try(InputStream inputStream = socket.getInputStream();
            OutputStream outputStream = socket.getOutputStream()) {
            while (true) {
                System.out.println("-> ");
                // 1. 从控制台输入字符串
                String request = scannerConsole.next();
                // 2. 把请求发送给服务器
                PrintWriter writer = new PrintWriter(outputStream);
                // 使用 println 带上换行. 后续服务器读取请求, 就可以使用 scanner.next 来获取了
                writer.println(request);
                // 确保数据发出去了
                writer.flush();
                // 3. 从服务器读取响应
                Scanner scannerNetWork = new Scanner(inputStream);
                String response = scannerNetWork.next();
                // 4. 把响应打印出来
                System.out.println(response);
            }
        }
    }

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

Scanner对象和PrintWriter没有进行close,是否有文件资源泄漏呢>
答案是不会的.
流对象持有的资源分为两部分:

  1. 内存(对象销毁,内存就回收了)
  2. 文件描述符
    while循环结束,内存被销毁.Scanner和PrintWriter没有文件描述符,有的是InputStream和OutputStream,准确说是Socket对象,把Socket对象关闭就可以了.
实际上客户端往往会发送大量的请求,我们可以使用线程池的方式来实现高并发.
但是即使使用了线程池,避免了频繁创建销毁线程.
毕竟是每个客户端对应一个线程,如果客户端很多,就需要创建大量线程,
对于服务器是开销很大的.
我们可以引入"IO多路复用"的方式解决多并发,利用"节流",是消耗的硬件资源更少了,减少
了线程的数量.

小结

本博客总结了Socket套接字(TCP流)的相关知识,有收获的小伙伴多多支持.

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

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

相关文章

广工电工与电子技术实验报告-8路彩灯循环控制电路

实验代码 module LED_water (clk,led); input clk; output [7:0] led; reg [7:0] led; integer p; reg clk_1Hz; reg [7:0] current_state, next_state; always (posedge clk) begin if(p25000000-1)begin …

JVM(Jvm如何管理空间?对象如何存储、管理?)

Jvm如何管理空间(Java运行时数据区域与分配空间的方式) ⭐运行时数据区域 程序计数器 程序计数器(PC),是一块较小的内存空。它可以看作是当前线程所执行的字节码的行号指示器。Java虚拟机的多线程是通过时间片轮转调…

Flutter 从 Assets 中读取 JSON 文件:指南 [2024]

在本教程中,我们将探讨如何从 Flutter 项目中的 asset 中读取 JSON 文件。您将找到详细的解释、实际示例和最佳实践,使您的 JSON 文件处理顺利高效。那么,让我们深入了解 Flutter 和 JSON 的世界吧! 从 asset 中读取 JSON 文件 …

RTK负载(4K可见光+高分热成像+超广角+激光测距)四光AI智能识别跟踪吊舱技术详解

无人机光电吊舱的RTK负载(4K可见光高分热成像超广角激光测距)AI智能识别跟踪吊舱技术是一种高度集成和先进的无人机观测系统。系统结合了无人机的飞行能力和光电吊舱的多功能传感器,通过集成RTK(实时动态差分定位)技术…

WebGL开发框架比较

WebGL开发框架提供了一套丰富的工具和API,使得在Web浏览器中创建和操作3D图形变得更加容易。以下是一些流行的WebGL开发框架及其各自的优缺点。北京木奇移动技术有限公司,专业的软件外包开发公司,欢迎交流合作。 1.Three.js 优点&#xff1a…

WoodMart主题下载:为您的电商网站带来自然而优雅的购物体验

在电子商务的激烈竞争中,一个设计精良、用户友好的在线商店是吸引和保留客户的关键。WoodMart主题,作为一款专为Shopify平台设计的高级主题,以其自然美学和强大的功能,帮助您的商店在众多竞争对手中脱颖而出。 [WoodMart主题的核…

运行游戏提示dll文件丢失,分享多种有效的解决方法

在我们日常频繁地利用电脑进行娱乐活动,特别是畅玩各类精彩纷呈的电子游戏时,常常会遭遇一个令人困扰的问题。当我们满怀期待地双击图标启动心仪的游戏程序,准备全身心投入虚拟世界时,屏幕上却赫然弹出一条醒目的错误提示信息&…

【书生浦语第二期实战营学习作业笔记(二)】

书生浦语第二期实战营学习作业&笔记(二) 操作文档:https://github.com/InternLM/Tutorial/blob/camp2/helloworld/hello_world.md 基础作业 : 使用 InternLM2-Chat-1.8B 模型生成 300 字的小故事: 八戒部署(笔记&#xff0…

基于灰狼算法的综合能源系统多时间尺度优化调度(附matlab程序)

0.代码链接 基于灰狼算法的综合能源系统多时间尺度优化调度(MATLAB程序)资源-CSDN文库 1.简述 对于冷、热、电联供综合能源系统优化问题,为了提高可再生能源利用率,故以弃风、弃光量最小和综合能源系统运行经济性为优化目标&…

mac配置maven

在 macOS 上配置 Maven 也相对简单。以下是一种常用的方法: 1. 安装maven **下载 Maven:**首先,你需要从 Maven 官网(https://maven.apache.org/download.cgi)下载最新版本的 Maven。你可以选择二进制压缩包&#xf…

redis常用数据结构

redis常用数据结构 Redis 底层在实现下面数据结构的时候,会进行特定的优化,来达到节省时间/空间的效果。 内部结构 String raw(最基本的字符串),int(实现计数功能,当value为整数的时候会用整…

JPEG图像常用加密算法简介

JPEG图像加密算法 目前,JPEG图像加密算法可以分成异或加密、置乱加密和置乱与异或组合加密。下面对这三种加密方式进行阐述。 (1) 异或加密 文献[1]提出了一种基于异或加密的JPEG图像的RDH-EI方案。该算法通过对AC系数的ACA和图像的量化表进行流密码异或&#xf…

Feign功能详解、使用步骤、代码案例

简介:Feign是Netflix开发的声明式,模板化的HTTP客户端,简化了HTTP的远程服务的开发。Feign是在RestTemplate和Ribbon的基础上进一步封装,使用RestTemplate实现Http调用,使用Ribbon实现负载均衡。我们可以看成 Feign R…

经典的免费wordpress模板

这款经典的免费WordPress模板以鲜艳的红色为主调,充满了活力与热情。设计简洁而现代,适合各种类型的项目网站。模板采用响应式设计,确保在不同设备和屏幕尺寸上都能呈现出完美的视觉效果。 红色象征着激情、活力和自信,这款模板…

ubuntu子系统密码忘记了,怎么办?

🏆本文收录于「Bug调优」专栏,主要记录项目实战过程中的Bug之前因后果及提供真实有效的解决方案,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&…

18种WEB常见漏洞:揭秘网络安全的薄弱点

输入验证漏洞: 认证和会话管理漏洞: 安全配置错误: 其他漏洞: 防范措施: Web 应用程序是现代互联网的核心,但它们也容易受到各种安全漏洞的影响。了解常见的 Web 漏洞类型,对于开发人员、安全测试人员和普通用户都至关重要。以下将介绍 18 种常见的 …

HttpClient工具类编写

HttpClient 介绍 HttpClient是Apache Jakarta Common下的一个子项目,它提供了一个高效的、最新的、功能丰富的支持HTTP协议的客户端编程工具包。它支持HTTP协议最新的版本和建议,并实现了Http1.0和Http1.1协议。 HttpClient具有可扩展的面向对象的结构…

电脑壁纸怎么设置?简单3步,让你的电脑桌面变得更合心意

电脑壁纸是我们每天在电脑上工作和娱乐时不可或缺的一部分。一张精美的电脑壁纸,既能提升我们的工作效率,也能为我们带来愉悦的心情。无论是静谧的自然风光、抽象的艺术设计,还是心动的明星照片,都可以在电脑壁纸的世界里找到自己…

HF区块链链码基础

链码生命周期 一 . 链码准备 准备文件 . 在测试目录下创建chaincode,拷贝测试链码进 chaincode目录,拷贝 set-env.sh 脚本进 scripts 目录 二. 打包链码 打包测试链码 export FABRIC_CFG_PATH${PWD}/config peer lifecycle chaincode package ./chaincode/chaincode_basic.…

Springboot 中RedisTemplate使用scan来获取所有的key底层做了哪些事情

直接上代码&#xff0c;围绕着代码来讨论 redisTemplate.execute((RedisCallback<Object>) (connection) -> {Cursor<byte[]> scan connection.scan(ScanOptions.scanOptions().count(2).match("*").build());scan.forEachRemaining((bytes) -> {…