【JavaEE】网络编程——TCP

news2024/11/13 11:19:21

在这里插入图片描述
🤡🤡🤡个人主页🤡🤡🤡
🤡🤡🤡JavaEE专栏🤡🤡🤡

文章目录

  • 前言
  • 1.网络编程套接字
    • 1.1流式套接字(TCP)
      • 1.1.1特点
      • 1.1.2编码
        • 1.1.2.1ServerSocket
        • 1.1.2.2Socket
        • 1.1.2.3实现一个TCP(7*24)回显服务器
        • 1.1.2.4实现一个TCP的客户端
        • 1.1.2.5实现一个TCP字典翻译服务器

前言

网络编程的目的是为了跨主机通信,socket==》操作系统提供的网络编程的API就称为"socket"API

1.网络编程套接字

TCP和UDP都是传输层协议,都是给应用层提供服务的,由于这两个协议特点差异非常打,因此我们就需要两套API来分别表示。

1.1流式套接字(TCP)

1.1.1特点

  1. 有连接:在数据传输开始前,需要通信双方建立一个专用的通道,数据传输完成后再关闭连接,好比打电话,需要双方都接通才可以对话
  2. 可靠传输:在传输数据的时候,尽可能的将数据传输到达对方,并不是100%
  3. 面向字节流:面向对象是字节,在读写的操作会非常灵活。
  4. 全双工:一条链路中,能够进行双向通信。

1.1.2编码

TCP中的socket API重点是两个类:ServerSocket和Socket。

1.1.2.1ServerSocket

ServerSocket这个类主要是用于TCP的服务器的,里面有一个非常重要的方法accept,这个方法主要是让服务器与客户端建立连接的方法,没有建立连接是无法让服务器与客户端双方互相通信。

1.1.2.2Socket

Socket这个类是既可以用于服务器中也可以用于客户端中,这个类主要是以字节的形式将数据存储和传输的,所以这个类中提供的两种方法可以类比文件操作中的方法,这个类提供getInputStream()和getOutputStream()
前者是相当于文件操作中的读操作,后者类比于写操作,只是这里的操作对象换成了服务器与客户端了。

1.1.2.3实现一个TCP(7*24)回显服务器

