Java中TCP通信的实现

news2024/11/22 9:56:52

0、TCP通信

传输控制协议(TCP,Transmission Control Protocol)是一种面向连接的、可靠的、基于字节流的传输层通信协议,

如果使用了 WireShark 工具,可以看到一次TCP连接建立时的整个过程。

1、单向通信

单向通信中,一方固定为信息发送方,另外一方则固定为信息的接收方。

1.1 单向通信中的服务端

服务端即为信息的接收方。

使用 ServerSocket 类创建服务端,并将服务的端口设置为 9527;

serverSocket.accept() 方法用于监听对 9527 端口的连接,该方法为阻塞式方法,当接收到数据后,程序才会继续向下执行,否则一直处于等待状态;

当接收到数据后,因是使用字节流传输,这里使用 使用 InputStreamReader 的转换流将字节数据转换为字符串,并使用 BufferedReader 进行读取和输出;

当服务端接收到客户端的请求后,需要向客户端发出响应数据,使用 PrintWriter 发送响应报文,需要使用 flush() 方法,将消息发出;

当客户端发出的消息为“再见”时,服务端即退出通信,关闭服务。

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

public class Server {
    public static void main(String[] args) {
        System.out.println("服务器启动!");
        try {
            ServerSocket serverSocket = new ServerSocket(9527);
            Socket socket = serverSocket.accept();
            BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            PrintWriter pw = new PrintWriter(socket.getOutputStream());
            System.out.println("接收客户端消息");

            while (true){
                String in = br.readLine();
                System.out.println("接收到客户端发来的请求:" + in);
                if("再见".equals(in)){
                    break;
                }
                pw.print(in + "回报");
                pw.flush();
            }
        } catch (IOException e) {
            System.out.println("服务启动失败!");
            e.printStackTrace();
        }
    }
}

启动后,服务端输出为:

服务器启动!

1.2 单向通信中的客户端

客户端即为信息的发送方。

  • 创建 Socket 对象,​​Socket("localhost", 9527)​​ 和端口为 9527 的服务建立通信;
  • 接收和发送消息的方法,和服务端相同;
  • 为了能够向服务端循环发送消息,使用了死循环,当用户输入“再见”时,终止循环;
  • 使用 Scanner 对象接收键盘输入。

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;

