Java基础——TCP通信

news2024/12/23 18:14:12

(1)TCP协议特点:

  • TCP是一种面向连接,安全,可靠的传输数据的协议
  • 传输前,采用“三次握手”方式,点对点通信,是可靠的
  • 在连接中可进行大数据量的传输

(2) TCP通信模式:(在java中只需使用java.net.Socket类实现通信,底层即是使用了TCP协议)

2.1:一发一收

客户端 (一发一收)

import java.io.OutputStream;
import java.io.PrintStream;
import java.net.Socket;

/**
   目标:完成Socket网络编程入门案例的客户端开发,实现1发1收。
 */
public class ClientDemo1 {
    public static void main(String[] args) {
        try {
            System.out.println("====客户端启动===");
            // 1、创建Socket通信管道请求有服务端的连接
            // public Socket(String host, int port)
            // 参数一:服务端的IP地址
            // 参数二:服务端的端口
            Socket socket = new Socket("127.0.0.1", 7777);

            // 2、从socket通信管道中得到一个字节输出流 负责发送数据
            OutputStream os = socket.getOutputStream();

            // 3、把低级的字节流包装成打印流
            PrintStream ps = new PrintStream(os);

            // 4、发送消息
            ps.println("我是TCP的客户端,我已经与你对接,并发出邀请:约吗?");
            ps.flush();

            // 关闭资源。
            // socket.close();

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

服务端(一发一收)

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;

/**
   目标:开发Socket网络编程入门代码的服务端,实现接收消息
 */
public class ServerDemo2 {
    public static void main(String[] args) {
        try {
            System.out.println("===服务端启动成功===");
            // 1、注册端口
            ServerSocket serverSocket = new ServerSocket(7777);
            // 2、必须调用accept方法:等待接收客户端的Socket连接请求,建立Socket通信管道
            Socket socket = serverSocket.accept();
            // 3、从socket通信管道中得到一个字节输入流
            InputStream is = socket.getInputStream();
            // 4、把字节输入流包装成缓冲字符输入流进行消息的接收
            BufferedReader br = new BufferedReader(new InputStreamReader(is));
            // 5、按照行读取消息
            String msg;
            if ((msg = br.readLine()) != null){
                System.out.println(socket.getRemoteSocketAddress() + "说了:: " + msg);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

2.2:多发多收(单线程)

注意:目前的服务端不可以同时接收多个客户端的信息,因为目前服务端现在只有一个线程,只能与一个客户端进行通信。

客户端(多发多收:单线程,使用循环反复地发送消息)

import java.io.OutputStream;
import java.io.PrintStream;
import java.net.Socket;
import java.util.Scanner;

/**
   目标:实现多发和多收
 */
public class ClientDemo1 {
    public static void main(String[] args) {
        try {
            System.out.println("====客户端启动===");
            // 1、创建Socket通信管道请求有服务端的连接
            // public Socket(String host, int port)
            // 参数一:服务端的IP地址
            // 参数二:服务端的端口
            Socket socket = new Socket("127.0.0.1", 7777);

            // 2、从socket通信管道中得到一个字节输出流 负责发送数据
            OutputStream os = socket.getOutputStream();

            // 3、把低级的字节流包装成打印流
            PrintStream ps = new PrintStream(os);

            Scanner sc =  new Scanner(System.in);
            while (true) {
                System.out.println("请说:");
                String msg = sc.nextLine();
                // 4、发送消息
                ps.println(msg);
                ps.flush();
            }

            // 关闭资源。
            // socket.close();

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

服务端(多发多收:单线程,使用循环反复的接收消息)

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;

/**
   目标:开发Socket网络编程入门代码的服务端,实现接收消息
 */
public class ServerDemo2 {
    public static void main(String[] args) {
        try {
            System.out.println("===服务端启动成功===");
            // 1、注册端口
            ServerSocket serverSocket = new ServerSocket(7777);
            while (true) {
                // 2、必须调用accept方法:等待接收客户端的Socket连接请求,建立Socket通信管道
                Socket socket = serverSocket.accept();
                // 3、从socket通信管道中得到一个字节输入流
                InputStream is = socket.getInputStream();
                // 4、把字节输入流包装成缓冲字符输入流进行消息的接收
                BufferedReader br = new BufferedReader(new InputStreamReader(is));
                // 5、按照行读取消息
                String msg;
                while ((msg = br.readLine()) != null){
                    System.out.println(socket.getRemoteSocketAddress() + "说了:: " + msg);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

2.3:多发多收(多线程)

客户端(多发多收:多线程) 

import java.io.OutputStream;
import java.io.PrintStream;
import java.net.Socket;
import java.util.Scanner;

/**
    目标:实现服务端可以同时处理多个客户端的消息。
 */
public class ClientDemo3 {
    public static void main(String[] args) {
        try {
            System.out.println("====客户端启动===");
            // 1、创建Socket通信管道请求有服务端的连接
            // public Socket(String host, int port)
            // 参数一:服务端的IP地址
            // 参数二:服务端的端口
            Socket socket = new Socket("127.0.0.1", 7777);

            // 2、从socket通信管道中得到一个字节输出流 负责发送数据
            OutputStream os = socket.getOutputStream();

            // 3、把低级的字节流包装成打印流
            PrintStream ps = new PrintStream(os);

            Scanner sc =  new Scanner(System.in);
            while (true) {
                System.out.println("请说:");
                String msg = sc.nextLine();
                // 4、发送消息
                ps.println(msg);
                ps.flush();
            }

            // 关闭资源。
            // socket.close();

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

服务端(多发多收:多线程) 

import java.net.ServerSocket;
import java.net.Socket;

/**
   目标:实现服务端可以同时处理多个客户端的消息。
 */
public class ServerDemo3 {
    public static void main(String[] args) {
        try {
            System.out.println("===服务端启动成功===");
            // 1、注册端口
            ServerSocket serverSocket = new ServerSocket(7777);
            // a.定义一个死循环由主线程负责不断的接收客户端的Socket管道连接。
            while (true) {
                // 2、每接收到一个客户端的Socket管道,交给一个独立的子线程负责读取消息
                Socket socket = serverSocket.accept();
                System.out.println(socket.getRemoteSocketAddress()+ "它来了,上线了!");
                // 3、开始创建独立线程处理socket
                new ServerReaderThread(socket).start();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

(定义一个线程类)

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.Socket;

public class ServerReaderThread extends Thread{
    private Socket socket;
    public ServerReaderThread(Socket socket){
        this.socket = socket;
    }
    @Override
    public void run() {
        try {
            // 3、从socket通信管道中得到一个字节输入流
            InputStream is = socket.getInputStream();
            // 4、把字节输入流包装成缓冲字符输入流进行消息的接收
            BufferedReader br = new BufferedReader(new InputStreamReader(is));
            // 5、按照行读取消息
            String msg;
            while ((msg = br.readLine()) != null){
                System.out.println(socket.getRemoteSocketAddress() + "说了:: " + msg);
            }
        } catch (Exception e) {
            System.out.println(socket.getRemoteSocketAddress() + "下线了!!!");
        }
    }
}

2.4:线程池

服务端可以复用线程处理多个客户端,可以避免系统瘫痪。

适合客户端通信时长较短的场景。

客户端(线程池:处理多个客户端消息,解决多线程N-N的关系,导致资源浪费的问题)

import java.io.OutputStream;
import java.io.PrintStream;
import java.net.Socket;
import java.util.Scanner;

/**
    拓展:使用线程池优化:实现通信。
 */
public class ClientDemo4 {
    public static void main(String[] args) {
        try {
            System.out.println("====客户端启动===");
            // 1、创建Socket通信管道请求有服务端的连接
            // public Socket(String host, int port)
            // 参数一:服务端的IP地址
            // 参数二:服务端的端口
            Socket socket = new Socket("127.0.0.1", 6666);

            // 2、从socket通信管道中得到一个字节输出流 负责发送数据
            OutputStream os = socket.getOutputStream();

            // 3、把低级的字节流包装成打印流
            PrintStream ps = new PrintStream(os);

            Scanner sc =  new Scanner(System.in);
            while (true) {
                System.out.println("请说:");
                String msg = sc.nextLine();
                // 4、发送消息
                ps.println(msg);
                ps.flush();
            }
            // 关闭资源。
            // socket.close();

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

 2.8服务端(线程池:处理多个客户端消息,解决多线程N-N的关系,导致资源浪费的问题)

import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.*;

/**
   目标:实现服务端可以同时处理多个客户端的消息。
 */
public class ServerDemo4 {

    // 使用静态变量记住一个线程池对象
    private static ExecutorService pool = new ThreadPoolExecutor(300,
            1500, 6, TimeUnit.SECONDS,
            new ArrayBlockingQueue<>(2)
    , Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());

    public static void main(String[] args) {
        try {
            System.out.println("===服务端启动成功===");
            // 1、注册端口
            ServerSocket serverSocket = new ServerSocket(6666);
            // a.定义一个死循环由主线程负责不断的接收客户端的Socket管道连接。
            while (true) {
                // 2、每接收到一个客户端的Socket管道,
                Socket socket = serverSocket.accept();
                System.out.println(socket.getRemoteSocketAddress()+ "它来了,上线了!");

                // 任务对象负责读取消息。
                Runnable target = new ServerReaderRunnable(socket);
                pool.execute(target);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

(定义一个任务类) 

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.Socket;

public class ServerReaderRunnable implements Runnable{
    private Socket socket;
    public ServerReaderRunnable(Socket socket){
        this.socket = socket;
    }
    @Override
    public void run() {
        try {
            // 3、从socket通信管道中得到一个字节输入流
            InputStream is = socket.getInputStream();
            // 4、把字节输入流包装成缓冲字符输入流进行消息的接收
            BufferedReader br = new BufferedReader(new InputStreamReader(is));
            // 5、按照行读取消息
            String msg;
            while ((msg = br.readLine()) != null){
                System.out.println(socket.getRemoteSocketAddress() + "说了:: " + msg);
            }
        } catch (Exception e) {
            System.out.println(socket.getRemoteSocketAddress() + "下线了!!!");
        }
    }
}

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

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

相关文章

【软考数据库】第七章 关系数据库

目录 7.1 关系数据库概述 7.2 关系代数 7.3 元组演算与域演算 7.4 查询优化 7.5 关系数据库设计 7.6 模式分解 前言&#xff1a; 笔记来自《文老师软考数据库》教材精讲&#xff0c;精讲视频在b站&#xff0c;某宝都可以找到&#xff0c;个人感觉通俗易懂。 7.1 关系数据…

服务端接口优化方案

一、背景 针对老项目&#xff0c;去年做了许多降本增效的事情&#xff0c;其中发现最多的就是接口耗时过长的问题&#xff0c;就集中搞了一次接口性能优化。本文将给小伙伴们分享一下接口优化的通用方案。 二、接口优化方案总结 1. 批处理 批量思想&#xff1a;批量操作数据…

YOLOv5s GTX 1660 Ti训练时出现,box,obj,cla全是nan的问题,Pytorch和cuda、cudnn版本不对

这里写自定义目录标题 参考资料问题描述当前使用版本尝试解决问题版本&#xff08;1&#xff09;尝试解决问题版本&#xff08;2&#xff09;CUDA卸载参考CUDA卸载之后发现依然还在&#xff0c;需要把torch卸载掉。 参考资料 1.Github_YOLOv5_nan问题 2.查看CUDA最高可使用版…

PHP+vue基于web的新闻发布投稿系统评论网站

运行环境:phpstudy/wamp/xammp等 开发语言&#xff1a;php 后端框架&#xff1a;Thinkphp5 前端框架&#xff1a;vue.js 服务器&#xff1a;apache 数据库&#xff1a;mysql 数据库工具&#xff1a;Navicat/phpmyadmin 系统包含了二个用户&#xff0c;即管理员和用户&#xff0…

ThingsBoard使用docker compose集群部署的问题以及如何解决问题

1、问题回顾 接着上一节继续讲解,上一节我们把整个服务全部都运行起来了,但是访问页面报错,最后查看的问题是前端的容易里面报错: 然后执行脚本删除所有的容器 2、问题分析 当遇到这个问题的时候,我当时真的不知道如何去解决,然后我又尝试使用官方的镜像来部署,发现官…

Baumer工业相机堡盟工业相机如何联合BGAPISDK和Halcon实现图像的线性灰度变换ScaleImage算法增强(C#)

Baumer工业相机堡盟工业相机如何联合BGAPISDK和Halcon实现图像的线性灰度变换算法增强&#xff08;C#&#xff09; Baumer工业相机Baumer工业相机使用图像算法增加图像的技术背景Baumer工业相机通过BGAPI SDK联合Halcon使用线性灰度变换增强算法1.引用合适的类文件2.BGAPI SDK在…

人大金仓亮相国际金融展,打造“金融+产业+生态”创新模式

4月27日&#xff0c;以“荟萃金融科技成果&#xff0c;展现数字金融力量&#xff0c;谱写金融服务中国式现代化新篇章”为主题的2023中国国际金融展圆满落幕。作为已经举办30年的行业盛会&#xff0c;人大金仓再一次重磅亮相&#xff0c;全方位展示国产数据库前沿应用和创新服务…

C/C++开发神器CLion全新发布v2023.1——新软件包管理解决方案

CLion是一款专为开发C及C所设计的跨平台IDE。它是以IntelliJ为基础设计的&#xff0c;包含了许多智能功能来提高开发人员的生产力。这种强大的IDE帮助开发人员在Linux、OS X和Windows上来开发C/C&#xff0c;同时它还使用智能编辑器来提高代码质量、自动代码重构并且深度整合CM…

国产仪器 6914CA/6914DA/6914EA/6914CX/6914DX/6914EX数字示波器

6914系列数字示波器将台式示波器的Any Acquire Phosphor技术融入到PXI/PXIe架构中&#xff0c;以模块化的结构形式提供台式示波器的功能和性能。该系列示波器具有6个产品型号&#xff0c;带宽350MHz~1GHz&#xff0c;最高采样率5GSa/s&#xff0c;最大存储深度200Mpts/CH&#…

vue项目将多张图片生成一个gif动图

当前做项目有一个需求是将多张图片生成一个gif动图的形式 类似下面图片几张图片叠加生成一个gif动图 图片涉及工作隐私&#xff0c;就不公开啦 我们要引入一个gif.js的引入包&#xff0c;但是他没有直接引入的方式&#xff0c;只能从官方下载文件包&#xff0c;下载地址&#…

面向航空智能制造的边缘计算光交换技术研究

源自&#xff1a;航空科学技术 作者&#xff1a;赵俊 吴宝锋 徐盛果 孙小菡 摘 要 面向航空智能制造大批量数据采集与传递的实时性要求&#xff0c;提出一种基于异步光分组交换&#xff08;optical packet switching,OPS&#xff09;技术的具有多级管理能力的边缘计算系统…

关于千兆和万兆电口模块,你了解多少?

网络技术的不断发展&#xff0c;使得传输速度的要求越来越高。为了满足这种需求&#xff0c;千兆和万兆电口模块逐渐成为了现代网络设备中的重要组成部分。 一、什么是千兆电口模块&#xff1f; 千兆电口模块是一种用于网络设备之间传输数据的光转电模块&#xff0c;它们可以…

谷粒商城二十四Sentinel限流熔断降级

我们在秒杀服务加的以上所有手段都是为了快&#xff0c;除了快之外&#xff0c;我们还需要保证稳定。 我们即使再快也会有一个极限值&#xff0c;现在假设单机下每秒处理一万个单&#xff0c;这已经是超高的处理能力了&#xff0c;秒杀服务上了五台服务器&#xff0c;有三台掉…

【直播预告】“知·道关基 行·筑安全”关基保护线上研讨会将于5月5日、5月9日开启

随着信息化建设的不断发展&#xff0c;网络安全形势日趋严峻&#xff0c;围绕网络空间主导权和控制权的竞争加剧&#xff0c;全球网络安全博弈日趋激烈。 关键信息基础设施是数字经济社会运行的神经中枢&#xff0c;事关国家网络安全和数据安全&#xff0c;日益成为国家网络空…

BetaFlight统一硬件配置文件研读之serial命令

BetaFlight统一硬件配置文件研读之serial命令 1. 源由2. 代码分析3. 实例分析4. 配置情况5. 参考资料 统一硬件配置文件的设计是一种非常好的设计模式&#xff0c;可以将硬件和软件的工作进行解耦。 1. 源由 cli命令中serial是对UART串口的配置&#xff0c;通常情况下BetaFli…

信创赛道全国二等奖!创邻科技国产化解决方案再获佳绩

4月27日&#xff0c;第六届数字中国建设峰会在福建省福州市开幕。本届峰会以“加快数字中国建设&#xff0c;推进中国式现代化”为主题&#xff0c;以宣传贯彻落实《数字中国建设整体布局规划》为主线&#xff0c;集中展示数字中国建设最新成果&#xff0c;分享发展经验&#x…

C++题解:静态区间最大值

题目链接 P3865 ST 表 题目描述 这是一道 ST 表经典题——静态区间最大值 请注意最大数据时限只有 0.8s&#xff0c;数据强度不低&#xff0c;请务必保证你的每次查询复杂度为 O ( 1 ) O(1) O(1)。若使用更高时间复杂度算法不保证能通过。 如果您认为您的代码时间复杂度正…

java版企业电子招投标采购系统源码——功能模块功能描述+数字化采购管理 采购招投标

​ 功能模块&#xff1a; 待办消息&#xff0c;招标公告&#xff0c;中标公告&#xff0c;信息发布 描述&#xff1a; 全过程数字化采购管理&#xff0c;打造从供应商管理到采购招投标、采购合同、采购执行的全过程数字化管理。通供应商门户具备内外协同的能力&#xff0c;为外…

ansible常见概念总结

目录 1、play和playbook和role 2、幂等性 3、清单 4、配置文件(ansible.cfg) 5、变量 5.1 在playbook中使用变量&#xff1a; 5.2 在playbook中使用变量文件&#xff1a; 6、事实 7、循环 8、处理程序 9、块 10、动态清单文件 11、角色 1、play和playbook和role …

本地事务,分布式事务(Seata)

本地事务 四大特性ACID A:原子性(Atomicity)&#xff1a;事务是不可分割的最小操作但愿&#xff0c;要么全部成功&#xff0c;要么全部失败 C:一致性(Consistency)&#xff1a;事务完成时&#xff0c;必须使所有数据都保持一致状态 l:隔离性(Isolation)&#xff1a;数据库系统…