javaEE-网络编程4.TCP回显服务器

目录

TCP流套接字编程

一.API介绍

ServerSocket类

构造方法:

​编辑方法:

Socket类

构造方法:

方法:

二、TCP连接

三、通过TCP实现回显服务器

TCP服务端:

1.创建Socket对象

2.构造方法

3.start方法

TCP客户端:

1.创建Socket对象

2.构造方法:

3.start方法

服务端参考代码:

客户端参考代码:

参考结果:


TCP流套接字编程

一.API介绍

有两个关键的类:

ServerSocket:是创建TCP服务端Socket的API。给服务器使用的类,使用这个类,绑定端口号.

(马路牙子上的拉客销售)

Socket:既会给客户端使用,又会给服务器使用。是客户端的Socket,又是服务器接收到客户端accept请求后,返回的服务端Socket.

(售楼处的销售顾问)

ServerSocket类

构造方法:

方法:

Socket类

既会给客户端使用,又会给服务器使用

作用:双方建立连接后,保存对端信息,用来与对方收发数据。

构造方法:

方法:

二、TCP连接

对于UDP来说,是无连接的,每次发送数据时,都需要手动在send方法中指定目标地址;

但是TCP是有连接的,需要提前把连接功能建立起来,

连接如何建立,不需要代码干预,是系统内核自动负责完成的。

我们要做的就是:客户端:发起“建立连接”的动作;

                                服务器:把建立好的连接从内核中拿到应用程序里。

三、通过TCP实现回显服务器

TCP服务端

1.创建Socket对象

2.构造方法

3.start方法

要循环的读取客户端的连接.因此要在循环中

任务1:接听连接,通过调用accept方法

任务2:建立连接,通过实现processConnection方法,建立连接

修改1:将连接改成多线程模式

当多个客户端同时发出请求时,由于单线程,这能处理一个客户端请求,将连接改成多线程,同时获取多用户的请求;但是还有一个问题,每来一个客户端,就创建一个线程,客户端结束,就销毁这个线程,当多个客户端发起请求时,就要创建和销毁大量的线程,开销就会较大;

可以用线程池的方法来创建多线程,提前将线程创建好,需要时就直接用,不用时就先放着,不需要创建和销毁。

线程池解决了线程频繁创建和销毁的开销,但是当多个线程被创建,而没有被销毁,就会导致当前服务器上积累了的大量的线程,这对于服务器的负担会非常严重。

为了解决这个问题,还可以引入其他方案:

1、引入协程。(轻量级线程)本质上还是线程,用户可以通过手动调度的方法,让一个线程并发的执行多个任务。(解决了线程调度的开销)

2.IO多路复用。(系统内核级别的机制)让一个线程负责处理多个Socket对象,这里需要Socket数据不是同时需要被处理的。

4.processConnection方法

输出客户端IP和端口号,表示客户端上线

通过调用Socket的getInputStream方法获取客户端请求,和getOutputStream返回响应

任务2.1 读取客户端请求

读取结束,则表明客户端下线,显示客户端IP和端口号

    2.2,请求并解析 注意:next读取到空白字符才结束

       

    2.3根据请求解析响应

   

这里的process方法建议写成public,方便之后子类通过继承TcpEchoServer方法,实现特有的功能

2.4把响应返回给客户端, 通过PrintfWriter的println方法返回.

修改2:手动刷新缓冲区

这里的println会有缓冲区,当读取到客户的请求时,不会计算响应,而是等缓冲区满了,才一起处理,因此,每次请求,要手动刷新缓冲区,才能保证客户端的每次请求都能及时响应

TCP客户端:

1.创建Socket对象

2.构造方法:

3.start方法

因为TCP是以字节流的形式发送请求的,要用InputStream来获取用户的输入; 获取到服务端的响应,也要用OutputStream来接收

任务1:获取用户输入请求