public class Client {
    public static void main(String[] args) {
        try {
            Socket socket = new Socket("localhost", 9527);
            //读取输入流
            BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            //获取输出流
            PrintWriter pw = new PrintWriter(socket.getOutputStream());
            //从键盘获取输入
            Scanner scanner = new Scanner(System.in);

            while (true){
                //从控制台获取向服务端发送的消息
                String next = scanner.next();
                pw.println(next);
                pw.flush();

                String s = br.readLine();
                System.out.println("收到服务器响应:" + s);

                if("再见".equals(next)){
                    break;
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

1.3 建立通信

启动客户端后,并在客户端的控制台输入“你好”,观察服务端和客户端的控制台

在客户端的控制台输入“再见”,观察服务端和客户端的控制台

2、双向通信

双向通信中,双方都可以既是信息的发送方,也可以是信息的接收方。

2.1 双向通信中的服务端

在服务端设置发消息和收消息。

在服务端也使用了 Scanner ,用来接收控制台输入,并将其发送给客户端。

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;

public class Server {
    public static void main(String[] args) {
        try{
            ServerSocket serverSocket = new ServerSocket(9528);
            Socket socket = serverSocket.accept();
            //获取客户端请求
            BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            //获取键盘输入
            Scanner scanner = new Scanner(System.in);
            //发送消息到客户端
            PrintWriter pw = new PrintWriter(socket.getOutputStream());

            while (true){
                String input = br.readLine();
                System.out.println("收到客户端请求: " + input);
                String output = scanner.nextLine();

                pw.println(output);
                pw.flush();

                if("再见".equals(input)){
                    break;
                }
            }
        }catch (Exception e){
            e.printStackTrace();
            System.out.println("服务启动失败!");
        }
    }
}

2.2 双向通信中的客户端

在客户端设置发消息和收消息

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;

public class Client {
    public static void main(String[] args) {
        try{
            Socket socket = new Socket("127.0.0.1", 9528);
            //获取服务端响应
            BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            //获取客户端用户输入
            Scanner scanner = new Scanner(System.in);
            //向服务端发送请求
            PrintWriter pw = new PrintWriter(socket.getOutputStream());
            System.out.println("准备接收请求……");
            while (true){
                String output = scanner.next();
                pw.println(output);
                pw.flush();

                String input = br.readLine();
                System.out.println("来自服务端的响应: " + input);
                if("再见".equals(output)){
                    break;
                }
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

2.3 建议通信

启动服务端及客户端,并在控制台输入内容:

存在的问题:

这样的通信,需要客户端发一次消息 -》 服务端回一次消息,如果客户端同时发送两条消息,就会导致消息不同步。

比如下边的情况:

这个问题可以先思考下,应该如何解决,后边将会给出解决方案。

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

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

相关文章

案例01-tlias智能学习辅助系统01-增删改查+参数传递

目录 1、需求说明:实现对部门表和员工表的增删改查 2、环境搭建 3、部门管理 3.1 查询部门 3.2 前后端联调 3.3 删除部门 3.4 新增部门 3.5 根据ID查询数据 3.5 修改部门 总结(Controller层参数接收): 4、员工管理 4.…

CMIP6:WRF模式动力降尺度、单点降尺度、统计方法区域降尺度

气候变化关系到农业、生态系统、社会经济和人类生存与发展,是当今世界关注的重点问题之一。IPCC(Intergovernmental Panel on Climate Change)第6次评估报告指出,自 20 世纪 50 年代以来,从全球平均气温和海温升高…

一个关于Mybatis和spring的公共组件starter

utils-springboot-starter 介绍使用说明 介绍 一个关于Mybatis和spring的公共组件starter,目前包含以下功能: 接口请求日志SQL执行日志数据自动加解密数据自动脱敏服务治理方面: 接口限流接口熔断降级:CPU、内存、异常数、异常率…

51.网页设计规则#1_字体设计

一些概念 字体排版 排版是安排字体的艺术和技术,以使书面语言在显示时清晰、可读和吸引人。(来自维基百科翻译) serif字体和sans-serif字体 serif字体 ● 创造一个传统/经典的外观和感觉 ● 体现出可信度 ● 适合长文本 sans-serif字体 …

【JavaScript】7.DOM的操作元素

DOM 的操作元素 JavaScript 的 DOM 操作可以改变网页内容、结构和样式,我们可以利用 DOM 操作元素来改变元素里面的内容 、属性等 1. 改变元素内容 element.innerText:从起始位置到终止位置的内容, 但它去除 html 标签, 同时空格和换行也会…

Pytorch深度学习笔记(十)多分类问题

课程推荐:09.多分类问题_哔哩哔哩_bilibili 目录 1. 多分类模型 2. softmax函数模型 3. Loss损失函数 4.实战MNIST Dataset 之前,在逻辑斯蒂回归中我们提到了二分类任务,现在我们讨论多分类问题。 1. 多分类模型 与二分类不同的是多分…

基于C#asp.net心里咨询服务网站系统

功能模块: 主要分为管理员和注册用户,注册用户可以查看所有人发布的心里文章,情感在线问答,查询相似问题,以及进入论坛进行交流(发帖跟帖评论收藏等)后台管理主要是针对个人信息修改 管理员对注…

SpringBoot自动装配机制的原理

自动装配 简单来说,就是自动去把第三方组件的Bean装载到IOC容器里面。不需要开发人员再去写Bean相关的一个配置。 在SpringBoot应用里面,只需要在启动类上去加上SpringBootApplication注解就可以实现自动配置,SpringBootApplication注解它是…

DSPC174 3BSE005461R1码垛工业机器人安装调试的13个步骤

​ DSPC174 3BSE005461R1码垛工业机器人安装调试的13个步骤 ABB码垛工业机器人安装调试的13个步骤 最近工业机器人市场上,调试工作比较火爆,单个项目动辄几十台机器人同时调试,开出的日薪达到1500-2000元。拥有如此庞大的市场需求和丰厚收入…

Hudi数据湖技术之核心概念

目录 1 基本概念1.1 时间轴Timeline1.2 文件管理1.3 索引Index 2 存储类型2.1 计算模型2.1.1 批式模型(Batch)2.1.2 流式模型(Stream)2.1.3 增量模型(Incremental) 2.2 查询类型(Query Type&…

力扣:通过《84.柱状图中最大的矩形》求解《85. 最大矩形》

84. 柱状图中最大的矩形 85. 最大矩形 84.柱状图中最大的矩形&#xff1a; 单调栈求解问题范围&#xff1a; 输出每个数左边第一个比它小的数 单调栈例题&#xff1a; Acwing 830. 单调栈 #include <iostream>using namespace std;const int N 100010; int stk[N],tt …

再多猜一次就爆炸(小黑子误入)

目录 猜数字游戏 游戏设计思路 1.电脑随机生成一个数 2.猜数字 3.输入我是ikun&#xff0c;泰裤辣! 否则电脑将在一分钟后关机 游戏运行效果 源码 代码分析 代码实现关键语句 strcmp() rand()与srand() 时间戳time() 寄语 猜数字游戏 游戏设计思路 1.电脑随机生…

C语言_Printf函数返回值

目录 1. 嵌套结构 2. Printf 函数返回值 在了解Printf 函数的返回值之前&#xff0c;先来了解下什么叫嵌套结构。 1. 嵌套结构 这里直接举个例子进行介绍&#xff1a; strlen 函数计算字符串长度&#xff0c;显然打印的结果是 3 但是如果采用嵌套结构&#xff08;简单来说就…

【深度学习】基于华为MindSpore的手写体图像识别实验

1 实验介绍 1.1 简介 Mnist手写体图像识别实验是深度学习入门经典实验。Mnist数据集包含60,000个用于训练的示例和10,000个用于测试的示例。这些数字已经过尺寸标准化并位于图像中心&#xff0c;图像是固定大小(28x28像素)&#xff0c;其值为0到255。为简单起见&#xff0c;每…

看完这篇文章你就彻底懂啦{保姆级讲解}-----(LeetCode刷题142环形链表II) 2023.4.24

目录 前言算法题&#xff08;LeetCode刷题142环形链表II&#xff09;—&#xff08;保姆级别讲解&#xff09;分析题目&#xff1a;算法思想环形链表II代码&#xff1a;补充 结束语 前言 本文章一部分内容参考于《代码随想录》----如有侵权请联系作者删除即可&#xff0c;撰写…

ESP32设备驱动-LIS3MDL磁场传感器驱动

LIS3MDL磁场传感器驱动 文章目录 LIS3MDL磁场传感器驱动1、LIS3MDL介绍2、硬件准备3、软件准备4、驱动实现1、LIS3MDL介绍 LIS3MDL 具有4/8/12/16 高斯的用户可选满量程。自检功能允许用户在最终应用中检查传感器的功能。该设备可以被配置为生成用于磁场检测的中断信号。 LIS…

Vue 3 第十四章:组件五(内置组件-transitiontransition-group)

文章目录 1. transition组件1.1. 基本用法1.2. css过渡class介绍1.3. 过渡效果命名1.3.1. 基本用法 1.4. 配合自定义动画&#xff08;animation&#xff09;使用1.5. 自定义过渡 class1.6. <Transition>组件生命周期1.7. transition 常用场景 2. transition-group组件2.1…

Java基础(十一)日期时间API

1 JDK8之前&#xff1a;日期时间API 1.1 java.lang.System类的方法 System类提供的public static long currentTimeMillis()&#xff1a;用来返回当前时间与1970年1月1日0时0分0秒之间以毫秒为单位的时间差。 此方法适用于计算时间差。 计算世界时间的主要标准有&#xff1a;…

SCAU 统计学 实验6

要确定不同培训方式对产品组装时间是否有显著影响&#xff0c;我们可以使用单因素方差分析&#xff08;One-way ANOVA&#xff09;。我们将使用以下数据&#xff1a; 培训方式 A 的样本数据 培训方式 B 的样本数据 培训方式 C 的样本数据 显著性水平&#xff08;α&#xff09…

windows下springboot集成ELK

ELK ElasticSearch Logstash Kibana的集合。ELK主要用于日志的集中管理、快速查询和分析。主要是通过 Logstash 将应用系统的日志通过 input 收集&#xff0c;然后通过内部整理&#xff0c;通过 output 输出到 Elasticsearch 中&#xff0c;其实就是建立了一个 index&#x…