Java学习笔记(五十六)—— TCP通信程序

概述
  • TCP通信能实现两台计算机之间的数据交付,通信的两端,要严格区分为客户端(Client)与服务端(Server)
  • 两端通信步骤:
  1. 服务端程序,需提前启动,等待客户端的连接
  2. 客户端主动连接服务器端,连接成功才能通信。服务器端不可以主动连接客户端
  • java中提供了两个类实现TCP通信
  1. 客户端:Socket类。创建Socket对象,向服务端发送连接请求,服务端响应请求,两者建立连接开始通信
  2. 服务端:ServerSocket类,创建ServerSocket对象,相当于开启一个服务器,并等待客户端的连接

在这里插入图片描述

Socket类
  • 概述:
  1. 该类实现客户端套接字(也称为“套接字”,包含了IP地址和端口号的网络单位)。 套接字是两台机器之间通讯的端点。
  2. 套接字的实际工作由SocketImpl类的实例执行。 应用程序通过更改创建套接字实现的套接字工厂,可以配置自己创建适合本地防火墙的套接字。
  • 构造方法

    Socket​(String host, int port) 创建流套接字并将其连接到指定主机上的指定端口号。
    	host:服务器主机名称/服务器ip地址
    	port:端口号 
    
  • 成员方法

    OutputStream getOutputStream​() 返回此套接字的输出流。  
    InputStream getInputStream​() 返回此套接字的输入流。  
    void close​() 关闭此套接字。  
    
    使用步骤:
    	1、创建一个客户端对象Socket,构造方法中绑定服务器IP地址和端口号
    	2、使用Socket对象中的方法getOutputStream​,获取网络字节输出流OutputStream对象
    	3、使用网络字节输出流OutputStream对象write方法,给服务器发送数据
    	4、使用Socket对象中的方法getInputStream​,获取网络字节输入流InputStream对象
    	5、使用网络字节输入流InputStream对象read方法,读取服务器回写的数据
    	6、使用资源(Socket)
    注意:
    	1、客户端和服务器端进行交互,必须使用Socket中提供的网络流对象,不能使用自己创建的流对象
    	2、当我们创建客户端对象Socket的时候,就会去请求服务器和服务器经过3次握手建立连接通路。
    
    	// 客户端
        try {
            Socket socket = new Socket("127.168.2.140",8888);
            OutputStream outputStream = socket.getOutputStream();
            outputStream.write("你好".getBytes());
            InputStream inputStream = socket.getInputStream();
            byte[] bytes=new byte[1024];
            int len=inputStream.read(bytes);
            System.out.println(new String(bytes,0,len));
            socket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    
ServerSocket类
  • 概述:
  1. 这个类实现了服务器套接字。 服务器套接字等待通过网络进入的请求。 它根据该请求执行一些操作,然后可能将结果返回给请求者。
  2. 服务器套接字的实际工作由SocketImpl类的实例执行。 应用程序可以更改创建套接字实现的套接字工厂,以配置自己创建适合本地防火墙的套接字。
  • 构造方法

    ServerSocket​(int port) 创建绑定到指定端口的服务器套接字。  
    
  • 成员方法

    Socket accept​() 侦听要连接到此套接字并接受它。  
    
    使用步骤:
    	1、创建服务器端ServerSocket对象和系统指定的端口号
    	2、使用ServerSocket对象中的accept对象,获取到请求的客户端对象Socket
    	3、使用Socket对象中的方法getInputStream​,获取网络字节输入流InputStream对象
    	4、获取网络字节输入流InputStream对象中的方法,读取客户端发送的数据
    	5、使用Socket对象中的方法getOutputStream​,获取网络字节输出流OutputStream对象
    	6、使用网络字节输出流OutputStream对象中的write,给客户端回写数据
    	7、释放资源(Socket,ServerSocket)
    
    	// 服务器端
        try {
            ServerSocket serverSocket = new ServerSocket(8888);
            Socket socket = serverSocket.accept();
            InputStream inputStream = socket.getInputStream();
            byte[] bytes=new byte[1024];
            int len= inputStream.read(bytes);
            System.out.println(new String(bytes,0,len));
            OutputStream outputStream = socket.getOutputStream();
            outputStream.write("收到".getBytes());
            socket.close();
            serverSocket.close();
    
        } catch (IOException e) {
            e.printStackTrace();
        }
    
案例
  • 文件上传

    // 服务器端
    public class FileUploadTCPServr {
        public static void main(String[] args) {
            try {
                ServerSocket serverSocket = new ServerSocket(8888);
                Socket accept = serverSocket.accept();
                InputStream internetInputStream = accept.getInputStream();
                File localFile = new File("day16\\src\\FileUpload");
                if(!localFile.exists()){
                    localFile.mkdir(); // 创建文件夹
                }            
                FileOutputStream localFileOutputStream = new FileOutputStream(localFile + "\\b.txt");
                int len=0;
                byte[] bytes = new byte[1024];
                while ((len=internetInputStream.read(bytes))!=-1){
                    localFileOutputStream.write(bytes,0,len);
                }
                accept.getOutputStream().write("上传成功".getBytes());
                localFileOutputStream.close();
                accept.close();
                serverSocket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
    
        }
    }
    
    // 服务端的优化
    public class FileUploadTCPServr {
        public static void main(String[] args) {
            try {
                ServerSocket serverSocket = new ServerSocket(8888);
                /*
                    让服务器一直处于监听状态(死循环accept方法)
                    有一个客户端上传文件,就保存文件
                */
                while (true){
                    /*
                        使用多线程提高程序效率
                        有一个客户端上传文件,就开启一个线程,完成文件的上传
                    */
                    Socket accept = serverSocket.accept();
                    new Thread(new Runnable() {
                        @Override
                        public void run() {
                            try {
                                InputStream internetInputStream = accept.getInputStream();
                                File localFile = new File("day16\\src\\FileUpload");
                                if(!localFile.exists()){
                                    localFile.mkdir(); // 创建文件夹
                                }
                            /*
                                自定义文件的命名规则
                                    规则:域名+毫米值+随机数
                            */
                                String fileName="itcast"+System.currentTimeMillis()+new Random().nextInt(9999)+".txt";
                                FileOutputStream localFileOutputStream = new FileOutputStream(localFile + "\\"+fileName);
                                int len=0;
                                byte[] bytes = new byte[1024];
                                while ((len=internetInputStream.read(bytes))!=-1){
                                    localFileOutputStream.write(bytes,0,len);
                                }
                                accept.getOutputStream().write("上传成功".getBytes());
                                localFileOutputStream.close();
                                accept.close();
                            }catch (Exception e){
                                e.printStackTrace();
                            }
                        }
                    }).start();
    
    
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
    
        }
    }
    
    
    // 客户端
    public class FileUploadTCPClient {
        public static void main(String[] args) {
            try {
                FileInputStream localFileInputStream = new FileInputStream("day16\\src\\FileUpload\\a.txt");
                Socket socket = new Socket("192.168.2.140", 8888);
                OutputStream internetOutputStream = socket.getOutputStream();
                byte[] bytes = new byte[1024];
                int len=0;
                while ((len= localFileInputStream.read(bytes))!=-1){
                    internetOutputStream.write(bytes,0,len);
                }
                socket.shutdownOutput();// 给服务器一个结束标记
                InputStream internetInputStream = socket.getInputStream();
                while ((len= internetInputStream.read(bytes))!=-1){
                    System.out.println(new String(bytes,0,len));
                }
                localFileInputStream.close();
                socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
    
        }
    }
    
  • 模拟B/S服务器

    // 服务器端
    public class BSTCPServer {
        public static void main(String[] args) {
            try {
                ServerSocket serverSocket = new ServerSocket(8080);
                Socket accept = serverSocket.accept();
                InputStream internetInputStream = accept.getInputStream();
                /*byte[] bytes1 = new byte[1024];
                int len1=0;
                while ((len1=internetInputStream.read(bytes1))!=-1){
                    System.out.println(len1);
                    System.out.println(new String(bytes1,0,465));
                }*/
                 //把internetInputStream网络字节输入流对象,转换为字符缓冲输入流
                BufferedReader br = new BufferedReader(new InputStreamReader(internetInputStream));
                 //把客户端请求信息的第一行读取出来
                String s = br.readLine(); // GET /day16/web/test.html HTTP/1.1
                // 把读取的信息进行切割,并截取
                String[] arr=s.split("");
                String htmlPath=arr[1].substring(1); // day16/web/test.html HTTP/1.1
                // 创建本地的字节输入流,构造方法中绑定要输入的文件路径
                FileInputStream localInputStream=new FileInputStream(htmlPath);
                // 使用Socket中的getOutputStream方法获取网络字节输出流OutputStream
                OutputStream internetOutputStream = accept.getOutputStream();
                // 写入HTTP协议响应头,固定写法
                internetOutputStream.write("HTTP/1.1 200 OK\r\n".getBytes());
                internetOutputStream.write("Content-Type:text/html\r\n".getBytes());
                // 必须写入空行,否则浏览器不解析
                internetOutputStream.write("\r\n".getBytes());
                // 一读一写复制文件,把服务端读取的html文件回写到客户端
                int len=0;
                byte[] bytes = new byte[1024];
                while ((len=localInputStream.read(bytes))!=-1){
                    internetOutputStream.write(bytes,0,len);
                }
                // 释放资源
                localInputStream.close();
                accept.close();
                serverSocket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    
    // 服务端改进
    public class BSTCPServer {
        public static void main(String[] args) {
            try {
                ServerSocket serverSocket = new ServerSocket(8080);
                while (true){
                    Socket accept = serverSocket.accept();
                    new Thread(new Runnable() {
                        @Override
                        public void run() {
                            try{
                                InputStream internetInputStream = accept.getInputStream();
                                //把internetInputStream网络字节输入流对象,转换为字符缓冲输入流
                                BufferedReader br = new BufferedReader(new InputStreamReader(internetInputStream));
                                //把客户端请求信息的第一行读取出来
                                String s = br.readLine(); // GET /day16/web/test.html HTTP/1.1
                                // 把读取的信息进行切割,并截取
                                String[] arr=s.split(" ");
                                String htmlPath=arr[1].substring(1); // day16/web/test.html HTTP/1.1
                                // 创建本地的字节输入流,构造方法中绑定要输入的文件路径
                                FileInputStream localInputStream=new FileInputStream(htmlPath);
                                // 使用Socket中的getOutputStream方法获取网络字节输出流OutputStream
                                OutputStream internetOutputStream = accept.getOutputStream();
                                // 写入HTTP协议响应头,固定写法
                                internetOutputStream.write("HTTP/1.1 200 OK\r\n".getBytes());
                                internetOutputStream.write("Content-Type:text/html\r\n".getBytes());
                                // 必须写入空行,否则浏览器不解析
                                internetOutputStream.write("\r\n".getBytes());
                                // 一读一写复制文件,把服务端读取的html文件回写到客户端
                                int len=0;
                                byte[] bytes = new byte[1024];
                                while ((len=localInputStream.read(bytes))!=-1){
                                    internetOutputStream.write(bytes,0,len);
                                }
                                // 释放资源
                                localInputStream.close();
                                accept.close();
                            }catch (IOException e){
                                e.printStackTrace();
                            }
                        }
                    }).start();	
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    
发布了113 篇原创文章 · 获赞 1 · 访问量 951

猜你喜欢

转载自blog.csdn.net/weixin_44876003/article/details/103361049