网络编程 p4 TCP编程

发布时间 2023-07-19 16:11:35作者: 凉白茶

TCP编程

  • 基本介绍

    1. 基于客户端——服务端的网络通信;
    2. 底层使用的是TCP/IP协议;
    3. 应用场景举例:客户端发送数据,服务端接收并显示在控制台;
    4. 基于Socket的TCP编程;
  • 示意图

  • netstat指令

    1. netstat -an可以查看当前主机网络情况,包括端口监听情况和网络连接情况;

    2. netstat -an|more可以分页显示;

    3. 要求在dos控制台下执行 (win+r)

      说明:

      • Listening 表示某个端口在监听;
      • 如果有一个外部程序(客户端)连接到该端口,就会显示一条连接信息;

  • 注意事项

    1. 当客户端连接到服务端后,实际上客户端也是通过一个端口和服务端进行通讯的,这端口是TCP/IP来分配的,是随机的;
  • 应用案例

    • 客户端

      package com.hspedu.socket;
      
      import java.io.*;
      import java.net.InetAddress;
      import java.net.Socket;
      
      /**
       * @author: 86199
       * @date: 2023/5/15 15:18
       * @description: 字符流
       */
      public class SocketTCP03Client {
          public static void main(String[] args) throws IOException {
              //思路
              //1. 连接服务端(ip,端口)
              //解读:连接本机的 9999 端口,如果连接成功,返回Socket对象
              Socket socket = new Socket(InetAddress.getLocalHost(), 9999);
              System.out.println("客户端 socket返回 = " + socket.getClass());
              //2. 连接上后,生成Socket,通过socket.getOutputStream()
              //  得到和socket对象关联的输出流对象
              BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
              //3. 通过输出流,写入数据到 数据通道
              bufferedWriter.write("hello, server");
              bufferedWriter.newLine();//写入一个换行符,表示写入内容结束,要求对方使用readLine的方式来读
              bufferedWriter.flush();//如果使用的字符流,需要手动刷新否则数据不会写入数据通道
      
      
              //4. 通过socket.个体InputStream()读取客户端写入到数据通道的数据,显示
              BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
              String s = bufferedReader.readLine();
              System.out.println(s);
      
              //5. 关闭流对象和socket,必须关闭
              bufferedReader.close();
              bufferedWriter.close();
              socket.close();
      
          }
      }
      
    • 服务端

      package com.hspedu.socket;
      
      import java.io.*;
      import java.net.ServerSocket;
      import java.net.Socket;
      
      /**
       * @author: 86199
       * @date: 2023/5/15 15:18
       * @description: 字符流
       */
      public class SocketTCP03Server {
          public static void main(String[] args) throws IOException {
              //思路
              //1. 在本机的9999端口监听,等待连接
              //   细节:要求本机没有其他服务在监听9999
              //   这个 ServerSocket 可以通过accept() 返回多个Socket[多个客户端连接服务器的并发]
              ServerSocket serverSocket = new ServerSocket(9999);
              System.out.println("服务端,在9999端口监听,等待连接...");
              //2. 当没有客户端连接9999端口时程序会阻塞,等待连接
              //   如果有客户端连接,则会返回Socket对象,程序继续
              Socket accept = serverSocket.accept();
      
              System.out.println("服务端 socket = " + accept.getClass());
      
              //3. 通过socket.个体InputStream()读取客户端写入到数据通道的数据,显示
              BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(accept.getInputStream()));//读不到内容会阻塞
      //4. IO读取
              String s = bufferedReader.readLine();
              System.out.println(s);
      
      
      
              //5. 通过输出流,写入数据到 数据通道
              BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(accept.getOutputStream()));
              bufferedWriter.write("hello, client");
              bufferedWriter.newLine();//写入一个换行符,表示写入内容结束,要求对方使用readLine的方式来读
              bufferedWriter.flush();//如果使用的字符流,需要手动刷新否则数据不会写入数据通道
              //设置结束标记
      
              //6. 关闭流对象和socket,必须关闭
              bufferedWriter.close();
              bufferedReader.close();
              accept.close();
              serverSocket.close();
          }
      }
      
      

    • StreamUtils类

      package com.hspedu.upload;
      
      import java.io.BufferedReader;
      import java.io.ByteArrayOutputStream;
      import java.io.InputStream;
      import java.io.InputStreamReader;
      
      /**
       * @author: 86199
       * @date: 2023/5/16 14:57
       * @description: 工具类
       */
      public class StreamUtils {
          public static byte[] streamToByteArray(InputStream is) throws Exception {
              // 创建输出流对象
              ByteArrayOutputStream bos = new ByteArrayOutputStream();
              // 字节数组
              byte[] b = new byte[1024];
              int len;
              while ((len = is.read(b)) != -1) {
                  // 循环读取
                  // 把读取到的数据,写入 bos
                  bos.write(b, 0, len);
              }
              byte[] array = bos.toByteArray();
              bos.close();
              return array;
          }
      
          public static String streamToString(InputStream is) throws Exception {
              BufferedReader reader = new BufferedReader(new InputStreamReader(is));
              StringBuilder builder = new StringBuilder();
              String line;
              while ((line = reader.readLine()) != null) {
                  builder.append(line + "\r\n");
              }
              return builder.toString();
          }
      }
      
    • 服务端

      package com.hspedu.upload;
      
      import java.io.*;
      import java.net.ServerSocket;
      import java.net.Socket;
      
      /**
       * @author: 86199
       * @date: 2023/5/15 16:24
       * @description:
       */
      public class TCPFileUploadServer {
          public static void main(String[] args) throws Exception {
              ServerSocket serverSocket = new ServerSocket(8888);
              System.out.println("服务端在8888等待连接......");
              Socket accept = serverSocket.accept();
      
              String filePath = "D:\\program\\javaProject\\Idea_Java_Project\\chapter21\\src\\copy.jpg";
      
              BufferedInputStream bis = new BufferedInputStream(accept.getInputStream());
              BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(filePath));
      
              byte[] bytes = StreamUtils.streamToByteArray(bis);
      
              bos.write(bytes);
              bos.close();
      
              //向客户端回复“收到图片”
              BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(accept.getOutputStream()));
              bufferedWriter.write("收到图片");
              bufferedWriter.flush();
              accept.shutdownOutput();
      
              //关闭流和socket
              bis.close();
              accept.close();
              serverSocket.close();
          }
      }
      
    • 客户端

      package com.hspedu.upload;
      
      import java.io.*;
      import java.net.InetAddress;
      import java.net.Socket;
      
      
      /**
       * @author: 86199
       * @date: 2023/5/15 16:24
       * @description:
       */
      public class TCPFileUploadClient {
          public static void main(String[] args) throws Exception {
      
              Socket socket = new Socket(InetAddress.getLocalHost(), 8888);
              String filePath = "e:\\qie.jpg";
      
              BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());
              BufferedInputStream bis = new BufferedInputStream(new FileInputStream(filePath));
      
              byte[] bytes = StreamUtils.streamToByteArray(bis);
              bos.write(bytes);
              bos.flush();
              //没有手动调用flush方法,也没有调用close方法关闭流,数据复制失败,
              //因为数据还在内部缓冲区,并没有输出 (因为内部缓冲区没有被放满,不调用flush方法,不会输出)
              bis.close();
              socket.shutdownOutput();
      
              //接收消息
              InputStream inputStream = socket.getInputStream();
              String s = StreamUtils.streamToString(inputStream);
              System.out.println(s);
      
              //关闭流和socket
              inputStream.close();
              bos.close();
              socket.close();
          }
      }