• Socket类关于TCP字符流编程的理解学习


    基本介绍

    套接字(socket):是通信的基石,是支持TCP/IP协议的网络通信的基本操作单元。它是网络通信过程中端点的抽象表示,包含进行网络通信必须的五种信息:连接使用的协议,本地主机的IP地址,本地进程的协议端口,远地主机的IP地址,远地进程的协议端口

    1. socket是通信的基石,是支持TCP/IP协议的网络通信的基本操作单元。
    2. socket简单的说,由 端口,协议,地址三个组成部分。
    3. 套接字之间的连接过程分为三个步骤:服务器监听,客户端请求,连接确认。
    4. 由于通常情况下Socket连接就是TCP连接,因此Socket连接一旦建立,通信双方即可开始相互发送数据内容,直到双方连接断开。
    5. 但在实际网络应用中,客户端到服务器之间的通信往往需要穿越多个中间节点,例如路由器、网关、防火墙等,大部分防火墙默认会关闭长时间处于非活跃状态的连接而导致Socket 连接断连,因此需要通过轮询告诉网络,该连接处于活跃状态。
    • Socket主要用于开发网络应用程序,其背广泛采用

    • 通信的两端都需要有Socket,是两台机器间通信的断点

    • 网络通信其实就是Socket的通信

    • Socket允许程序把网络连接当成一个流,数据在两个Socket间通过IO传输

    • 一般主动发起通信的应用程序属于客户端,等待通信请求的为服务端

    示意图:

    image-20220727232736510

    代码实现

    一定要注意,必须要先开启服务端,在启动客户端,否则会报错

    **注意:**这里的代码示例都是关于发送与接收信息,如果需要发送或接收图片等都差不多,只是必须要使用字节流而不能使用字符流,基本流程都是使用IO中的知识。

    需求1:

    1. 编写一个服务端和一个客户端
    2. 服务端在9999端口监听
    3. 客户端连接到服务器,发送"hello,server",退出
    4. 服务端接收到客户端发送的信息并输出,退出

    服务端

    /**
     *
     * 服务端
     * 需求:接收从客户端发来的信息并输出
     *
     * @author:雷子杰
     * @date:2022/7/27
     */
    public class ScoketTCP01Server {
        public static void main(String[] args) throws IOException {
    
            //新建serverSocket对象,实现9999端口监听
            ServerSocket serverSocket = new ServerSocket(9999);
    
            //客户端连接后会生成管道
            Socket socket = serverSocket.accept();
    
            //获取管道的输入流
            InputStream inputStream = socket.getInputStream();
            byte[] buf=new byte[1024];
            int len = 0;
    
            while ((len = inputStream.read(buf))!=-1){
                System.out.println(new String(buf,0,len));
            }
    
            //关闭流
            inputStream.close();
            socket.close();
            serverSocket.close();
    
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    客户端

    输出流写入数据后一定要进行flush(),同时进行结束标记

    /**
     *
     * 客户端
     * 需求:向服务器端发送一条信息
     *
     * @author:雷子杰
     * @date:2022/7/27
     */
    public class ScoketTCP01Client {
        public static void main(String[] args) throws IOException {
            //获取socket连接
            Socket socket = new Socket(InetAddress.getLocalHost(),9999);
    
            //获取输出流对象
            OutputStream outputStream = socket.getOutputStream();
            //往输出流中写入信息
            outputStream.write("hello,server".getBytes());
    
            //关闭流
            outputStream.close();
            socket.close();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    测试结果

    服务端收到信息

    image-20220727231736859

    需求2

    1. 编写一个服务端和一个客户端
    2. 服务端在9999端口监听
    3. 客户端连接到服务器,发送"hello,server",并接收服务端回发的"hello,client",退出
    4. 服务端接收到客户端发送的信息输出,并发送"hello,client",退出

    服务端

    输出流写入数据后一定要进行flush(),同时进行结束标记

    /**
     *
     * 服务端
     * 需求:接收从客户端发来的信息输出,并返回一条消息给客户端
     *
     *
     * @author:雷子杰
     * @date:2022/7/27
     */
    public class ScoketTCP02Server {
        public static void main(String[] args) throws IOException {
    
            //新建serverSocket对象,实现9999端口监听
            ServerSocket serverSocket = new ServerSocket(9999);
    
            //客户端连接后会生成管道
            Socket socket = serverSocket.accept();
    
            //获取管道的输入流,获取客户端发来的信息
            InputStream inputStream = socket.getInputStream();
            byte[] buf=new byte[1024];
            int len = 0;
    
            while ((len = inputStream.read(buf))!=-1){
                System.out.println(new String(buf,0,len));
            }
            //关闭读取
            socket.shutdownInput();
    
            //获取输出流对象
            OutputStream outputStream = socket.getOutputStream();
            //往输出流中写入信息,发送给服务端
            outputStream.write("hello,client".getBytes());
            //关闭写入
            socket.shutdownOutput();
    
            //关闭流
            outputStream.close();
            inputStream.close();
            socket.close();
            serverSocket.close();
    
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45

    客户端

    输出流写入数据后一定要进行flush(),同时进行结束标记

    /**
     *
     * 客户端
     * 需求:向服务器端发送一条信息,并接收从服务器端返回的一条信息
     *
     * @author:雷子杰
     * @date:2022/7/27
     */
    public class ScoketTCP02Client {
        public static void main(String[] args) throws IOException {
            //获取socket连接
            Socket socket = new Socket(InetAddress.getLocalHost(),9999);
    
            //获取输出流对象
            OutputStream outputStream = socket.getOutputStream();
            //往输出流中写入信息,发送给服务端
            outputStream.write("hello,server".getBytes());
            //关闭写入
            socket.shutdownOutput();
    
            //获取管道的输入流,获取服务器端发来的信息
            InputStream inputStream = socket.getInputStream();
            byte[] buf=new byte[1024];
            int len = 0;
    
            while ((len = inputStream.read(buf))!=-1){
                System.out.println(new String(buf,0,len));
            }
    
            //关闭流
            inputStream.close();
            outputStream.close();
            socket.close();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    测试结果

    服务端收到信息

    image-20220727231852931

    客户端收到信息

    image-20220727231909658

    需求3

    使用字符流完成,之前两个需求都是使用的字节流去完成

    1. 编写一个服务端和一个客户端
    2. 服务端在9999端口监听
    3. 客户端连接到服务器,发送"hello,server",并接收服务端回发的"hello,client",退出
    4. 服务端接收到客户端发送的信息输出,并发送"hello,client",退出

    服务端

    输出流写入数据后一定要进行flush(),同时进行结束标记

    /**
     *
     * 服务端
     * 需求:使用字符流,接收从客户端发来的信息输出,并返回一条消息给客户端
     *
     * @author:雷子杰
     * @date:2022/7/27
     */
    public class ScoketTCP03Server {
        public static void main(String[] args) throws IOException {
    
            //新建serverSocket对象,实现9999端口监听
            ServerSocket serverSocket = new ServerSocket(9999);
    
            //客户端连接后会生成管道
            Socket socket = serverSocket.accept();
    
            //获取管道的输入流,获取客户端发来的信息
            InputStream inputStream = socket.getInputStream();
            //将字节流输入流转为字符流输入流
            InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
            char[] cbuf=new char[1024];
            int len;
            while ((len = inputStreamReader.read(cbuf))!=-1){
                System.out.println(new String(cbuf,0,len));
            }
            //关闭读取
            socket.shutdownInput();
    
            //获取输出流对象
            OutputStream outputStream = socket.getOutputStream();
            //将字节流输出流转换为字符流输出流
            OutputStreamWriter outputStreamWriter = new OutputStreamWriter(outputStream);
            //往输出流中写入信息,发送给服务端
            outputStreamWriter.write("hello,client");
            //需要刷新流后才能写入
            outputStreamWriter.flush();
            //关闭写入
            socket.shutdownOutput();
    
            //关闭流
            outputStreamWriter.close();
            inputStreamReader.close();
            socket.close();
            serverSocket.close();
    
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49

    客户端

    输出流写入数据后一定要进行flush(),同时进行结束标记

    /**
     *
     * 客户端
     * 需求:使用字符流,向服务器端发送一条信息,并接收从服务器端返回的一条信息
     *
     * @author:雷子杰
     * @date:2022/7/27
     */
    public class ScoketTCP03Client {
        public static void main(String[] args) throws IOException {
            //获取socket连接
            Socket socket = new Socket(InetAddress.getLocalHost(),9999);
    
            //获取输出流对象
            OutputStream outputStream = socket.getOutputStream();
            //将字节流输出流转换为字符流输出流
            OutputStreamWriter outputStreamWriter = new OutputStreamWriter(outputStream);
            //往输出流中写入信息,发送给服务端
            outputStreamWriter.write("hello,server");
            //需要刷新流后才能写入
            outputStreamWriter.flush();
    
            //关闭写入
            socket.shutdownOutput();
    
            //获取管道的输入流,获取服务器端发来的信息
            InputStream inputStream = socket.getInputStream();
            //将字节流输入流转为字符流输入流
            InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
            char[] cbuf=new char[1024];
            int len;
            while ((len = inputStreamReader.read(cbuf))!=-1){
                System.out.println(new String(cbuf,0,len));
            }
    
            //关闭流
            inputStreamReader.close();
            outputStreamWriter.close();
            socket.close();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41

    测试结果

    服务端收到信息

    image-20220727231959710

    客户端收到信息

    image-20220727231954226

    发送图片、视频等文件流程说明

    由于是图片、视频等文件,所以一定要使用字节流去进行传输

    需求:

    1. 编写一个服务端和一个客户端
    2. 服务端在8888端口监听
    3. 客户端连接到服务端,发送本地一张图片
    4. 服务端接收到客户端发送的图片,保存到src下,发送“收到图片”给客户端,然后退出
    5. 客户端接收服务端发送的“收到图片”,然后退出

    流程示例:

    1. 客户端使用字节输入流将磁盘中的图片输入到内存中
    2. 客户端使用字节输出流将内存中的图片输出给服务端
    3. 服务端使用字节输入流将客户端字节输出流中的图片获取得到
    4. 服务端使用字节输出流将图片输出到磁盘文件中

    服务端

    输出流写入数据后一定要进行flush(),同时进行结束标记

    /**
     *
     * 服务端
     *
     * @author:雷子杰
     * @date:2022/7/27
     */
    public class TCPFileUploadServer {
        public static void main(String[] args) throws IOException {
    
            //监听8888端口
            ServerSocket serverSocket = new ServerSocket(8888);
            //等待连接
            Socket socket = serverSocket.accept();
    
            BufferedInputStream bufferedInputStream = new BufferedInputStream(socket.getInputStream());
            //创建的字节流输出流
            BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(new FileOutputStream("basic_review\\src\\socket_\\图片.jpg"));
            //读取图片信息
            byte[] buf = new byte[1024];
            int len;
            while ((len = bufferedInputStream.read(buf)) != -1){
    
                bufferedOutputStream.write(buf,0,len);
            }
            bufferedOutputStream.flush();
    
            socket.shutdownInput();
    
    
    
            bufferedOutputStream = new BufferedOutputStream(socket.getOutputStream());
    
            bufferedOutputStream.write("收到图片".getBytes());
    
            //刷新流
            bufferedOutputStream.flush();
    
            socket.shutdownOutput();
    
            bufferedOutputStream.close();
            bufferedInputStream.close();
            socket.close();
            serverSocket.close();
    
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48

    客户端

    输出流写入数据后一定要进行flush(),同时进行结束标记

    /**
     *
     * 客户端
     *
     * @author:雷子杰
     * @date:2022/7/27
     */
    public class TCPFileUploadClient {
        public static void main(String[] args) throws IOException {
            //连接主机的8888端口,得到socket对象
            Socket socket = new Socket(InetAddress.getLocalHost(), 8888);
    
            //读取的文件地址
            String filePath ="f:\\ssm博客系统.jpg";
            //创建的字节流输入流
            BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream(filePath));
            //创建的字节流输出流
            BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(socket.getOutputStream());
            //读取图片信息
            byte[] buf = new byte[1024];
            int len;
            while ((len = bufferedInputStream.read(buf)) != -1){
                //写入到管道中
                bufferedOutputStream.write(buf,0,len);
            }
            //刷新流
            bufferedOutputStream.flush();
            //关闭写出
            socket.shutdownOutput();
    
    
            bufferedInputStream = new BufferedInputStream(socket.getInputStream());
            while ((len = bufferedInputStream.read(buf)) != -1){
                System.out.println(new String(buf,0,len));
    
            }
    
            socket.shutdownInput();
    
            bufferedOutputStream.close();
            bufferedInputStream.close();
    
            socket.close();
    
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47

    总结

    目前复习java基础复习到了计算机网络阶段,发现自身在网络通信编程这方面的知识较为匮乏,本篇文章用于记载学习java网络编程技术

    另外一个重点!!!!!在使用输出流写入数据后一定要进行flush(),同时进行结束标记,否则可能会报错

  • 相关阅读:
    Spring Cloud Gateway 使用 Redis 限流使用教程
    深入理解Laravel(CVE-2021-3129)RCE漏洞(超2万字从源码分析黑客攻击流程)
    C#(CSharp)入门实践项目(简易回合制游戏)
    机器学习模型性能度量详解 【Python机器学习系列(十六)】
    错过金三银四,找工作4个月,面试15家,终于拿到3个offer,定级P7+
    Mac环境下 gmssl编译iOS静态库
    CSS常用技巧
    论文解读(GSAT)《Interpretable and Generalizable Graph Learning via Stochastic Attention Mechanism》
    赌上了绩效,赢了公司CTO,我要搭DevOps平台!
    Altium Designer20.2.3安装详解
  • 原文地址:https://blog.csdn.net/qq_49137582/article/details/126031824