【JavaEE】网络编程——TCP

在这里插入图片描述
🤡🤡🤡个人主页🤡🤡🤡
🤡🤡🤡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();
    }
}

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

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

相关文章

同四千价位闺蜜机,当贝PadGO Air和KTCPro谁更好?

市面上闺蜜机品牌那么多,那么在4K这个价位,如果想购买一台高性价比的闺蜜机应该选择当贝PadGO Air还是KTCPro呢?我们一起来看一下对比 一、外观对比 当贝PadGO Air机身底部为CD型底盘设计,非常有设计感及美感。并且创新性地融入了磁吸快拆布面设计,极大提升了用户体验的便捷…

编程入门(九)【linux系统下docker的部署与发布网站】

读者大大们好呀&#xff01;&#xff01;!☀️☀️☀️ &#x1f440;期待大大的关注哦❗️❗️❗️ &#x1f680;欢迎收看我的主页文章➡️木道寻的主页 文章目录 &#x1f525;前言&#x1f680;什么是docker?&#x1f680;docker三要素&#x1f680;linux系统下docker的基…

算法题-字符串

1.C字符串 c提供了一下两种类型的字符串表示形式&#xff1a; c风格字符串c引入的string类类型 1.1C风格字符串 C 风格的字符串起源于 C 语言&#xff0c;并在 C 中继续得到支持。字符串实际上是使用 null 字符 \0 终止的一维字符数组。因此&#xff0c;一个以 null 结尾的…

KnoBo:医书学习知识,辅助图像分析,解决分布外性能下降和可解释性问题

KnoBo&#xff1a;从医书中学习知识&#xff0c;辅助图像分析&#xff0c;解决分布外性能下降问题 提出背景KnoBo 流程图KnoBo 详解问题构成结构先验瓶颈预测器参数先验 解法拆解逻辑链对比 CLIP、Med-CLIPCLIPMed-CLIPKnoBo 训练细节预训练过程OpenCLIP的微调 构建医学语料库文…

【Nuxt3】vue3+tailwindcss+vuetify引入自定义字体样式

一、目的 在项目中引入自定义的字体样式&#xff08;全局页面都可使用&#xff09; 二、步骤 1、下载好字体 字体的后缀可以是ttf、otf、woff、eot或者svg&#xff08;推荐前三种&#xff09; 以抖音字体为例下载好放在静态文件夹&#xff08;font&#xff09;下 案例字…

notepad++中文出现异体汉字,怎么改正

notepad显示异体字&#xff0c;如何恢复&#xff1f; 比如 “门” 和 “直接” 的"直"字&#xff0c;显示成了 方法 修改字体&#xff0c; 菜单栏选择 Settings(设置&#xff09;&#xff0c;Style Configurator…&#xff08;语言格式设置…&#xff09;&#xf…

《昇思25天学习打卡营第22天|onereal》

文本解码原理--以MindNLP为例 回顾&#xff1a;自回归语言模型 根据前文预测下一个单词 一个文本序列的概率分布可以分解为每个词基于其上文的条件概率的乘积 &#x1d44a;_0:初始上下文单词序列&#x1d447;: 时间步当生成EOS标签时&#xff0c;停止生成。 MindNLP/huggi…

C++基础(三)

1.再探构造函数 之前的构造函数&#xff0c;初始化成员变量主要使用函数体内赋值&#xff0c;构造函数初始化还有一种方式&#xff0c;就是初始化列表&#xff0c;初始化列表的使用方式是以一个冒号开始&#xff0c;接着是一个以逗号分隔开的数据成员列表&#xff0c;每个“成…

【JavaScript】解决 JavaScript 语言报错:Uncaught SyntaxError: Unexpected identifier

文章目录 一、背景介绍常见场景 二、报错信息解析三、常见原因分析1. 缺少必要的标点符号2. 使用了不正确的标识符3. 关键词拼写错误4. 变量名与保留字冲突 四、解决方案与预防措施1. 检查和添加必要的标点符号2. 使用正确的标识符3. 检查关键词拼写4. 避免使用保留字作为变量名…

C# 解析省份、城市、区域 json文件

一、json文件内容如下&#xff0c;&#xff08;小程序里好像有用到...&#xff09;: 二、读取包含省份城市区域的json文件&#xff0c;并整理成想要的结果&#xff1a; string path Server.MapPath("/js"); string file System.IO.Path.Combine(path, "数据.…

