当前位置: 首页 > news >正文

【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() {@Overridepublic 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");}@Overridepublic String process(String request) {return map.getOrDefault(request,"该词汇没有查询到");}public static void main(String[] args) throws IOException {tcpDictServer tcpDictServer = new tcpDictServer(9999);tcpDictServer.start();}
}

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 【chatgpt消费者偏好】是什么驱动了游客持续旅游意愿?推文分享—2024-07-08
  • 2024.7.10 刷题总结
  • Qt基础 | Qt Creator的基本介绍与使用 | 在Visual Studio中创建Qt项目
  • BUG解决:postman可以请求成功,但Python requests请求报403
  • 开源模型应用落地-Yi模型小试-开源模型 vs 闭源模型(四)
  • VSCode设置好看清晰的字体!中文用鸿蒙,英文用Jetbrains Mono
  • 【机器学习】12.十大算法之一支持向量机(SVM - Support Vector Machine)算法原理讲解
  • Unity之VS脚本自动添加头部注释Package包开发
  • 昇思25天训练营Day11 - 基于 MindSpore 实现 BERT 对话情绪识别
  • 坑2.Date类型的请求参数
  • Mysql中常用函数的使用示例
  • Python 视频的色彩转换
  • RedisTemplate使用
  • vue实例和容器的一夫一制——04
  • 【项目实战】深入解析HTTP状态码:500 Internal Server Error
  • 2017届校招提前批面试回顾
  • 5分钟即可掌握的前端高效利器:JavaScript 策略模式
  • Babel配置的不完全指南
  • Fabric架构演变之路
  • IDEA 插件开发入门教程
  • Java Agent 学习笔记
  • javascript从右向左截取指定位数字符的3种方法
  • Java教程_软件开发基础
  • 关于使用markdown的方法(引自CSDN教程)
  • 利用jquery编写加法运算验证码
  • 排序(1):冒泡排序
  • 批量截取pdf文件
  • 如何优雅的使用vue+Dcloud(Hbuild)开发混合app
  • 正则表达式小结
  • Redis4.x新特性 -- 萌萌的MEMORY DOCTOR
  • ​RecSys 2022 | 面向人岗匹配的双向选择偏好建模
  • ​学习笔记——动态路由——IS-IS中间系统到中间系统(报文/TLV)​
  • # 日期待t_最值得等的SUV奥迪Q9:空间比MPV还大,或搭4.0T,香
  • #70结构体案例1(导师,学生,成绩)
  • #每日一题合集#牛客JZ23-JZ33
  • (MTK)java文件添加简单接口并配置相应的SELinux avc 权限笔记2
  • (pt可视化)利用torch的make_grid进行张量可视化
  • (不用互三)AI绘画工具应该如何选择
  • (二开)Flink 修改源码拓展 SQL 语法
  • (附源码)php投票系统 毕业设计 121500
  • (附源码)ssm基于jsp的在线点餐系统 毕业设计 111016
  • (回溯) LeetCode 46. 全排列
  • (论文阅读22/100)Learning a Deep Compact Image Representation for Visual Tracking
  • (三分钟)速览传统边缘检测算子
  • (十三)Flink SQL
  • (四)汇编语言——简单程序
  • (一)spring cloud微服务分布式云架构 - Spring Cloud简介
  • (一)utf8mb4_general_ci 和 utf8mb4_unicode_ci 适用排序和比较规则场景
  • (一)十分简易快速 自己训练样本 opencv级联haar分类器 车牌识别
  • (译) 函数式 JS #1:简介
  • (正则)提取页面里的img标签
  • (转)微软牛津计划介绍——屌爆了的自然数据处理解决方案(人脸/语音识别,计算机视觉与语言理解)...
  • .bat批处理(六):替换字符串中匹配的子串
  • .bat批处理(四):路径相关%cd%和%~dp0的区别
  • .net 程序发生了一个不可捕获的异常