TCP实现双向通信练习题

news2025/5/24 13:22:24

1. 客户端代码:Client.java

package com.xie.javase.net3;

import java.io.*;
import java.net.InetAddress;
import java.net.Socket;

/**
 * TCP客户端:向服务端发送图片,并接收服务端响应
 */
public class Client {
    public static void main(String[] args) {
        Socket socket = null;
        BufferedInputStream bis = null;
        BufferedOutputStream bos = null;
        BufferedReader br = null;

        try {
            // 1. 获取本机地址对象
            InetAddress localHost = InetAddress.getLocalHost();
            int port = 8888;

            // 2. 创建Socket并连接服务端
            socket = new Socket(localHost, port);
            System.out.println("已连接到服务端:" + socket.getRemoteSocketAddress());

            // 3. 准备发送图片
            bis = new BufferedInputStream(new FileInputStream("D:\\kakaluote.jpg"));
            bos = new BufferedOutputStream(socket.getOutputStream());

            // 4. 读取本地图片并发送到服务端
            byte[] buffer = new byte[1024];
            int readCount;
            while ((readCount = bis.read(buffer)) != -1) {
                bos.write(buffer, 0, readCount);
            }
            bos.flush(); // 强制刷新输出流
            System.out.println("图片发送完成");

            // 5. 半关闭输出流(通知服务端数据发送完毕)
            socket.shutdownOutput();

            // 6. 接收服务端响应
            br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            String response;
            while ((response = br.readLine()) != null) {
                System.out.println("服务端响应:" + response);
            }

        } catch (IOException e) {
            System.err.println("客户端异常:" + e.getMessage());
        } finally {
            // 7. 关闭资源(反向顺序)
            try {
                if (br != null) br.close();
                if (bos != null) bos.close();
                if (bis != null) bis.close();
                if (socket != null) socket.close();
            } catch (IOException e) {
                System.err.println("资源关闭异常:" + e.getMessage());
            }
        }
    }
}

2. 服务端代码:Server.java

package com.xie.javase.net3;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * TCP服务端:接收客户端图片,保存后发送确认响应
 */
public class Server {
    public static void main(String[] args) {
        ServerSocket serverSocket = null;
        Socket clientSocket = null;
        BufferedInputStream bis = null;
        BufferedOutputStream bos = null;
        BufferedWriter bw = null;

        try {
            // 1. 创建服务端Socket并监听端口
            int port = 8888;
            serverSocket = new ServerSocket(port);
            System.out.println("服务端已启动,等待客户端连接...");

            // 2. 接受客户端连接
            clientSocket = serverSocket.accept();
            System.out.println("客户端已连接:" + clientSocket.getRemoteSocketAddress());

            // 3. 接收客户端发送的图片
            bis = new BufferedInputStream(clientSocket.getInputStream());
            bos = new BufferedOutputStream(new FileOutputStream("./dog.jpg")); // 保存到当前目录

            byte[] buffer = new byte[1024];
            int readCount;
            while ((readCount = bis.read(buffer)) != -1) {
                bos.write(buffer, 0, readCount);
            }
            bos.flush();
            System.out.println("图片接收完成");

            // 4. 发送响应给客户端
            bw = new BufferedWriter(new OutputStreamWriter(clientSocket.getOutputStream()));
            bw.write("图片已成功接收,大小:" + new File("./kakaluote.jpg").length() + "字节");
            bw.newLine(); // 添加换行符标识消息结束
            bw.flush();

        } catch (IOException e) {
            System.err.println("服务端异常:" + e.getMessage());
        } finally {
            // 5. 关闭资源(反向顺序)
            try {
                if (bw != null) bw.close();
                if (bos != null) bos.close();
                if (bis != null) bis.close();
                if (clientSocket != null) clientSocket.close();
                if (serverSocket != null) serverSocket.close();
            } catch (IOException e) {
                System.err.println("资源关闭异常:" + e.getMessage());
            }
        }
    }
}

关键代码解析

客户端
  1. socket.shutdownOutput()

    • 半关闭输出流,通知服务端数据发送完毕,但保持输入流开启以接收响应。
    • 避免服务端的bis.read()无限阻塞。
  2. 响应接收逻辑

    • 使用BufferedReader.readLine()读取服务端文本响应,需服务端发送换行符。
服务端
  1. 图片保存路径

    • new FileOutputStream("./kakaluote.jpg"):将文件保存到项目根目录。
  2. 响应消息优化

    • 动态计算接收文件大小,增强反馈信息:
      new File("./kakaluote.jpg").length()