数字孪生技术在元宇宙的应用

数字孪生技术与元宇宙有着天然的契合性&#xff0c;两者在技术、应用场景等方面都具有高度的互补性。数字孪生技术可以为元宇宙提供逼真、实时的数据模型和场景&#xff0c;而元宇宙可以为数字孪生技术提供广阔的应用平台和场景。北京木奇移动技术有限公司&#xff0c;专业的软…

从零开始学习深度学习库-5:自动微分(续)

引言 欢迎来到这个从头开始构建深度学习库系列的第5部分。这篇文章将介绍库中自动微分部分的代码。自动微分在上一篇文章中已经讨论过了&#xff0c;所以如果你不知道自动微分是什么&#xff0c;请查看一下。 自动微分系统的核心是计算图&#xff0c;这是一种有向图&#xff…

仅在少数市场发售?三星Galaxy Z Fold 6 Slim折叠屏手机更轻更薄

在智能手机的创新之路上&#xff0c;三星一直是行业的领跑者之一。随着Galaxy Z Fold系列的不断进化&#xff0c;三星再次突破技术边界&#xff0c;推出了更为轻薄的Galaxy Z Fold 6 Slim。 这款新型折叠屏手机以其独特的设计和卓越的性能&#xff0c;为用户带来了全新的使用体…

浅谈RLHF---人类反馈强化学习

浅谈RLHF&#xff08;人类反馈强化学习&#xff09; RLHF&#xff08;Reinforcement Learning fromHuman Feedback&#xff09;人类反馈强化学习 RLHF是[Reinforcement Learning from Human Feedback的缩写&#xff0c;即从人类反馈中进行强化学习。这是一种结合了机器学习中…

java实现资产管理系统图形化用户界面

创建一个&#x1f495;资产管理系统的GUI&#xff08;图形用户界面&#xff09;❤️画面通常需要使用Java的Swing或者JavaFX库。下面我将提供一个简单的资产管理系统GUI的示例代码&#xff0c;使用Java Swing库来实现。这个示例将包括一个主窗口&#xff0c;一个表格来显示资产…

SD card知识总结

一、基础知识 1、简介 SD Card 全称(Secure Digital Memory Card)&#xff0c;日本电子公司松下&#xff08;Panasonic&#xff09;、瑞典公司爱立信&#xff08;Ericsson&#xff09;、德国公司西门子&#xff08;Siemens&#xff09;共同开发的&#xff0c;于1999年发布根…

网络文件系统—NFS

目录 一、概述 二、NFS挂载原理 三、NFS相关协议及软件安装管理 1.协议&#xff1a; 2.软件&#xff1a; 四、NFS系统守护进程 五、NFS服务器的配置 六、NFS服务器的启动与停止 1. 启动NFS服务器 2.查询NFS服务器状态 3.停止NFS服务器 4.设置NFS服务器的自动启动状…

Redis的配置优化、数据类型、消息队列

文章目录 一、Redis的配置优化redis主要配置项CONFIG 动态修改配置慢查询持久化RDB模式AOF模式 Redis多实例Redis命令相关 二、Redis数据类型字符串string列表list集合 set有序集合sorted set哈希hash 三、消息队列生产者消费者模式发布者订阅者模式 一、Redis的配置优化 redi…

【java计算机毕设】网上购书管理系统MySQL servlet JSP项目设计源代码 期末寒暑假作业 小组作业

目录 1项目功能 2项目介绍 3项目地址 1项目功能 【java计算机毕设】网上购书管理系统MySQL servlet JSP项目设计源代码 期末寒暑假作业 小组作业 2项目介绍 系统功能&#xff1a; servlet网上购书管理系统包括管理员、用户两种角色。 管理员功能包括订单管理&#xff08;已…

pytorch中一些最基本函数和类

1.Tensor操作 Tensor是PyTorch中最基本的数据结构&#xff0c;类似于NumPy的数组&#xff0c;但可以在GPU上运行加速计算。 示例&#xff1a;创建和操作Tensor import torch# 创建一个零填充的Tensor x torch.zeros(3, 3) print(x)# 加法操作 y torch.ones(3, 3) z x y pr…