TCP协议网络编程 回显服务器,客户端实现

        回显服务器表示客户端传来的请求是什么,服务器就回应什么,客户端不用对传来的数据进行处理,主要是为了熟悉TCP协议提供的API的使用

对于代码的解释全作为注释写在了代码上,推荐复制到编程软件中查看

UDP协议实现回显服务器可以看UDP数据报网络编程(实现简单的回显服务器,客户端)

其中涉及到的线程池的内容可以看通过标准库创建线程池

idea开启多个客户端的方法可以看idea如何开启多个客户端(一个代码开启多个客户端运行)

服务器代码

package TcpEcho;import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;/*** Created with IntelliJ IDEA.* Description:* User: wuyulin* Date: 2023-08-10* Time: 16:25*/
//TCP协议 回显服务器(客户端传来的请求是什么,服务器就回应什么)
//TCP协议网络编程两个最主要的类是ServerSocket和Socket
public class TcpEchoServer {//线程池对象ExecutorService executorService= null;//ServerSocket类内置了一个队列,在内核中客户端和服务器尝试建立连接,连接建立完了以后得到的连接对象就存入了队列中//客户端和服务器尝试建立连接,进行一系列的数据交互称为“握手”,这个过程建立完了以后,连接就建立好了private ServerSocket serverSocket=null;//在构造方法中实例化serverSocket对象,port参数表示在创建服务器时要指定服务器的ip地址TcpEchoServer(int port) throws IOException {serverSocket=new ServerSocket(port);executorService=Executors.newCachedThreadPool();    //实例化一个线程数目动态变化的线程池}public void start() throws IOException {//写日志,方便观察当前运行状态System.out.println("服务器启动");//服务器需要不停的去接收客户端传来的请求并做出回应,所以需要一个死循环while (true){//TCP是有连接的,需要处理服务器与客户端之间的连接,而UDP是无连接的,不需要处理//处理服务器与客户端之间的连接//通过调用accept方法,取出serverSocket对象内置的队列中的连接对象(Socket对象)//当队列中没有Socket连接对象时,就会在accept方法这里进入阻塞等待,直到取得连接对象为止Socket socket=serverSocket.accept();//对获得的服务器与客户端之间的连接对象进行处理//采用当前的编写方式会发现当有多个客户端来连接服务器并发出请求时,服务器不能同时处理//因为在handleConnection方法中会一直循环处理客户端发出的请求//而当前编写方式要等handleConnection方法执行完毕才能去取出下一个连接对象,才能处理下一个客户端发出的请求// handleConnection(socket);//解决办法:用主线程去调用accept方法取出连接对象,每取出一个连接对象就创建一个线程去处理连接对象对应的客户端发出的请求//但下面这个创建线程来处理socket连接对象的代码也注释掉了,这是因为要是有很多客户端来对服务器发出请求,就会涉及到大量//线程的创建和销毁,这是很消耗资源的,所以应该采用线程池来处理socket连接对象
//            Thread t=new Thread(()->{
//                try {
//                    handleConnection(socket);
//                } catch (IOException e) {
//                    throw new RuntimeException(e);
//                }
//            });
//
//            t.start();//在该服务器类的成员属性中添加上线程池//将处理连接对象的任务通过submit添加到线程池的阻塞队列中(线程池中的线程会将添加到阻塞队列中的任务进行处理)executorService.submit(new Runnable() {@Overridepublic void run() {try {handleConnection(socket);} catch (IOException e) {throw new RuntimeException(e);}}});}}//处理客户端和服务器之间的连接,并且完成数据的接收,处理,回应public void handleConnection(Socket socket) throws IOException {System.out.printf("客户端上线 %s %d\n",socket.getInetAddress().toString(),socket.getPort());//由于TCP协议的网络编程,进行数据传输的基本单位是字节,所以需要inputstream和outputstream类型的对象来处理字节流的数据//socket网络连接对象可以直接实例化InputStream和OutputStream对象来对网络要传输的字节数据进行处理//采用try(){}的结构,在()中实例化inputStream和outputStream对象,可以在{}中的程序执行结束了以后自动关闭这两个对象(防止内存泄漏)try(InputStream inputStream=socket.getInputStream();OutputStream outputStream=socket.getOutputStream()){//处理客户端传来的请求//客户端传来的请求可能不止一个,所以需要一直死循环去一直读取客户端传来的请求while (true){//InputStream直接使用不是很方便,包装一层Scanner使用Scanner scanner=new Scanner(inputStream);//当没有读取到请求了(客户端传来的请求读取完了)就跳出循环,结束方法,去拿下一个网络连接对象进行处理//当客户端还没有传入请求时就会进入阻塞等待,直到客户端传入请求或客户端下线才恢复if(!scanner.hasNext()){//只有当客户端下线才会执行这段代码System.out.printf("%s %d客户端下线",socket.getInetAddress().toString(),socket.getPort());break;}//客户端中还有请求,读取客服端的请求到request字符串中//这里默认了客户端传来的请求是字符串,按照字符串的形式来处理请求String request=scanner.next();//对客户端传来的请求进行处理并作出响应String response=handle(request);//将响应传递给客户端//直接使用outputStream比较麻烦,包装一层PrintWriter进行使用PrintWriter printWriter=new PrintWriter(outputStream);//要调用println方法将回应传递给客户端才行,因为println方法在传递了一个回应后会换行,而在客户端中就刚好可以用next方法读取//(next方法不会读取空白符,而换行属于空白符)printWriter.println(request);//由于IO操作很消耗资源,所以在调用println方法向客户端发送数据时会先将数据放到一个内存缓冲区中,等到有一定的内容再一起发送//所以为了保证回应被及时的发到客户端,就要对内存缓冲区进行刷新printWriter.flush();//写日志,方便观察当前运行状态System.out.printf("[%s,%d] request:%s response:%s\n",socket.getInetAddress().toString(),socket.getPort(),request,response);}} catch (IOException e) {throw new RuntimeException(e);}finally {  //Socket连接对象会被不停的从serverSocket对象中取出,所以在使用完毕Socket连接对象以后应该调用close方法关闭,否则会出现内存泄漏socket.close();}}//对客户端传来的请求进行处理public String handle(String request){return request;}public static void main(String[] args) throws IOException {TcpEchoServer tcpEchoServer=new TcpEchoServer(1010);tcpEchoServer.start();}
}

