Java网络通信TCP

news/2024/4/19 14:28:54/文章来源:https://blog.csdn.net/weixin_57535054/article/details/136437973

目录

TCP两个核心类

服务端

1.用ServerSocker类创建对象并且手动指定端口号

2.accept阻塞连接服务端与客户端

3.给客户端提供处理业务方法

4.处理业务

整体代码

客户端

1.创建Socket对象,并连接服务端的ip与端口号

2.获取Socket流对象,写入数据,阻塞等待服务端响应

整体代码

jconsole用来监控java线程


TCP两个核心类

ServerSocket 服务器使用socket

accept没有参数 返回值是一个Socket对象

功能是等待服务器和客户端建立连接,建立成功后则会把这个连接获取到进程中。接下来就通过Scoket返回的对象来进行交互

Scoket服务器和客户端都使用socket

通过socket对象就可以进行发送接收数据

socket内部包含了输入流对象(接收) 输出流对象 (发送)

服务端

1.用ServerSocker类创建对象并且手动指定端口号

    private ServerSocket serverSocket=null;public Test1(int port) throws IOException {serverSocket=new ServerSocket(port);

2.accept阻塞连接服务端与客户端

当我们用UDP那样连接客户端会出现一个问题

UDP是无连接的,他发送数据时直接用地址端口号发送

而TCP是有连接的,当我们用accept连接时,ProcessConnect方法会一直被循环执行单个客户端,而其他客户端要连接时,无法执行到accept,必须等待ProcessConnect方法执行结束,所以会被阻塞。简单来说就是当有一个客户端连接时,其他客户端必须等待连接的客户端断开连接才能连接,还是一个个来连接。

所以ProcessConnect方法我们直接交给线程去执行,这样其他客户端来连接时,直接让线程去执行处理客户端业务。

所以我们可以用到多线程

既然用到了多线程,就可以用出线程池,效率会更高。

public void start() throws IOException {System.out.println("服务器启动");while (true){//阻塞等待服务器与客户端建立连接Socket socket=serverSocket.accept();//若没线程 当一个客户端连接后 会一直在ProcessConnect内//其他客户端连接时 必须要等待ProcessConnect结束,进入下一次循环,才能执行到Socketsocket=serverSocket.accept(); 才能连接下一个客户端
//           // ProcessConnect(socket);//所以执行处理客户端请求,我们让线程去干,这样就不会在一个线程内阻塞
//            Thread thread=new Thread(()->{
//                try {
//                    ProcessConnect(socket);
//                } catch (IOException e) {
//                    throw new RuntimeException(e);
//                }
//            });
//            thread.start();//线程池ExecutorService executorService= Executors.newCachedThreadPool();executorService.submit(new Runnable() {@Overridepublic void run() {try {ProcessConnect(socket);} catch (IOException e) {throw new RuntimeException(e);}}});}}

3.给客户端提供处理业务方法

我们可以直接获取Socket内的流对象,直接写入读出即可

需要注意,写入数据时,因为时流对象接收,要\n等待其他结束,而我们输入数据时,流对象是不会写入\n的,所以我们可以在数据后自动添加\n 或者用println默认有个\n

public void ProcessConnect(Socket socket) throws IOException {//实际他们交流数据是一个为socket类型的文件System.out.printf("[地址:%s:端口号%d]建立连接成功\n",socket.getInetAddress().toString(),socket.getPort());try (InputStream inputStream = socket.getInputStream();//获取socket内部的input流OutputStream outputStream = socket.getOutputStream())//获取socket内部的output流{Scanner scanner = new Scanner(inputStream);PrintWriter printWriter = new PrintWriter(outputStream);//长连接写法while (true) {if(!scanner.hasNext()){System.out.printf("[地址:%s:端口号%d]断开连接",socket.getInetAddress().toString(),socket.getPort());}//从客户端接收数据String resqust = scanner.next();System.out.println("服务器接收数据");//处理数据String response = process(resqust);System.out.println("服务器处理数据");//因为这用流接收 我们按下换行是被scanner接收但并未添加到数据内 而服务器接收流收到的数据内//是没有换行符的 就会一直阻塞 所以我们要在数据后再加个\n//服务器发送数据//printWriter.write(response+'\n');//或者直接使用println自带\nprintWriter.println(response);System.out.println("服务器发送数据");//刷新缓冲区printWriter.flush();System.out.printf("[地址:%s:端口号:%d]接收数据:%s 响应数据:%s",socket.getInetAddress().toString(),socket.getPort(),resqust,response);}}}

4.处理业务

这里是为了演示TCP连接,所以只写个简单回传

public String process(String s){return s;}

整体代码

package TestTCP;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.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;//服务器
public class Test1 {private ServerSocket serverSocket=null;public Test1(int port) throws IOException {serverSocket=new ServerSocket(port);}public void start() throws IOException {System.out.println("服务器启动");while (true){//阻塞等待服务器与客户端建立连接Socket socket=serverSocket.accept();//若没线程 当一个客户端连接后 会一直在ProcessConnect内//其他客户端连接时 必须要等待ProcessConnect结束,进入下一次循环,// 才能执行到Socketsocket=serverSocket.accept(); 才能连接下一个客户端
//            ProcessConnect(socket);//所以执行处理客户端请求,我们让线程去干,这样就不会在一个线程内阻塞
//            Thread thread=new Thread(()->{
//                try {
//                    ProcessConnect(socket);
//                } catch (IOException e) {
//                    throw new RuntimeException(e);
//                }
//            });
//            thread.start();//线程池ExecutorService executorService= Executors.newCachedThreadPool();executorService.submit(new Runnable() {@Overridepublic void run() {try {ProcessConnect(socket);} catch (IOException e) {throw new RuntimeException(e);}}});}}//给当前客户端提供服务方法public void ProcessConnect(Socket socket) throws IOException {//实际他们交流数据是一个为socket类型的文件System.out.printf("[地址:%s:端口号%d]建立连接成功\n",socket.getInetAddress().toString(),socket.getPort());try (InputStream inputStream = socket.getInputStream();//获取socket内部的input流OutputStream outputStream = socket.getOutputStream())//获取socket内部的output流{Scanner scanner = new Scanner(inputStream);PrintWriter printWriter = new PrintWriter(outputStream);//长连接写法while (true) {if(!scanner.hasNext()){System.out.printf("[地址:%s:端口号%d]断开连接",socket.getInetAddress().toString(),socket.getPort());}//从客户端接收数据String resqust = scanner.next();System.out.println("服务器接收数据");//处理数据String response = process(resqust);System.out.println("服务器处理数据");//因为这用流接收 我们按下换行是被scanner接收但并未添加到数据内 而服务器接收流收到的数据内//是没有换行符的 就会一直阻塞 所以我们要在数据后再加个\n//服务器发送数据//printWriter.write(response+'\n');//或者直接使用println自带\nprintWriter.println(response);System.out.println("服务器发送数据");//刷新缓冲区printWriter.flush();System.out.printf("[地址:%s:端口号:%d]接收数据:%s 响应数据:%s",socket.getInetAddress().toString(),socket.getPort(),resqust,response);}}}public String process(String s){return s;}public static void main(String[] args) throws IOException {Test1 t1=new Test1(8080);t1.start();}
}

客户端

1.创建Socket对象,并连接服务端的ip与端口号

    private Socket socket=null;public Test2() throws IOException {socket=new Socket("127.0.0.1",8080);

2.获取Socket流对象,写入数据,阻塞等待服务端响应

    public void start() throws IOException {try(InputStream inputStream=socket.getInputStream();OutputStream outputStream=socket.getOutputStream()){while (true){Scanner scanner=new Scanner(inputStream);PrintWriter printWriter=new PrintWriter(outputStream);Scanner scanner1=new Scanner(System.in);System.out.println("输入数据>");String requst=scanner1.next();//因为这用流接收 我们按下换行是被scanner接收但并未添加到数据内 而服务器接收流收到的数据内//是没有换行符的 就会一直阻塞 所以我们要在数据后再加个\n//printWriter.write(requst+'\n');//或者直接使用println自带\nprintWriter.println(requst);//刷新缓冲区printWriter.flush();String response=scanner.next();System.out.println(response);}}finally {socket.close();}}

整体代码

package TestTCP;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 Test2 {private Socket socket=null;public Test2() throws IOException {socket=new Socket("127.0.0.1",8080);}public void start() throws IOException {try(InputStream inputStream=socket.getInputStream();OutputStream outputStream=socket.getOutputStream()){while (true){Scanner scanner=new Scanner(inputStream);PrintWriter printWriter=new PrintWriter(outputStream);Scanner scanner1=new Scanner(System.in);System.out.println("输入数据>");String requst=scanner1.next();//因为这用流接收 我们按下换行是被scanner接收但并未添加到数据内 而服务器接收流收到的数据内//是没有换行符的 就会一直阻塞 所以我们要在数据后再加个\n//printWriter.write(requst+'\n');//或者直接使用println自带\nprintWriter.println(requst);//刷新缓冲区printWriter.flush();String response=scanner.next();System.out.println(response);}}finally {socket.close();}}public static void main(String[] args) throws IOException {Test2 t2=new Test2();t2.start();}
}

jconsole用来监控java线程

jconsole在路径 jdk/bin/jconsole.exe

例:

我们需要看util最后一局,可以看出线程是在next阻塞着。

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

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

相关文章

HAproxy

四层: - LVS:Linux Virtual Server - Nginx: - HAProxy:High Availability Proxy 七层: - HAProxy - Nginx 硬件: - F5 https://f5.com/zh- Netscaler https://www.citrix.com.cn/product…

能量不等式证明

波动方程初值问题能量不等式的证明 Gronwall 不等式 若非负函数 G ( τ ) G(\tau) G(τ) 在 [ 0 , T ] [0,T] [0,T] 上连续可微, G ( 0 ) 0 G(0)0 G(0)0,且对 τ ∈ [ 0 , T ] \tau\in[0,T] τ∈[0,T]满足 d G ( τ ) d τ ≤ C G ( τ ) F ( τ …

【PyQt】16-剪切板的使用

文章目录 前言一、代码疑惑快捷键 二、现象2.1 复制粘贴文本复制粘贴 2.2 复制粘贴图片复制粘贴 2.3 复制粘贴网页 总结 前言 1、剪切板的使用 2、pycharm的编译快捷键 3、类的属性和普通变量的关系 4、pyqt应该养成的编程习惯-体现在代码里了,自己看看。 一、代码…

Bert Encoder和Transformer Encoder有什么不同

前言:本篇文章主要从代码实现角度研究 Bert Encoder和Transformer Encoder 有什么不同?应该可以帮助你: 深入了解Bert Encoder 的结构实现深入了解Transformer Encoder的结构实现 本篇文章不涉及对注意力机制实现的代码研究。 注:…

CentOS7 利用remi yum源安装php8.1

目录 前言remi yum源remi yum源 支持的操作系统remi yum源 支持的php版本 安装epel源安装remi源安装 php8.1查看php版本查看php-fpm服务启动php-fpm服务查看php-fpm服务运行状态查看php-fpm服务占用的端口查看 php8.1 相关的应用 前言 CentOS Linux release 7.9.2009 (Core) …

maven项目引入私有jar,并打包到java.jar中

私有jar存放位置 maven依赖 <dependency><groupId>com.hikvision.ga</groupId><artifactId>artemis-http-client</artifactId><version>1.1.10</version><scope>system</scope><systemPath>${project.basedir}/s…

【ETCD】简介安装常用操作---图文并茂详细讲解

目录 一 简介 1.1 etcd是什么 1.2. 特点 1.3. 使用场景 1.4 关键字 1.5 工作原理 二 安装 2.1 etcd安装前介绍 2.2 安装 2.3 启动 2.4 创建一个etcd服务 三 常用操作 一 简介 1.1 etcd是什么 etcd是CoreOS团队于2013年6月发起的开源项目&#xff0c;它的目标是构建…

面向对象中类与对象

思考系统1000个对象逻辑结构 理解系统1000个对象物理结构 对象this 引用 类的静态变量和静态函数 静态变量和静态函数属于类本身&#xff0c;而不是类的实例。它们可以在不创建类的实例的情况下直接通过类名访问。静态变量在内存中只有一份拷贝&#xff0c;被所有实例共享&…

从一个问题开始聊聊clickhouse的物化视图

【问题】 今天有A问我一个问题&#xff0c;我明明创建了一个物化视图&#xff0c;源表是有数据的&#xff0c;为什么查询物化视图就没有数据&#xff1f; 创建物化视图的SQL示意如下&#xff1a; CREATE MATERIALIZED VIEW schema1.test_mvon cluster clusterNameTO schema1…

docker三剑客compose+machine+swarm小结

背景 在容器领域&#xff0c;不少公司会使用docker三剑客composemachineswarm进行容器编排和部署&#xff0c;本文就简单记录下这几个工具的用法 三剑客composemachineswarm compose compose主要是用于容器编排&#xff0c;我们部署容器时&#xff0c;容器之间会有依赖&…

单链表的实现(数据结构)

本篇博客主要是单链表&#xff08;无头单项不循环&#xff09;的实现的代码分享 说明&#xff1a;因为此单链表无头&#xff08;哨兵位&#xff09;&#xff0c;可以说成没有初始化也可以说初始化时没有一个有效地址作为单链表的起始地址 例如下面代码中的plist NULL。 所以在…

神经网络(neural network)

在这一章中我们将进入深度学习算法&#xff0c;学习一些神经网络相关的知识&#xff0c;这些是有更加强大的作用&#xff0c;更加广泛的用途。 神经元和大脑(neurons and the brain): 我们对于我们的编程的进步主要来自我们对于大脑的研究&#xff0c;根据我们对于大脑的研究…

9*9乘法表

单层循环 99乘法表 动手写写画画整个程序的输出结果

Python 读取写入excel文件

使用Python读取和写入excel的xlsx、xls文件 目录 读取xlsx文件 安装三方库 引入三方库 读取数据 打开文件 表名 最大行数 最大列数 读取一张表 读取整个文件 返回xls整体内容 安装三方包 读取内容 写入xls文件 引入三方库 创建文件并写入数据 报错及解决 报错…

Vue.js+SpringBoot开发无代码动态表单系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 动态类型模块2.2 动态文件模块2.3 动态字段模块2.4 动态值模块 三、系统设计3.1 用例设计3.2 数据库设计3.2.1 动态类型表3.2.2 动态文件表3.2.3 动态字段表3.2.4 动态值表 四、系统展示五、核心代码5.1 查询档案类型5.…

电脑不小心格式化了,怎么恢复?

在这个数字化时代&#xff0c;电脑已经成为我们日常生活和工作中不可或缺的工具。然而&#xff0c;有时我们可能会不小心格式化电脑硬盘&#xff0c;导致重要数据的丢失。那么&#xff0c;电脑不小心格式化了&#xff0c;怎么恢复&#xff1f; 别着急&#xff0c;在本篇攻略中&…

unicloud 云数据库概念及创建一个云数据库表并添加记录(数据)

云数据库概念 uniCloud提供了一个 JSON 格式的文档型数据库。顾名思义&#xff0c;数据库中的每条记录都是一个 JSON 格式的文档。 它是 nosql 非关系型数据库&#xff0c;如果您之前熟悉 sql 关系型数据库&#xff0c;那么两者概念对应关系如下表&#xff1a; 关系型JSON 文…

基于React的低代码开发:探索应用构建的新模式

&#x1f308;个人主页: Aileen_0v0 &#x1f525;热门专栏: 华为鸿蒙系统学习|计算机网络|数据结构与算法|MySQL| ​&#x1f4ab;个人格言:“没有罗马,那就自己创造罗马~” #mermaid-svg-OywB1Epu30PrvOJQ {font-family:"trebuchet ms",verdana,arial,sans-serif;f…

智慧农业5G融合方案(2)

应用场景 农业航空 农业农村部资料显示,植保无人机具有机动灵活、喷施效率高、施药效果好等特点,能够克服复杂地形条件下地面喷雾机具进地难的问题。目前我国有400多家企业从事植保无人机研发、生产、销售等全产业链业务。主要机型以电动多旋翼为主。2018年作业面积约2.67亿…

ElasticSearch之文档的存储

写在前面 本文看下文档的存储相关内容。 1&#xff1a;如何确定文档存储在哪个分片&#xff1f; 我们需要确保文档均匀分布在所有的分片中&#xff0c;避免某些部分机器空闲&#xff0c;部分机器繁忙的情况出现&#xff0c;想要实现均匀分布我们可以考虑如下的几种分片路由算…