2.将请求发送给服务端 通过PrintWriter的println方法发送,这样可以获取到y用户输入的 "\n"

修改1:手动刷新缓冲区

客户端这里的println也有缓冲区的问题,每次输入后,也要手动刷新,将请求发送给服务端

3.从服务端获取响应 通过Scanner读取OutPutStream的输出流来获取服务器返回的响应

4.显示响应

修改2:对Socket手动关闭

目前这个代码会出现文件资源泄露,创建的Socket,没有进行close(),

这里的关闭,只是关闭了输出流和输入流,并没有关闭Socket

因此,为了避免文件资源泄露,当客户端断来连接后,要在客户端的finally代码块中手动关闭

服务端参考代码:


class TcpEchoServer1{//创建ServerSocket对象private ServerSocket serverSocket=null;//提供客户端端口号public TcpEchoServer1(int port) throws IOException {serverSocket=new ServerSocket(port);}public void start() throws IOException {System.out.println("服务端启动");ExecutorService pool = Executors.newCachedThreadPool();while(true){//1.通过accpet方法 接听连接Socket clientSocket = serverSocket.accept();//2.通过实现processConnection方法 建立连接
//            processConnection(clientSocket);pool.submit(new Runnable(){//通过线程池,创建多条线程@Overridepublic void run() {processConnection(clientSocket);}});}}//TCP是以字节流的方式发送请求的,要用InputStream来读取发送的请求,//    用OutputStream来 返回响应private void processConnection(Socket clientSocket) {System.out.printf("[%s,%d] 客户端上线\n",clientSocket.getInetAddress(),clientSocket.getPort());try(InputStream inputStream=clientSocket.getInputStream();OutputStream outputStream=clientSocket.getOutputStream()) {//循环读取客户端的请求,并返回响应while(true){//1.读取请求Scanner scan=new Scanner(inputStream);if(!scan.hasNext()){//读取完毕,客户端断开连接,产生 读取完毕System.out.printf("[%s,%d] 客户端下线\n",clientSocket.getInetAddress(),clientSocket.getPort());break;}//2,请求并解析 注意:next读取到空白字符才结束String request=scan.next();//3.根据请求,计算响应String response=process(request);//4.把响应返回给客户端//给outputStream套上一层,可以获取 \n 更方便操作PrintWriter printWriter=new PrintWriter(outputStream);printWriter.println(response);printWriter.flush();//手动刷新缓冲区System.out.printf("[%s,%d] req:%s, resp:%s\n",clientSocket.getInetAddress(),clientSocket.getPort(),request,response);}} catch (IOException e) {throw new RuntimeException(e);}}private String process(String request) {//这里还是什么都不做,就返回请求return request;}public static void main(String[] args) throws IOException {TcpEchoServer1 tcpEchoServer1 = new TcpEchoServer1(9090);tcpEchoServer1.start();}
}

客户端参考代码:


class TcpEchoClient1{//1.创建Socket对象private Socket clientSocket=null;//传入服务端的IP和端口号public TcpEchoClient1(String serverIp,int serverPort) throws IOException {clientSocket=new Socket(serverIp,serverPort);}public void start() throws IOException {System.out.println("客户端启动");try(InputStream inputStream=clientSocket.getInputStream();OutputStream outputStream=clientSocket.getOutputStream();Scanner scanNetWork=new Scanner(inputStream);Scanner scanConsole=new Scanner(System.in);PrintWriter printWriter=new PrintWriter(outputStream) ) {while(true){System.out.print("->");if(!scanConsole.hasNext()){break;//客户端请求输入结束}//1.获取请求String request=scanConsole.next();//2.将请求发送给服务端 通过PrintWriter的println方法发送printWriter.println(request);printWriter.flush();//3.获取响应String response=scanNetWork.next();//4.输出响应System.out.println(response);}} catch (IOException e) {throw new RuntimeException(e);}finally {clientSocket.close();}}public static void main(String[] args) throws IOException {TcpEchoClient1 tcpEchoClient1 = new TcpEchoClient1("127.0.0.1", 9090);tcpEchoClient1.start();}
}

