【网络编程】TCP流套接字编程(TCP实现回显服务器)

2024-04-21 03:36

本文主要是介绍【网络编程】TCP流套接字编程(TCP实现回显服务器),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一.TCP流套字节相关API.

Socket(既能给客户端使用,也能给服务器使用)

构造方法

在这里插入图片描述

基本方法:

在这里插入图片描述

ServerSocket(只能给服务器使用)

构造方法:

在这里插入图片描述

基本方法:

在这里插入图片描述

二.TCP实现回显服务器.

客户端代码示例:

package Demo2;import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;public class TcpEchoClient {private Socket clientSocket =null;public TcpEchoClient(String serverIp,int serverPort) throws IOException {//此处可以把这里的IP和port直接传给socket对象.//由于TCP是有连接的,所以socket中就会保存好这两个信息.clientSocket = new Socket(serverIp,serverPort);}public void start(){System.out.println("客户端启动~~");try(InputStream inputStream = clientSocket.getInputStream();OutputStream outputStream = clientSocket.getOutputStream()) {Scanner scannerConsole = new Scanner(System.in);//从控制台读取数据Scanner scannerNetWork = new Scanner(inputStream);//while(true){//1.从控制台读取数据.System.out.println("->");if(!scannerConsole.hasNext()){break;}String request = scannerConsole.next();PrintWriter printWriter = new PrintWriter(outputStream);//2.把请求发送给服务器. 这里要使用println来发送.为了让发送的请求末尾带有一个换行.printWriter.println(request);//通过flush来主动刷新缓冲区,来确保数据发送到服务器了.printWriter.flush();//3.从服务器读取响应.这里也是和服务器返回响应的逻辑想对应String response = scannerNetWork.next();//4.把响应打印到控制台.System.out.println(response);}} catch (IOException e) {throw new RuntimeException(e);}}public static void main(String[] args) throws IOException {TcpEchoClient client = new TcpEchoClient("127.0.0.1",9090);client.start();}
}

服务器代码示例:

package Demo2;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;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();while(true) {//通过accept方法来接听电话,然后才能进行通信.Socket clientSocket = serverSocket.accept();
//            Thread thread = new Thread(()->{
//                processConnection(clientSocket);
//            });
//            thread.start();pool.submit(new Runnable() {@Overridepublic void run() {processConnection(clientSocket);}});}}//通过这个方法来处理一次连接,连接过程中就会涉及请求响应交互public void processConnection(Socket clientSocket){System.out.printf("[%s:%d] 客户端上线!\n",clientSocket.getInetAddress(),clientSocket.getPort());//循环读取客户端的请求并返回响应try(InputStream inputStream = clientSocket.getInputStream();OutputStream outputStream = clientSocket.getOutputStream()) {Scanner scanner = new Scanner(inputStream);while(true){//可以通过inputStream来读取数据了.//byte[] buffer = new byte[4096];//int n = inputStream.read(buffer);//此处读操作完全可以用read来完成,但是read是把读取到的数据放到一个byte数组之中//后续根据请求处理响应,还需要把数组转化成字符串.//此时就可以使用Scanner来简化这个过程.if(!scanner.hasNext()){//读取完毕,例如客户端断开链接.System.out.printf("[%s %d] 客户端下线!\n",clientSocket.getInetAddress(),clientSocket.getPort());break;}//1.读取请求并解析,此时有一个隐藏的约定,next读的时候要读到空白符才会结束//  因此就要求客户端发来的请求必须带有空白符结尾.比如带有/n或" ".String request = scanner.next();//2.根据请求计算响应.String response = process(request);//3.把相应给客户端.//outputStream.write(response.getBytes(),0,response.getBytes().length);//  通过这种方式可以返回,但是这种方式不方便给返回的响应中添加换行//  此时就可以给outputStream套一层来完成更方便的写入.PrintWriter printWriter = new PrintWriter(outputStream);printWriter.println(response);printWriter.flush();System.out.printf("[%s %d] request : %s ;response : %s ",clientSocket.getInetAddress(),clientSocket.getPort(),request,response);System.out.println();}} catch (IOException e) {throw new RuntimeException(e);}finally {try {clientSocket.close();} catch (IOException e) {throw new RuntimeException(e);}}}public String process(String request){return request;}public static void main(String[] args) throws IOException {TcpEchoServer server = new TcpEchoServer(9090);server.start();}
}

运行结果:
在这里插入图片描述
在这里插入图片描述

代码执行流程:

  1. 服务器启动,阻塞在accept,等待客户端建立连接.
    在这里插入图片描述
  2. 客户端启动.这里的new操作会触发和服务器之间建立连接的操作.此时服务器就会从accept中返回.
    在这里插入图片描述
  3. 服务器解除阻塞,继续向下执行,执行processConnection方法
    在这里插入图片描述执行这个方法,执行到hasNext就会阻塞,此时虽然建立了连接,但是客户端还没有发来任何请求.hasNext阻塞等待到请求到达.
  4. 客户端继续执行到hasNext,等待用户向客户端写入内容.
    在这里插入图片描述
  5. 如果用户真的输入了,就会继续向下执行发送请求等待返回的逻辑.
    在这里插入图片描述这里就会把请求真的发出去,同时客户端等待服务器返回响应,此时next就会阻塞等待.
  6. 服务器从hasNext 返回读取到的请求,构造响应,并把响应返回给客户端.
    在这里插入图片描述此时服务器结束此次循环,开启下一次循环,继续阻塞在hasNext等待下一个请求
  7. 客户端读取到响应,并显示出来.
    在这里插入图片描述此时客户端就会结束此次循环,开启下一次循环,继续阻塞在hasNext等待用户输入下一个请求.

代码注意事项:

    1. flush()方法存在一个内存缓冲区.由于文件IO的操作比较低效,因此就希望IO的次数少一些,等攒到一定程度再进行IO操作.(相当于多次IO合并成一次了). 因此就引入了缓冲区,此时就会出现问题,你输入的数据比较少,数据被存在内存缓冲区了,所以需要我们手动刷新缓冲区.
    1. 如果客户端非常的多,就需要创建多个Socket对象,此时就可能导致系统的资源使用完了,因此需要在Socket执行完毕之后关闭资源.
    1. 引入线程池来解决频繁的创建销毁线程.
    1. 如果有多个客户端建立请求,并且长时间不销毁
    • 解决方案一:引入协程===>轻量级线程,用户态可以通过手动调度的方式让一个线程并发的做多个任务.
    • 解决方案二:IO多路复用===>这是一个系统内核级别的机制,本质上是让一个线程去处理多个Socket对象 (这些Socket数据并非是同一时刻都需要处理).

这篇关于【网络编程】TCP流套接字编程(TCP实现回显服务器)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!


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

相关文章

Python实现批量提取BLF文件时间戳

《Python实现批量提取BLF文件时间戳》BLF(BinaryLoggingFormat)作为Vector公司推出的CAN总线数据记录格式,被广泛用于存储车辆通信数据,本文将使用Python轻松提取... 目录一、为什么需要批量处理 BLF 文件二、核心代码解析:从文件遍历到数据导出1. 环境准备与依赖库

linux下shell脚本启动jar包实现过程

《linux下shell脚本启动jar包实现过程》确保APP_NAME和LOG_FILE位于目录内,首次启动前需手动创建log文件夹,否则报错,此为个人经验,供参考,欢迎支持脚本之家... 目录linux下shell脚本启动jar包样例1样例2总结linux下shell脚本启动jar包样例1#!/bin

go动态限制并发数量的实现示例

《go动态限制并发数量的实现示例》本文主要介绍了Go并发控制方法,通过带缓冲通道和第三方库实现并发数量限制,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面... 目录带有缓冲大小的通道使用第三方库其他控制并发的方法因为go从语言层面支持并发,所以面试百分百会问到

Go语言并发之通知退出机制的实现

《Go语言并发之通知退出机制的实现》本文主要介绍了Go语言并发之通知退出机制的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录1、通知退出机制1.1 进程/main函数退出1.2 通过channel退出1.3 通过cont

Python实现PDF按页分割的技术指南

《Python实现PDF按页分割的技术指南》PDF文件处理是日常工作中的常见需求,特别是当我们需要将大型PDF文档拆分为多个部分时,下面我们就来看看如何使用Python创建一个灵活的PDF分割工具吧... 目录需求分析技术方案工具选择安装依赖完整代码实现使用说明基本用法示例命令输出示例技术亮点实际应用场景扩

java如何实现高并发场景下三级缓存的数据一致性

《java如何实现高并发场景下三级缓存的数据一致性》这篇文章主要为大家详细介绍了java如何实现高并发场景下三级缓存的数据一致性,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 下面代码是一个使用Java和Redisson实现的三级缓存服务,主要功能包括:1.缓存结构:本地缓存:使

如何在Java Spring实现异步执行(详细篇)

《如何在JavaSpring实现异步执行(详细篇)》Spring框架通过@Async、Executor等实现异步执行,提升系统性能与响应速度,支持自定义线程池管理并发,本文给大家介绍如何在Sprin... 目录前言1. 使用 @Async 实现异步执行1.1 启用异步执行支持1.2 创建异步方法1.3 调用

Spring Boot配置和使用两个数据源的实现步骤

《SpringBoot配置和使用两个数据源的实现步骤》本文详解SpringBoot配置双数据源方法,包含配置文件设置、Bean创建、事务管理器配置及@Qualifier注解使用,强调主数据源标记、代... 目录Spring Boot配置和使用两个数据源技术背景实现步骤1. 配置数据源信息2. 创建数据源Be

在MySQL中实现冷热数据分离的方法及使用场景底层原理解析

《在MySQL中实现冷热数据分离的方法及使用场景底层原理解析》MySQL冷热数据分离通过分表/分区策略、数据归档和索引优化,将频繁访问的热数据与冷数据分开存储,提升查询效率并降低存储成本,适用于高并发... 目录实现冷热数据分离1. 分表策略2. 使用分区表3. 数据归档与迁移在mysql中实现冷热数据分

linux批量替换文件内容的实现方式

《linux批量替换文件内容的实现方式》本文总结了Linux中批量替换文件内容的几种方法,包括使用sed替换文件夹内所有文件、单个文件内容及逐行字符串,强调使用反引号和绝对路径,并分享个人经验供参考... 目录一、linux批量替换文件内容 二、替换文件内所有匹配的字符串 三、替换每一行中全部str1为st