客户端代码

package TcpEcho;import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.Socket;
import java.util.Scanner;/*** Created with IntelliJ IDEA.* Description:* User: wuyulin* Date: 2023-08-10* Time: 19:26*/
//TCP回显客户端
public class TcpEchoClient {//客户端需要实例化一个连接对象Socket来实现客户端与服务器之间的数据交互Socket socket=null;//在实例化连接对象Socket时需要服务器的ip地址和端口号TcpEchoClient(String serverIp,int serverPort) throws IOException {socket=new Socket(serverIp,serverPort);}public void start(){//写日志,方便观察当前运行状态System.out.println("客户端启动");//TCP协议进行网络编程传递数据的基本单位是字节,所以需要用到InputStream和OutputStream的对象来进行数据的传输//通过连接对象即可实例化InputStream和OutputStream的对象try(InputStream inputStream=socket.getInputStream();OutputStream outputStream=socket.getOutputStream();){//客户端需要不停的读取客户输入的请求,所以要用循环while (true){Scanner scanner=new Scanner(System.in);//读取用户的请求System.out.println("->");String request=scanner.next();//将用户的请求发送给服务器//直接使用outputStream不方便,包装一层PrintWriter使用PrintWriter printWriter=new PrintWriter(outputStream);printWriter.println(request);//由于IO操作很消耗资源,所以在调用println方法向客户端发送数据时会先将数据放到一个内存缓冲区中,等到有一定的内容再一起发送//所以为了保证请求被及时的发到服务器,就要对内存缓冲区进行刷新printWriter.flush();//接收服务器处理后的回应//直接使用inputStream不方便,包装一层Scanner使用Scanner inputScanner=new Scanner(inputStream);String response=inputScanner.next();//将回应打印到控制台System.out.println(response);}} catch (IOException e) {throw new RuntimeException(e);}}public static void main(String[] args) throws IOException {TcpEchoClient tcpEchoClient=new TcpEchoClient("127.0.0.1",1010);tcpEchoClient.start();}
}

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

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

相关文章

基于Gradio的GPT聊天程序

网上很多别人写的,要用账号也不放心。就自己写了一个基于gradio的聊天界面,部署后可以本地运行。 特点: 可以用openai的,也可以用api2d,其他api可以自己测试一下。使用了langchain的库 可以更改模型,会的…

【调整奇数偶数顺序】

调整奇数偶数顺序 1.题目 输入一个整数数组,实现一个函数, 来调整该数组中数字的顺序使得数组中所有的奇数位于数组的前半部分, 所有偶数位于数组的后半部分。 2.题目分析 这道题首先用到的方法是冒泡排序的思想,首先通过冒泡排序…

时序预测 | MATLAB实现BO-BiLSTM贝叶斯优化双向长短期记忆神经网络时间序列预测

时序预测 | MATLAB实现BO-BiLSTM贝叶斯优化双向长短期记忆神经网络时间序列预测 目录 时序预测 | MATLAB实现BO-BiLSTM贝叶斯优化双向长短期记忆神经网络时间序列预测效果一览基本介绍模型搭建程序设计参考资料 效果一览 基本介绍 MATLAB实现BO-BiLSTM贝叶斯优化双向长短期记忆…

Linux下C语言调用libcurl库获取天气预报信息

一、概述 当前文章介绍如何在Linux(Ubuntu)下使用C语言调用libcurl库获取天气预报的方法。通过HTTP GET请求访问百度天气API,并解析返回的JSON数据,可以获取指定城市未来7天的天气预报信息。 二、设计思路 【1】使用libcurl库进…

【算法题】2561. 重排水果

