Java中TCP通信的实现方法详解

 更新时间:2023年09月14日 10:32:00   作者:我有健康  
这篇文章主要给大家介绍了关于Java中TCP通信的实现方法,TCP通信能实现两台计算机之间的数据交互,通信的两端,要严格区分为客户端(Client)与服务端(Server),需要的朋友可以参考下

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 建议通信

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

存在的问题:

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

比如下边的情况:

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

总结

到此这篇关于Java中TCP通信的实现方法的文章就介绍到这了,更多相关Java TCP通信实现内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Java实现HDFS文件上传下载

    Java实现HDFS文件上传下载

    这篇文章主要为大家详细介绍了Java实现HDFS文件上传下载,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-06-06
  • Java面向对象的封装你了解吗

    Java面向对象的封装你了解吗

    这篇文章主要为大家详细介绍了Java面向对象的封装,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助
    2022-03-03
  • 解读List list=new ArrayList()是怎么回事

    解读List list=new ArrayList()是怎么回事

    这篇文章主要介绍了解读List list=new ArrayList()是怎么回事,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-06-06
  • Java Swing SpringLayout弹性布局的实现代码

    Java Swing SpringLayout弹性布局的实现代码

    这篇文章主要介绍了Java Swing SpringLayout弹性布局的实现代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-12-12
  • Spring的@Lazy懒加载注解用法详细解析

    Spring的@Lazy懒加载注解用法详细解析

    这篇文章主要介绍了Spring的@Lazy懒加载注解用法详细解析,SpringIoC容器会在启动的时候实例化所有单实例 bean ,如果我们想要实现 Spring 在启动的时候延迟加载 bean,即在首次调用bean的时候再去执行初始化,就可以使用 @Lazy 注解来解决这个问题,需要的朋友可以参考下
    2023-11-11
  • mybatis的foreach标签语法报错的解决

    mybatis的foreach标签语法报错的解决

    这篇文章主要介绍了mybatis的foreach标签语法报错的解决方案,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-02-02
  • java中@JSONField和@JsonProperty注解的使用说明及对比

    java中@JSONField和@JsonProperty注解的使用说明及对比

    @JSONField与@JsonProperty隶属两个不同的包,前者是阿里系的fastjson包,后者是spring boot官方使用的jackson包,本文主要介绍了java中@JSONField和@JsonProperty注解的使用说明及对比,感兴趣的可以了解一下
    2023-11-11
  • java基于线程池和反射机制实现定时任务完整实例

    java基于线程池和反射机制实现定时任务完整实例

    这篇文章主要介绍了java基于线程池和反射机制实现定时任务的方法,以完整实例形式较为详细的分析了Java定时任务的功能原理与实现技巧,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-11-11
  • Java递归遍历文件目录代码实例

    Java递归遍历文件目录代码实例

    这篇文章主要介绍了Java递归遍历文件目录代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-11-11
  • 10个经典的Java main方法面试题

    10个经典的Java main方法面试题

    这篇文章主要为大家分享了10个经典的Java main方法面试题,与其说是Java面试题,其实也是Java的一些最基础知识问题,感兴趣的小伙伴们可以参考一下
    2016-01-01

最新评论