在这里由于getInputStream()数据都是以字节的形式存在和传输的,但在处理响应的时候会转化为字符串的形式,为了不这么麻烦的去转化,我们就用Scanner来作为读操作,将getInputStream实现的对象放入Scanner构造方法中,让Scanner内部将字节数据转化为字符串的形式,这样就避免了之后程序中许多转化。

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("服务器启动!!!");
        //将服务器与客户端进行连接,连接成功返回一个Socket对象,后续服务器对客户端的操作都基于这个对象
        while(true) {
            Socket clientSocket = serverSocket.accept();
            //创建一个方法来操作每一个客户端与服务器的联系
            processConnection(clientSocket);
        }
    }
    public void processConnection(Socket clienSocket) throws IOException {
        //打印一个客户端上线的日志
        System.out.printf("[%s:%d]客户端上线!\n",clienSocket.getInetAddress(),clienSocket.getPort());
        //1.接收客户端发送过来的信息和并解析
        try(InputStream inputStream = clienSocket.getInputStream();
            OutputStream outputStream = clienSocket.getOutputStream()) {
            //接收客户端发送过来的请求并解析(相当于从客户端读到服务器),用到Scanner的原因是由于InputStream读取的数据是字节的形式,
            //后续处理数据的时候还是要将数据从字节形式转化为字符串,而Scanner内部可以帮我们直接转化。
            Scanner scanner = new Scanner(inputStream);
            //由于需要处理客户端不断发送过来的请求,我们就需要一个while循环
            while(true) {
                //处理客户端那边不发送请求的情况
                if(!scanner.hasNext()) {
                    System.out.printf("[%s:%d]客户端下线!\n",clienSocket.getInetAddress(),clienSocket.getPort());
                    break;
                }
                //将从客户端接收过来的数据赋值到request中,为之后处理数据做铺垫
                //这里的scanner.next()需要读到空白符才会停止,所以为了区分每一份的应用层的数据报,所以我们可以在客户端手动添加空白符,
                //来控制每一份的应用层数据报
                String request = scanner.next();
                //2.计算响应,由于这是一个回显服务器,所以我们呢不需要对响应做处理,请求什么就返回什么响应
                String response = process(request);
                //3.将计算好的响应传回客户端(相当与将数据写回客户端)
                outputStream.write(response.getBytes(),0,response.getBytes().length);
                //4.打印服务器日志
                System.out.printf("[%s:%d]res = %s,resp = %s\n",clienSocket.getInetAddress(),clienSocket.getPort(),
                        request,response);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        finally {
            clienSocket.close();
        }
    }
    private String process(String request) {
        return request + "\n";
    }

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

在这里插入图片描述
程序走到这里有两种情况:

  1. 服务器与客户端双方之间的连接还在,但是客户端并没有发送请求,则会在此处进行阻塞,直到客户端发送请求过来,才会解除阻塞
  2. 服务器与客户端双方之间的连接已经断开了,那么直接就执行了if中的语句
    关于if中的scanner怎么判断连接存在还是不存在的情况,scanner是无法判断的,scnner只有阻塞作用,判断连接是否存在是scoket来判断的。
1.1.2.4实现一个TCP的客户端
public class tcpEchoClient {
    public Socket socket = null;

    public tcpEchoClient(String serverIp,int serverProt) throws IOException {
        socket = new Socket(serverIp,serverProt);
    }
    public void start() throws IOException {
        //打印日志
        System.out.println("客户端启动!");
        //1.从控制台读取
        Scanner scanner = new Scanner(System.in);
        try (InputStream inputStream = socket.getInputStream();
             OutputStream outputStream = socket.getOutputStream()){
            Scanner scannerNetwork = new Scanner(inputStream);
            while(true) {
                System.out.println("请输入你的请求:");
                String request = scanner.next();
                //与服务器规定的规则相对应
                request += "\n";
                //2.发送请求到服务器(写入服务器中)
                outputStream.write(request.getBytes());
                //3.接收从服务器发送过来的响应(从服务器将响应读入客户端)
                if(!scannerNetwork.hasNext()) {
                    break;
                }
                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",9999);
        client.start();
    }
}

上述的服务器还是存在一些问题的,比如:无法处理多个客户端同时来访问服务器,解决这个问题可以使用多线程让一个主线程来创建多个服务器与客户端连接的对象,然后再用其他线程来给客户端提供服务。

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("服务器启动!!!");
        ExecutorService pool = Executors.newCachedThreadPool();

        //将服务器与客户端进行连接,连接成功返回一个Socket对象,后续服务器对客户端的操作都基于这个对象
        while(true) {
            Socket clientSocket = serverSocket.accept();
            pool.submit(new Runnable() {
                @Override
                public void run() {
                    try {
                        processConnection(clientSocket);
                    } catch (IOException e) {
                        throw new RuntimeException(e);
                    }
                }
            });
        }
    }
    public void processConnection(Socket clienSocket) throws IOException {
        //打印一个客户端上线的日志
        System.out.printf("[%s:%d]客户端上线!\n",clienSocket.getInetAddress(),clienSocket.getPort());
        //1.接收客户端发送过来的信息和并解析
        try(InputStream inputStream = clienSocket.getInputStream();
            OutputStream outputStream = clienSocket.getOutputStream()) {
            //接收客户端发送过来的请求并解析(相当于从客户端读到服务器),用到Scanner的原因是由于InputStream读取的数据是字节的形式,
            //后续处理数据的时候还是要将数据从字节形式转化为字符串,而Scanner内部可以帮我们直接转化。
            Scanner scanner = new Scanner(inputStream);
            //由于需要处理客户端不断发送过来的请求,我们就需要一个while循环
            while(true) {
                //处理客户端那边不发送请求的情况
                if(!scanner.hasNext()) {
                    System.out.printf("[%s:%d]客户端下线!\n",clienSocket.getInetAddress(),clienSocket.getPort());
                    break;
                }
                //将从客户端接收过来的数据赋值到request中,为之后处理数据做铺垫
                //这里的scanner.next()需要读到空白符才会停止,所以为了区分每一份的应用层的数据报,所以我们可以在客户端手动添加空白符,
                //来控制每一份的应用层数据报
                String request = scanner.next();
                //2.计算响应,由于这是一个回显服务器,所以我们呢不需要对响应做处理,请求什么就返回什么响应
                String response = process(request);
                //3.将计算好的响应传回客户端(相当与将数据写回客户端)
                outputStream.write(response.getBytes(),0,response.getBytes().length);
                //4.打印服务器日志
                System.out.printf("[%s:%d]res = %s,resp = %s\n",clienSocket.getInetAddress(),clienSocket.getPort(),
                        request,response);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        finally {
            clienSocket.close();
        }
    }
    private String process(String request) {
        return request + "\n";
    }

    public static void main(String[] args) throws IOException {
        tcpEchoServer server = new tcpEchoServer(9999);
        server.start();
    }
}
1.1.2.5实现一个TCP字典翻译服务器
public class tcpDictServer extends tcpEchoServer{
    HashMap<String,String> map = null;
    public tcpDictServer(int port) throws IOException {
        super(port);
        map = new HashMap<>();
        map.put("server","服务\n");
        map.put("client","客户端\n");
        map.put("cat","🐱\n");
        map.put("dog","🐕\n");
        map.put("pig","🐖\n");
    }

    @Override
    public String process(String request) {
        return map.getOrDefault(request,"该词汇没有查询到");
    }

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

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

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

相关文章

开发个人Ollama-Chat--10 绑定域名

开发个人Ollama-Chat–10 绑定域名 域名购买最好找正规的渠道购买&#xff0c;不要因贪图小便宜而多走很多的弯路。我就是第一次购买域名&#xff0c;到了一个坑壁的平台"西部数码"&#xff0c;SSL证书申请了2个月&#xff0c;没下来&#xff0c;客服也贼不专业&…

SAP 消息输出 - Adobe Form

目录 1 安装链接 2 前台配置 - Fiori app 2.1 维护表单模板 (maintain form templates) 2.2 管理微标 (manage logos) 2.3 管理文本 (manage texts) 3 后台配置 3.1 定义表单输出规则 3.2 分配表单模板 SAP 消息输出&#xff0c;不仅是企业内部用来记录关键业务操作也是…

GAN 如何打造人造名人身份?

GAN 如何打造人造名人身份&#xff1f; 文章目录 一、介绍二、生成对抗网络&#xff08;GAN&#xff09;三、什么是发电机&#xff1f;四、什么是鉴别器&#xff1f;五、对抗性训练六、实现七、数据7.1 初始配置和设置7.2 数据加载器7.3 噪声产生7.4 发电机7.5 鉴别器 八、训练…

Appium自动化测试系列: 2. 使用Appium启动APP(真机)

历史文章&#xff1a;Appium自动化测试系列: 1. Mac安装配置Appium_mac安装appium-CSDN博客 一、准备工作 1. 安卓测试机打开调试模式&#xff0c;然后使用可以传输数据的数据线连接上你的电脑。注意&#xff1a;你的数据线一定要支持传输数据&#xff0c;有的数据线只支持充…

computed计算属性用法及方法对比

模板中的插值表达式虽然方便&#xff0c;但当要写复杂逻辑时就会变得臃肿&#xff0c;难以维护&#xff0c;遇上复杂逻辑时&#xff0c;推荐使用计算属性来描述以响应式状态的复杂逻辑。这里我们做个对比&#xff0c;先用表达式的方法进行计算&#xff0c;先把页面写好&#xf…

WIN10开机突然,过一会就自动重启蓝屏DRIVER_IRQL_NOT_LESS_OR_EQUAL

环境&#xff1a; Win10 专业版 DELL7080 问题描述&#xff1a; WIN10开机突然&#xff0c;过一会就自动重启蓝屏DRIVER_IRQL_NOT_LESS_OR_EQUAL 事件日志 解决方案&#xff1a; 1.找到MEMORY.DMP文件内容&#xff0c;分析一下 Microsoft (R) Windows Debugger Version 10…

rabbitmq集群创建admin用户之后,提示can access virtual hosts是No access状态

问题描述&#xff1a; 因业务需要使用的rabbitmq是3.7.8版本的&#xff0c;rabbitmq在3.3.0之后就允许使用guest账号的权限了&#xff0c;所以需要创建一个administrator标签的用户。 如下操作创建的用户&#xff1a; 创建完成之后就提示如下的报错&#xff1a; 注&#xff1a…

探索大模型:袋鼠云在 Text To SQL 上的实践与优化

Text To SQL 指的是将自然语言转化为能够在关系型数据库中执行的结构化查询语言&#xff08;简称 SQL&#xff09;。近年来&#xff0c;伴随人工智能大模型技术的不断进步&#xff0c;Text To SQL 任务的成功率显著提升&#xff0c;这得益于大模型的推理、理解以及指令遵循等能…

postman macOS版安装包

链接: https://pan.baidu.com/s/1Y7j4mxB1Otmf3Ku41e7v7w?pwdfy99 提取码: fy99 安装后的效果

【QT】窗口MainWindow

目录 窗口的组成 菜单栏 图形化创建菜单栏 代码创建菜单栏 给菜单设置快捷键 添加子菜单 添加分割线 添加图标 创建menuBar的细节 工具栏 设置工具栏出现的初始位置&#xff08;上下左右&#xff09; 设置工具栏允许停靠的位置 设置不允许浮动 设置不允许移动…

【STM32项目】基于嵌入式智能网控微嵌式远距操控平台(完整工程资料源码)

基于嵌入式智能网控微嵌式远距操控平台 目录&#xff1a; 前言: 一、项目前景调研 1.1 研究背景及意义 1.2 国内外发展现状及趋势 1.2.1 国内现状 1.2.2 国外发展现状 1.2.3 发展趋势 二、什么是嵌入式&#xff1f; 2.1 嵌入式系统概述 2.2 嵌入式系统的组成 2.3 嵌入式操作系统…

camera-qsc-crosstalk校准数据XTALK回写

问题背景 手机越做越紧凑&#xff0c;需要模组和芯片尺寸越做越小&#xff0c;在尺寸一定的基础上&#xff0c;高像素和大像素&#xff0c;对于手机摄像头来说&#xff0c;一直是一对矛盾的存在。 高像素&#xff1a;带来高分辨率画质大像素&#xff1a;带来暗态下高感光度和…

【java】力扣 反转链表

力扣 206 链表反转 题目介绍 解法讲解 先定义两个游标indexnull&#xff0c;prenull&#xff0c;反转之后链表应该是5&#xff0c;4&#xff0c;3&#xff0c;2&#xff0c;1&#xff0c;我们先进行2->1的反转&#xff0c;然后再循坏即可 让定义的游标index去存储head.n…

RocketMQ~消息的种类与生命周期(普通消息、延时定时消息、事务消息)

普通消息 普通消息一般应用于微服务解耦、事件驱动、数据集成等场景&#xff0c;这些场景大多数要求数据传输通道具有可靠传输的能力&#xff0c;且对消息的处理时机、处理顺序没有特别要求。 以在线的电商交易场景为例&#xff0c;上游订单系统将用户下单支付这一业务事件封…

im即时通讯系统有哪些?

IM即时通讯系统是一种通过互联网和移动通信网络实现实时通信的系统。在众多IM即时通讯系统中&#xff0c;WorkPlus作为企业级IM即时通讯系统&#xff0c;提供了全面的通讯和协作解决方案。本文将介绍几种常见的IM即时通讯系统&#xff0c;以及WorkPlus作为企业级IM即时通讯系统…

第三方配件也能适配苹果了,iOS 18与iPadOS 18将支持快速配对

苹果公司以其对用户体验的不懈追求和对创新技术的不断探索而闻名。随着iOS 18和iPadOS 18的发布&#xff0c;苹果再次证明了其在移动操作系统领域的领先地位。 最新系统版本中的一项引人注目的功能&#xff0c;便是对蓝牙和Wi-Fi配件的配对方式进行了重大改进&#xff0c;不仅…

【自动驾驶汽车通讯协议】UART通信详解:理解串行数据传输的基石

文章目录 0. 前言1. 同步通讯与异步通讯1.1 同步通信1.2 异步通信 2. UART的数据格式3. 工作原理3.1 波特率和比特率3.2 UART的关键特性 4. UART在自动驾驶汽车中的典型应用4.1 UART特性4.2应用示例 5. 结语 0. 前言 按照国际惯例&#xff0c;首先声明&#xff1a;本文只是我自…

html5——列表、表格

目录 列表 无序列表 有序列表 自定义列表 表格 基本结构 示例 表格的跨列 表格的跨行 列表 无序列表 <ul>【声明无序列表】 <li>河间驴肉火烧</li>【声明列表项】 <li>唐山棋子烧饼</li> <li>邯郸豆沫</li> <l…

pyinstaller教程(二)-快速使用(打包python程序为exe)

1.介绍 PyInstaller 是一个强大的 Python 打包工具&#xff0c;可以将 Python 程序打包成独立的可执行文件。以下会基于如何在win系统上将python程序打包为exe可执行程序为例&#xff0c;介绍安装方式、快速使用、注意事项以及特别用法。 2.安装方式 通过 pip 安装 PyInstal…

随笔-不是来养老的吗

来了有一个多月了&#xff0c;日子过得飞快。都以为我来养老的&#xff0c;一开始我也这么认为&#xff0c;结果6月份的日均工时&#xff0c;排在了部门第一。一个月做的需求比之前的三个月都多。 来之前&#xff0c;老徐让我多承担点&#xff0c;想着能有多少活嘛&#xff0c…