题目: 你有两个果篮,每个果篮中有 n 个水果。给你两个下标从 0 开始的整数数组 basket1 和 basket2 ,用以表示两个果篮中每个水果的成本。 你希望两个果篮相等。为此,可以根据需要多次执行下述操作: 选中两个下标 i…

用MariaDB创建数据库,SQL练习,MarialDB安装和使用

前言:MariaDB数据库管理系统是MySQL的一个分支,主要由开源社区在维护,采用GPL授权许可 MariaDB的目的是完全兼容MySQL,包括API和命令行,使之能轻松成为MySQL的代替品。在存储引擎方面,使用XtraDB来代替MySQ…

Electron+vue3项目使用SQLite3数据库

SQLite 是一个进程内的库,实现了自给自足的、无服务器的、零配置的、事务性的 SQL 数据库引擎。它是一个零配置的数据库,这意味着与其他数据库不一样,我们不需要在系统中配置。 就像其他数据库,SQLite 引擎不是一个独立的进程&am…

Scratch 之 如何矢量图中去除矢量刺

如果您曾经在“矢量编辑器”中使用过轮廓,那么您一定已经看到了这一点... 这被称为矢量刺,只有当你正在绘制的形状中有尖锐的点或角时才会发生这种情况,这真的很烦人😡 所以在这个视频中,我将向你展示如何摆脱这些令人…

Springboot后端通过路径映射获取本机图片资源

项目场景: 项目中对图片的处理与查看是必不可少的,本文将讲解如何通过项目路径来获取到本机电脑的图片资源 如图所示,在我的本机D盘的图片测试文件夹(文件夹名字不要有中文)下有一些图片, 我们要在浏览器上访问到这些图片&#…

Matlab实现神经网络SOM算法(附上完整仿真源码)

神经网络SOM算法是一种基于自组织的无监督学习算法,其全称为Self-Organizing Map,可以用来对数据进行聚类和可视化。本文将介绍如何使用Matlab实现神经网络SOM算法。 文章目录 一、准备工作二、数据准备三、SOM算法实现四、聚类结果分析五、总结六、完整…

在时间和频率域中准确地测量太阳黑子活动及使用信号处理工具箱(TM)生成广泛的波形,如正弦波、方波等研究(Matlab代码实现)

💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…

python压缩pdf文件大小

pdf文件过大,经常会是一个问题,但是市面上基本上都是收费的工具,wps需要开会员才能使用。因此找了一个python库进行试验: 首先需要安装 pip install aspose-pdf 运行的代码: import aspose.pdf as apcompressPdfDo…

你的服务器安全吗?--服务器防渗透

1、概述 在本人所处的公司的服务器正式遭到黑客攻击之前,一直都以为 黑客 是个遥不可及的词,直到真正成为了受害者时,才猛然意识到安全的重要性。有一些基本经验和心得总结出来,和同行分享一下吧。 2、暴破手段 最粗暴的黑客行为…

篇十八:状态模式:状态驱动的行为

篇十八:"状态模式:状态驱动的行为" 开始本篇文章之前先推荐一个好用的学习工具,AIRIght,借助于AI助手工具,学习事半功倍。欢迎访问:http://airight.fun/。 另外有2本不错的关于设计模式的资料&…

什么是敏捷开发?

敏捷开发流程:制度化、规范化地PUA程序员的顶级神器!!!

SQL | 使用函数处理数据

8-使用函数处理数据 8.1-函数 SQL可以用函数来处理数据。函数一般是在数据上执行的,为数据的转换和处理提供了方便。 8.1.1 函数带来的问题 每种DBMS都有特定的函数,只有很少一部分函数,是被所有主要的DBMS等同的支持。 虽然所有的类型的…

设计模式十四:责任链模式(Chain of Responsibility Pattern)

责任链模式(Chain of Responsibility Pattern)是一种行为设计模式,它允许你将请求沿着处理者链进行传递,直到有一个处理者能够处理该请求。 在责任链模式中,多个处理者对象被连接成一个链。当接收到一个请求时&#xf…

【C++】C++异常

文章目录 1. C语言传统处理错误的方式2. C异常的概念3. 异常的使用3.1 异常的抛出和捕获3.2 异常的重新抛出3.3 异常安全3.4 异常规范 4. C标准库的异常体系5. 自定义的异常体系6. 异常的优缺点 1. C语言传统处理错误的方式 C语言传统的错误处理机制有两个: 终止程…

SQL注入漏洞

SQL注入漏洞是一种常见的网络安全漏洞,它允许攻击者通过在应用程序中插入恶意的SQL代码来执行未经授权的数据库操作。这可能导致敏感数据泄露、数据损坏或完全接管系统的风险。 SQL注入漏洞的原理是应用程序未能正确验证和过滤用户输入的数据,而直接将用…

华为、阿里巴巴、字节跳动 100+ Python 面试问题总结(七)

系列文章目录 个人简介:机电专业在读研究生,CSDN内容合伙人,博主个人首页 Python面试专栏:《Python面试》此专栏面向准备面试的2024届毕业生。欢迎阅读,一起进步!🌟🌟🌟 …