执行流程

  1. 启动服务端

    服务端已启动,等待客户端连接...
    
  2. 启动客户端

    已连接到服务端:/127.0.0.1:8888
    图片发送完成
    服务端响应:图片已成功接收,大小:204800字节
    
  3. 服务端输出

    客户端已连接:/127.0.0.1:52345
    图片接收完成
    

注意事项

  1. 文件路径

    • 客户端确保D:\\kakaluote.jpg存在。
    • 服务端需要项目根目录有写入权限。
  2. 流关闭顺序

    • 先关闭外层流(如BufferedWriter),再关闭内层流(如OutputStream)和Socket。
  3. 异常处理

    • 打印具体异常信息,而非直接抛出RuntimeException,便于调试。

扩展建议

  1. 多线程服务端
    使用线程池处理多个客户端同时上传:

    ExecutorService pool = Executors.newCachedThreadPool();
    while (true) {
        Socket socket = serverSocket.accept();
        pool.execute(() -> handleClient(socket));
    }
    
  2. 进度显示
    在客户端和服务端添加传输进度百分比计算:

    File file = new File("D:\\kakaluote.jpg");
    long totalSize = file.length();
    long transferred = 0;
    while ((readCount = bis.read(buffer)) != -1) {
        bos.write(buffer, 0, readCount);
        transferred += readCount;
        System.out.printf("传输进度:%.2f%%\n", (transferred * 100.0 / totalSize));
    }
    

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

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

相关文章

PCIe学习笔记(3)链路初始化和训练

PCIe学习系列往期文章 PCIe学习笔记(1)Hot-Plug机制 PCIe学习笔记(2)错误处理和AER/DPC功能 文章目录 链路训练概述Bit LockSymbol Lock (Gen1/2)Block Alignment (Gen3)Lane Polarity InversionLane ReversalLane-to-Lane De-ske…

Oracle 11g导出数据库结构和数据