参考结果:

可以同时启动多个客户端,与同一个服务端建立连接

 

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

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

相关文章

数据库1-4讲

各种名词区分 内模式也叫物理模式、存储模式。 概念模式也叫全局模式、逻辑模式。 外模式也叫用户模式。 笛卡尔积:D1、D2、D3集合中任取一个的所有可能情况。 因此上述笛卡尔积的基数22312 关系模型的三个完整性: 实体完整性&#x…

UnityWebGl:打包成webgl后UGUI不显示文字(中文)问题

是由于unity默认使用的是Arial,导致打包成webgl时中文不显示 解决方案: 可在电脑C盘下,路径为C:\Windows\Fonts 找个中文简体的字体文件放到unity里面,格式必须为. ttf

朴素贝叶斯方法

一般来说训练时的一个实例有很多属性用一个<a1,a2,....,an>来表示一个数据&#xff0c;那么此时根据最大后验概率的计算公式可以得出&#xff1a; 其中&#xff0c; H 是目标值集合。 估计每个 P&#xff08;hi&#xff09;很容易&#xff0c; 只要计算每个目标值 hi出现…

Launcher3主页面加载显示流程分析

布局结构 抓取布局后&#xff0c;可以看到每个图标是一个DoubleShadowBubbleTextView&#xff0c;父布局是CellLayout、workspace。 我们可以在CellLayout添加子view打印出调用堆栈信息&#xff0c;可以整体上看页面加载显示流程。 主要类 Launcher.java&#xff1a;主界面&…

C++编程进阶:标准库中的算法库解析

文章目录 概述1. 非修改性序列操作2. 修改性序列操作3. 排序相关算法4. 二分查找算法5. 合并与集合操作6. 堆操作7. 最小/最大操作8. 数值算法(`<numeric>`头文件)概述 算法库总览:介绍了C++ 标准库提供的海量算法,这些算法作用于各类容器(如vector、list、set等)和…

Express 加 sqlite3 写一个简单博客

例图&#xff1a; 搭建 命令&#xff1a; 前提已装好node.js 开始创建项目结构 npm init -y package.json:{"name": "ex01","version": "1.0.0","main": "index.js","scripts": {"test": &q…

Linux双端口服务器:端口1的文件系统目录挂载到端口2

目录 一、服务器安装NFS服务并配置二、文件挂载三、持久化挂载总结为什么服务器配置多个端口 目前有一台服务器&#xff0c;不过他设置了两个SSH的端口&#xff0c;通过下面方法可以让这两个端口连接的主机能够共享同一个文件系统&#xff0c;原本这两个端口的文件系统是隔离的…

nginx-灰度发布策略(split_clients)

一. 简述&#xff1a; 基于客户端的灰度发布&#xff08;也称为蓝绿部署或金丝雀发布&#xff09;是一种逐步将新版本的服务或应用暴露给部分用户&#xff0c;以确保在出现问题时可以快速回滚并最小化影响的技术。对于 Nginx&#xff0c;可以通过配置和使用不同的模块来实现基于…

【NLP自然语言处理】Transformer模型的几大核心优势与应用前景

目录 &#x1f354; Transformer的并行计算 &#x1f354; Transformer架构的并行化过程 2.1 Transformer架构中Encoder的并行化 2.2 Transformer架构中Decoder的并行化 &#x1f354; Transformer的特征抽取能力 &#x1f354; 为什么说Transformer可以代替seq2seq? 4…

数据结构与算法之排序

9.1 排序的概念 1. 排序的定义 定义&#xff1a;排序是将表中的记录按关键字递增&#xff08;或递减&#xff09;有序排列的过程。说明&#xff1a;数据中可以存在相同关键字的记录。本章主要考虑递增排序。扩展&#xff1a;排序是数据处理中的基本操作之一&#xff0c;广泛应用…

