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();


    }
}

客户端

输出流写入数据后一定要进行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();
    }
}

测试结果

服务端收到信息

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();


    }
}

客户端

输出流写入数据后一定要进行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();
    }
}

测试结果

服务端收到信息

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();


    }
}

客户端

输出流写入数据后一定要进行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();
    }
}

测试结果

服务端收到信息

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();

    }
}

客户端

输出流写入数据后一定要进行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();


    }
}

总结

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

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

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

爱学习的大雄

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值