第一种方法:Plsql 利用plsql可视化工具导出,首先根据步骤导出表结构: 工具(Tools)->导出用户对象(export user objects)。 其次导出数据表结构: 工具(Tools)->导出表(export Tables)->选中表->sql inserts(where语…

零基础设计模式——创建型模式 - 抽象工厂模式

第二部分:创建型模式 - 抽象工厂模式 (Abstract Factory Pattern) 我们已经学习了单例模式(保证唯一实例)和工厂方法模式(延迟创建到子类)。现在,我们来探讨创建型模式中更为复杂和强大的一个——抽象工厂…

解锁内心的冲突:神经症冲突的理解与解决之道

目录 一、神经症冲突概述 二、冲突的基本类型 三、未解决冲突的后果 四、尝试解决的途径 五、真正解决冲突 六、总结 干货分享,感谢您的阅读! 人类的内心世界复杂多变,常常充满了各种冲突和矛盾。每个人在成长的过程中,都或…

Redisson读写锁和分布式锁的项目实践

解决方案:采用读写锁 什么是读写锁 Redisson读写锁是一种基于Redis实现特殊的机制,用于在分布式系统中协调对共享资源的访问,其继承了Java中的ReentrantReadWriteLock的思想.特别适用于读多写少的场景.其核心是:允许多个线程同时读取共享资源,但写操作必须占用资源.从而保证线…

SkyWalking高频采集泄漏线程导致CPU满载排查思路

SkyWalking高频采集泄漏线程导致CPU满载排查思路 契机 最近在消除线上服务告警,发现Java线上测试服经常CPU满载告警,以前都是重启解决,今天好好研究下,打arthas火焰图发现是SkyWalking-agent的线程采集任务一直在吃cpu&#xff…

【HarmonyOS 5】Map Kit 地图服务之应用内地图加载

#HarmonyOS SDK应用服务,#Map Kit,#应用内地图 目录 前期准备 AGC 平台创建项目并创建APP ID 生成调试证书 生成应用证书 p12 与签名文件 csr 获取 cer 数字证书文件 获取 p7b 证书文件 配置项目签名 配置签名证书指纹 项目开发 配置Client I…

ld: cpu type/subtype in slice (arm64e.old) does not match fat header (arm64e)

ld: cpu type/subtype in slice (arm64e.old) does not match fat header (arm64e) in ‘/Users/*****/MposApp/MposApp/Modules/Common/Mpos/NewLand/MESDK.framework/MESDK’ clang: error: linker command failed with exit code 1 (use -v to see invocation) 报错 解决方…

通过vue-pdf和print-js实现PDF和图片在线预览

npm install vue-pdf npm install print-js <template><div><!-- PDF 预览模态框 --><a-modal:visible"showDialog":footer"null"cancel"handleCancel":width"800":maskClosable"true":keyboard"…

视频监控管理平台EasyCVR结合AI分析技术构建高空抛物智能监控系统,筑牢社区安全防护网

高空抛物严重威胁居民生命安全与公共秩序&#xff0c;传统监管手段存在追责难、威慑弱等问题。本方案基于EasyCVR视频监控与AI视频分析技术&#xff08;智能分析网关&#xff09;&#xff0c;构建高空抛物智能监控系统&#xff0c;实现24小时实时监测、智能识别与精准预警&…

2.2.1 05年T1复习

引言 从现在进去考研英语基础阶段的进阶&#xff0c;主要任务还是05-09年阅读真题的解题&#xff0c;在本阶段需要注意正确率。阅读最后目标&#xff1a;32-34分&#xff0c;也就是每年真题最多错四个。 做题步骤&#xff1a; 1. 预习&#xff1a;读题干并找关键词 做题&#…

Python-11(集合)

与字典类似&#xff0c;集合最大的特点就是唯一性。集合中所有的元素都应该是独一无二的&#xff0c;并且也是无序的。 创建集合 使用花括号 set {"python","Java"} print(type(set)) 使用集合推导式 set {s for s in "python"} print(set…

Opixs: Fluxim推出的全新显示仿真模拟软件

Opixs 是 Fluxim 最新研发的显示仿真模拟软件&#xff0c;旨在应对当今显示技术日益复杂的挑战。通过 Opixs&#xff0c;研究人员和工程师可以在制造前&#xff0c;设计并验证 新的像素架构&#xff0c;从而找出更功节能、色彩表现更优的布局方案。 Opixs 适用于学术研究和工业…

佰力博与您探讨PVDF薄膜极化特性及其影响因素

PVDF&#xff08;聚偏氟乙烯&#xff09;薄膜的极化是其压电性能形成的关键步骤&#xff0c;通过极化处理可以显著提高其压电系数和储能能力。极化过程涉及多种方法和条件&#xff0c;以下从不同角度详细说明PVDF薄膜的极化特性及其影响因素。 1、极化方法 热极化&#xff1a;…

自动获取ip地址安全吗?如何自动获取ip地址

在数字化网络环境中&#xff0c;IP地址的获取方式直接影响设备连接的便捷性与安全性。自动获取IP地址&#xff08;通过DHCP协议&#xff09;虽简化了配置流程&#xff0c;但其安全性常引发用户疑虑。那么&#xff0c;自动获取IP地址安全吗&#xff1f;如何自动获取IP地址&#…

STM32:深度解析RS-485总线与SP3485芯片

32个设备 知识点1【RS-485的简介】 RS-485是一种物理层差分总线标准&#xff0c;在串口的基础上演变而来&#xff1b; 两者虽然不在同一层次上直接对等&#xff0c;但在实际系统中&#xff0c;往往使用RS-485驱动差分总线&#xff0c;将USART转换为适合长距离、多点通信的物…

亚马逊搜索代理: 终极指南

文章目录 前言一、为什么需要代理来搜索亚马逊二、如何选择正确的代理三、搜索亚马逊的最佳代理类型四、为亚马逊搜索设置代理五、常见挑战及克服方法六、亚马逊搜索的替代方法总结 前言 在没有代理的情况下搜索亚马逊会导致 IP 禁止、验证码和速度限制&#xff0c;从而使数据…

C++笔记-封装红黑树实现set和map

1.源码及框架分析 上面就是在stl库中set和map的部分源代码。 通过上图对框架的分析&#xff0c;我们可以看到源码中rb_tree⽤了⼀个巧妙的泛型思想实现&#xff0c;rb_tree是实 现key的搜索场景&#xff0c;还是key/value的搜索场景不是直接写死的&#xff0c;⽽是由第⼆个模板…

留给王小川的时间不多了

王小川&#xff0c;这位头顶“天才少年”光环的清华学霸、搜狗输入法创始人、中国互联网初代技术偶像&#xff0c;正迎来人生中最难啃的硬骨头。 他在2023年创立的百川智能&#xff0c;被称为“大模型六小虎”之一。今年4月&#xff0c;王小川在全员信中罕见地反思过去两年工作…

国产频谱仪性能如何?矢量信号分析仪到底怎么样?

矢量信号分析仪是一种高性能的电子测量设备&#xff0c;具备频谱分析、矢量信号分析、实时频谱分析、脉冲信号分析、噪声系数测量、相位噪声测量等多种功能。它能够对各类复杂信号进行精确的频谱特性分析、调制质量评估、信号完整性检测以及干扰源定位等操作。广泛应用于通信、…