《C++11》各种初始化方式的详细列举与对比

在 C 中&#xff0c;初始化对象的方式多种多样。随着 C 标准的演进&#xff0c;特别是 C11 的引入&#xff0c;初始化方式得到了显著的扩展和改进。本文将详细列举 C 中的各种初始化方式&#xff0c;并对它们进行对比&#xff0c;帮助开发者更好地理解和应用这些特性。 1. C98…

基于 Python Django 的西西家居全屋定制系统(源码+部署+文档)

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;…

25考研|重邮软件工程复试攻略!

与计算机一样&#xff0c;重邮复试不合格也很有可能被淘汰&#xff01;快快认真准备起来&#xff01; 一、复试内容 1、笔试&#xff1a;分值100 2、综合面试&#xff1a;满分100 主要考核考生的综合素质和业务能力&#xff0c;由各招生学院具体组织实施&#xff0c;综合面试…

如何制作重识别数据集及如何解决all query identities do not appear in gallery的问题

如何制作重识别数据集 数据集制作链接 注意点&#xff1a; 按照上述方式制作完成数据集之后&#xff0c;分别建立3个文件夹&#xff0c;分别为train&#xff0c;test&#xff0c;query&#xff0c; 值得注意的是&#xff0c;query文件里的相机编号要进行修改&#xff0c;修改…

链地址法(哈希桶)

链地址法&#xff08;哈希桶&#xff09; 解决冲突的思路 开放定址法中所有的元素都放到哈希表⾥&#xff0c;链地址法中所有的数据不再直接存储在哈希表中&#xff0c;哈希表 中存储⼀个指针&#xff0c;没有数据映射这个位置时&#xff0c;这个指针为空&#xff0c;有多个数…

【C语言】可移植性陷阱与缺陷(七): 除法运算时发生的截断

在C语言编程中&#xff0c;除法运算可能会引发一些与可移植性相关的问题&#xff0c;特别是当涉及到整数除法时发生的截断&#xff08;truncation&#xff09;。不同平台对于整数除法的行为和处理方式可能会有所不同&#xff0c;这可能导致代码在不同编译器或硬件平台上的行为不…

了解RabbitMQ的工作原理

RabbitMQ是一个开源的消息代理系统&#xff0c;实现了高级消息队列协议&#xff08;AMQP&#xff09;。在现代分布式系统中&#xff0c;特别是在微服务架构中&#xff0c;RabbitMQ有广泛的应用。本文将详细介绍RabbitMQ的工作原理&#xff0c;并通过实践案例帮助读者理解和应用…

分布式搜索引擎之elasticsearch基本使用3

分布式搜索引擎之elasticsearch基本使用3 1.部署单点es 1.1.创建网络 因为我们还需要部署kibana容器&#xff0c;因此需要让es和kibana容器互联。这里先创建一个网络&#xff1a; docker network create es-net1.2.加载镜像 这里我们采用elasticsearch的7.12.1版本的镜像&…

【FlutterDart】 拖动改变 widget 的窗口尺寸大小GestureDetector~简单实现(10 /100)

上效果 预期的是通过拖动一条边界线改变窗口大小&#xff0c;类似vscode里拖动效果。这个是简单的拖动实现 上代码&#xff1a; import package:flutter/material.dart;class MyDraggableViewDemo extends StatelessWidget {const MyDraggableViewDemo({super.key});override…

使用Dinky快速提交Flink operator任务

官网地址&#xff1a;K8s集成 | Dinky 1.目前使用版本 Dinky1.2.0、Flink1.18.1、Flink operator0.10.0 2.制作镜像 2.1创建DockerFile ARG FLINK_VERSION1.18.1 FROM flink:${FLINK_VERSION}-scala_2.12 RUN mkdir -p /opt/flink/usrlib COPY commons-cli-1.3.1.jar …