欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Java 【网络编程】学习笔记

程序员文章站 2022-07-11 20:58:46
...

网络编程

IP

import java.net.InetAddress;
import java.net.UnknownHostException;

/**
 * InetAddress: 多个静态方法
 * 1.getLocalHost:本机
 * 2.getByName:根据域名DNS || IP地址 ———>IP
 *
 * 两个成员方法:
 * 1.getHostAddress:返回地址
 * 2.getHostName:返回计算机名
 */
public class IPTest {
    public static void main(String[] args) throws UnknownHostException {
        //使用getLocalHost方法创建InetAddress对象  本机
        InetAddress address = InetAddress.getLocalHost();
        System.out.println(address.getHostAddress());
        System.out.println(address.getHostName());
        //根据域名得到InetAddress对象
        address = InetAddress.getByName("www.163.com");
        System.out.println(address.getHostAddress());
        System.out.println(address.getHostName());
        //根据IP得到InetAddress对象
        address = InetAddress.getByName("121.22.230.62");
        System.out.println(address.getHostAddress());
        System.out.println(address.getHostName());//输出的IP不是域名,如果这个IP地址不存在或DNS服务器不允许进行IP地址和域名的映射,getHostName方法就直接返回这个IP地址
    }
}

端口

  1. 查看所有端口: netstat-ano•

  2. 查看指定端口: netstat-aon|findstr"808"

  3. 查看指定进程: tasklist|findstr"808"

  4. 查看具体程序:使用任务管理器查看 PID

import java.net.InetSocketAddress;

/**
 * 端口:
 * 1.区分软件
 * 2. 2个字节 0-65535 UDP TCP
 * 3.同一个协议端口不能冲突
 * 4.定义端口越大越好
 * InetSocketAddress
 * 1.构造器
 * new InetSocketAddress(地址|域名,8080);
 * 2.方法
 * getAddress()
 * getPort()
 * getHostName()
 */
public class PortTest {
    public static void main(String[] args) {
        InetSocketAddress socketAddress = new InetSocketAddress("127.0.0.1",8080);
        InetSocketAddress socketAddress1 = new InetSocketAddress("localhost",9000);
        System.out.println(socketAddress.getHostName());
        System.out.println(socketAddress1.getAddress());
        System.out.println(socketAddress1.getPort());
    }
}

URL

import java.net.MalformedURLException;
import java.net.URL;

/**
 * 统一资源定位器 互联网三大基石之一(HTML http),区分资源
 * 1.协议
 * 2.域名或计算机名
 * 3.端口 :默认80
 * 4.请求资源
 * http:||www.baidu.com:80|index.html?uname=shsxt&age=18#a
 */
public class URLTest {
    public static void main(String[] args) throws MalformedURLException {
        URL url = new URL("https://www.csdn.net");
        //获取四个值
        System.out.println("协议"+url.getProtocol());
        System.out.println("域名|IP"+url.getHost());
        System.out.println("请求资源"+url.getFile());
        System.out.println("请求资源"+url.getPath());
        System.out.println("端口"+url.getPort());
        //参数
        System.out.println("参数"+url.getQuery());
        //锚点
        System.out.println("锚点"+url.getRef());
    }
}

爬虫原理

import java.io.*;
import java.net.URL;

/**
 * 网络爬虫的原理
 */
public class SpiderTest01 {
    public static void main(String[] args) throws IOException {
        //获取URL
        URL url = new URL("https://www.csdn.net/");
        //下载资源
        InputStream inputStream = url.openStream();
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream,"UTF-8"));
        String msg =null;
        while (null!=(msg = bufferedReader.readLine())){
            System.out.println(msg);
        }
        bufferedReader.close();
    }
}


/**
 * 网络爬虫的原理+模拟浏览器
 */

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;

public class SpiderTest02 {
    public static void main(String[] args) throws IOException {
        //获取URL
        URL url = new URL("https://www.csdn.net/");
        //下载资源
        HttpURLConnection connection = (HttpURLConnection)url.openConnection();
        connection.setRequestMethod("GET");
        connection.setRequestProperty("......");
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream,"UTF-8"));
        String msg =null;
        while (null!=(msg = bufferedReader.readLine())){
            System.out.println(msg);
        }
        bufferedReader.close();
    }
}

UDP网络编程

基本步骤

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.nio.charset.StandardCharsets;

/**
 * 基本流程:
 * 发送端
 * 1.使用DatagramSocket创建发送端  (指定端口)
 * 2.准备数据 一定转成字节数组
 * 3.封装成DatagramPacket 包裹 需要指定目的地
 * 4.发送包裹 send(DatagramPacket p)
 * 5.释放资源
 */
public class UDPClient {
    public static void main(String[] args) throws Exception{
        System.out.println("发送方启动中......");
        DatagramSocket client = new DatagramSocket(8888);
        String data = "上海尚学堂";
        byte[] datas = data.getBytes();
        DatagramPacket packet = new DatagramPacket(datas,0,datas.length,new InetSocketAddress("localhost",9999));
        client.send(packet);
        client.close();
    }
}

/**
 * 基本流程:
 * 接收端
 * 1.使用DatagramSocket创建接收端  (指定端口)
 * 2.准备容器 封装成DatagramPacket 包裹
 * 3.阻塞式接受包裹 recieve(DatagramPacket p)
 * 4.分析数据
 *  byte[] getData()
 *  getLength()
 */
public class UDPServer {
    public static void main(String[] args) throws IOException {
        System.out.println("接收方启动中......");
        DatagramSocket server = new DatagramSocket(6666);
        byte[] container = new byte[1024*60];
        DatagramPacket packet = new DatagramPacket(container,0,container.length);
        server.receive(packet);
        byte[] datas = packet.getData();
        int len = packet.getLength();
        System.out.println(new String(datas,0,len));

    }
}

上传文件

import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
/**
 * 基本流程:
 * 发送端
 * 1.使用DatagramSocket创建发送端  (指定端口)
 * 2.准备数据 一定转成字节数组
 * 3.封装成DatagramPacket 包裹 需要指定目的地
 * 4.发送包裹 send(DatagramPacket p)
 * 5.释放资源
 */
public class UDPTypeClient {
    public static void main(String[] args) throws Exception{
        System.out.println("发送方启动中......");
        DatagramSocket client = new DatagramSocket(8888);
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(baos));
        dos.writeUTF("编码辛酸泪");
        dos.writeInt(18);
        dos.writeBoolean(false);
        dos.writeChar('a');
        dos.flush();
        byte[] datas = baos.toByteArray();
        DatagramPacket packet = new DatagramPacket(datas,0,datas.length,new InetSocketAddress("localhost",6666));
        client.send(packet);
        client.close();
    }
}


import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
/**
 * 基本流程:
 * 接收端
 * 1.使用DatagramSocket创建接收端  (指定端口)
 * 2.准备容器 封装成DatagramPacket 包裹
 * 3.阻塞式接受包裹 recieve(DatagramPacket p)
 * 4.分析数据  将字节数组还原为对应的类型
 *  byte[] getData()
 *  getLength()
 */
public class UDPTypeServer {
    public static void main(String[] args) throws IOException {
        System.out.println("接收方启动中......");
        DatagramSocket server = new DatagramSocket(6666);
        byte[] container = new byte[1024*60];
        DatagramPacket packet = new DatagramPacket(container,0,container.length);
        server.receive(packet);
        byte[] datas = packet.getData();
        int len = packet.getLength();
        DataInputStream dataInputStream = new DataInputStream(new BufferedInputStream(new ByteArrayInputStream(datas)));
        //顺序与写出一致
        String msg = dataInputStream.readUTF();
        int age = dataInputStream.readInt();
        boolean flag = dataInputStream.readBoolean();
        char ch = dataInputStream.readChar();
        System.out.println(msg+"-->"+flag);
        server.close();

    }
}

案例:在线咨询

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.net.SocketException;

/**
 * 发送端 :使用面向对象封装
 */
public class TalkSend implements Runnable{
    private DatagramSocket client;
    private BufferedReader reader;
    private String toIp;
    private int toPort;
    public TalkSend(int port,String toIp,int toPort)  {
        this.toIp = toIp;
        this.toPort = toPort;
        try {
            client = new DatagramSocket(port);
            reader = new BufferedReader(new InputStreamReader(System.in));
        } catch (SocketException e) {
            e.printStackTrace();
        }
    }
    @Override
    public void run() {
        while(true){
            String data = null;
            try {
             data = reader.readLine();
            byte []datas = data.getBytes();
            DatagramPacket packet = new DatagramPacket(datas,0,datas.length,new InetSocketAddress(this.toIp,this.toPort));
            client.send(packet);
            if (data.equals("bye")){
                break;
            }
            } catch (IOException e) {
                e.printStackTrace();
            }

        }
        client.close();
    }
}


import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
import java.util.regex.Pattern;

/**
 * 接收端:使用面向对象封装
 */
public class TalkRecieve implements Runnable{
    private DatagramSocket server;
    private String from;
    public TalkRecieve(int port,String from){
        this.from = from;
        try {
            server = new DatagramSocket(port);
        } catch (SocketException e) {
            e.printStackTrace();
        }
    }
    @Override
    public void run() {
        while (true) {
            byte[] container = new byte[1024 * 60];
            DatagramPacket packet = new DatagramPacket(container, 0, container.length);
            try {
                server.receive(packet);
                byte[] datas = packet.getData();
                int len = packet.getLength();
                String data = new String(datas, 0, len);
                System.out.println(from+":"+data);
                if (data.equals("bye")){
                    break;
                }
            } catch (IOException e) {
                e.printStackTrace();
            }

        }
    }
}


/**
 * 加入多线程,实现双向交流 模拟在线咨询
 */
public class TalkStudent {
    public static void main(String[] args) {
        new Thread(new TalkSend(7777,"localhost",9999)).start();//发送

        new Thread(new TalkRecieve(8888,"老师")).start();
    }
}

/**
 * 加入多线程,实现双向交流 模拟在线咨询
 */
public class TalkTeacher {
    public static void main(String[] args) {
        new Thread(new TalkRecieve(9999,"学生")).start();//接收

        new Thread(new TalkSend(5555,"localhost",8888)).start();
    }
}

TCP网络编程

基本步骤

import java.io.DataInputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * 熟悉流程
 * 创建服务器
 * 1.指定端口 使用ServerSocket 创建服务器
 * 2.阻塞式等待连接 accept
 * 3.操作:输入输出流操作
 * 4.释放资源
 */
public class Server {
    public static void main(String[] args) throws IOException {
        System.out.println("-----创建服务器-----");
        //1.指定端口 使用ServerSocket 创建服务器
        ServerSocket server = new ServerSocket(8888);
        //2.阻塞式等待连接 accept
        Socket client = server.accept();
        System.out.println("一个客户端建立了连接");
        //3.操作:输入输出流操作
        DataInputStream dis = new DataInputStream(client.getInputStream());
        String data = dis.readUTF();
        System.out.println(data);
        //4.释放资源
        dis.close();
        client.close();
        server.close();
    }
}

import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;

/**
 * 熟悉流程
 * 创建客户端
 * 1.建立连接: 使用Socket创建客户端 + 服务的地址和端口
 * 2.操作: 输入输出流操作
 * 3.释放资源
 */
public class Client {
    public static void main(String[] args) throws IOException {
        System.out.println("-----Client-----");
        //1.建立连接: 使用Socket创建客户端 + 服务的地址和端口
        Socket client = new Socket("localhost",8888);
        //2.操作: 输入输出流操作
        DataOutputStream dos = new DataOutputStream(client.getOutputStream());
        String data = "hello";
        dos.writeUTF(data);
        dos.flush();
        //3.释放资源
        dos.close();
        client.close();
    }
}

单向登录

/**
 * 模拟登录 单向
 * 创建客户端
 * 1.建立连接: 使用Socket创建客户端 + 服务的地址和端口
 * 2.操作: 输入输出流操作
 * 3.释放资源
 */
public class LoginClient {
    public static void main(String[] args) throws IOException {
        System.out.println("-----Client-----");
        BufferedReader console = new BufferedReader(new InputStreamReader(System.in));
        System.out.println("请输入用户名");
        String uname = console.readLine();
        System.out.println("请输入密码");
        String upwd = console.readLine();
        //1.建立连接: 使用Socket创建客户端 + 服务的地址和端口
        Socket client = new Socket("localhost",8888);
        //2.操作: 输入输出流操作
        DataOutputStream dos = new DataOutputStream(client.getOutputStream());

        dos.writeUTF("uname="+uname+"&"+"upwd="+upwd);
        dos.flush();
        //3.释放资源
        dos.close();
        client.close();
    }
}


import java.io.DataInputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * 模拟登录 单向
 * 创建服务器
 * 1.指定端口 使用ServerSocket 创建服务器
 * 2.阻塞式等待连接 accept
 * 3.操作:输入输出流操作
 * 4.释放资源
 */
public class LoginServer {
    public static void main(String[] args) throws IOException {
        System.out.println("-----创建服务器-----");
        //1.指定端口 使用ServerSocket 创建服务器
        ServerSocket server = new ServerSocket(8888);
        //2.阻塞式等待连接 accept
        Socket client = server.accept();
        System.out.println("一个客户端建立了连接");
        //3.操作:输入输出流操作
        DataInputStream dis = new DataInputStream(client.getInputStream());
        String datas= dis.readUTF();
        //分析
        String []datasArray = datas.split("&");
        for (String info:datasArray){
            String[] userinfo = info.split("=");
            System.out.println(userinfo[0]+"-->"+userinfo[1]);
            if (userinfo[0].equals("uname")){
                System.out.println("你的用户名为:"+userinfo[1]);
            }else if (userinfo[0].equals("upwd")){
                System.out.println("你的密码为:"+userinfo[1]);
            }
        }
        //4.释放资源
        dis.close();
        client.close();

    }
}

双向登录

import java.io.*;
import java.net.Socket;
/**
 * 模拟登录 双向
 * 创建客户端
 * 1.建立连接: 使用Socket创建客户端 + 服务的地址和端口
 * 2.操作: 输入输出流操作
 * 3.释放资源
 */
public class LoginTwoWayClient {
    public static void main(String[] args) throws IOException {
        System.out.println("-----Client-----");
        BufferedReader console = new BufferedReader(new InputStreamReader(System.in));
        System.out.println("请输入用户名");
        String uname = console.readLine();
        System.out.println("请输入密码");
        String upwd = console.readLine();
        //1.建立连接: 使用Socket创建客户端 + 服务的地址和端口
        Socket client = new Socket("localhost",8888);
        //2.操作: 输入输出流操作
        DataOutputStream dos = new DataOutputStream(client.getOutputStream());
        dos.writeUTF("uname="+uname+"&"+"upwd="+upwd);
        dos.flush();

        DataInputStream dis = new DataInputStream(client.getInputStream());
        String result= dis.readUTF();

        System.out.println(result);
        //3.释放资源
        dos.close();
        client.close();
    }
}


import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
/**
 * 模拟登录 双向
 * 创建服务器
 * 1.指定端口 使用ServerSocket 创建服务器
 * 2.阻塞式等待连接 accept
 * 3.操作:输入输出流操作
 * 4.释放资源
 */
public class LoginTwoWayServer {
    public static void main(String[] args) throws IOException {
        System.out.println("-----创建服务器-----");
        //1.指定端口 使用ServerSocket 创建服务器
        ServerSocket server = new ServerSocket(8888);
        //2.阻塞式等待连接 accept
        Socket client = server.accept();
        System.out.println("一个客户端建立了连接");
        //3.操作:输入输出流操作
        DataInputStream dis = new DataInputStream(client.getInputStream());
        String datas= dis.readUTF();
        String uname = "";
        String upwd ="";
        //分析
        String []datasArray = datas.split("&");
        for (String info:datasArray){
            String[] userinfo = info.split("=");
            System.out.println(userinfo[0]+"-->"+userinfo[1]);
            //分析
            if (userinfo[0].equals("uname")){
                System.out.println("你的用户名为:"+userinfo[1]);
                uname = userinfo[1];
            }else if (userinfo[0].equals("upwd")){
                System.out.println("你的密码为:"+userinfo[1]);
                upwd = userinfo[1];
            }
        }
        //输出
        DataOutputStream dos = new DataOutputStream(client.getOutputStream());

        if (uname.equals("lwz") && upwd.equals("123456")){
                dos.writeUTF("登录成功,欢迎回来");
        }else{
                dos.writeUTF("用户名或密码错误");
        }
        dos.flush();
        //4.释放资源
        dis.close();
        client.close();

    }
}

文件上传

import java.io.*;
import java.net.Socket;

/**
 * 上传文件
 * 创建客户端
 * 1.建立连接: 使用Socket创建客户端 + 服务的地址和端口
 * 2.操作: 输入输出流操作
 * 3.释放资源
 */
public class FileClient {
    public static void main(String[] args) throws IOException {
        System.out.println("-----Client-----");
        //1.建立连接: 使用Socket创建客户端 + 服务的地址和端口
        Socket client = new Socket("localhost",8888);
        //2.操作: 输入输出流操作  拷贝上传
        InputStream is = new BufferedInputStream(new FileInputStream("E:\\Download\\ThreadStudy\\lantian.jpg"));
        OutputStream os = new BufferedOutputStream(client.getOutputStream());
        byte []flush = new byte[1024];
        int len = -1;
        while ((len=is.read(flush))!=-1){
            os.write(flush,0,len);
        }
        os.flush();
        os.close();
        is.close();
        //3.释放资源
        client.close();
    }
}


/**
 * 存储文件
 * 创建服务器
 * 1.指定端口 使用ServerSocket 创建服务器
 * 2.阻塞式等待连接 accept
 * 3.操作:输入输出流操作
 * 4.释放资源
 */
public class FileServer {
    public static void main(String[] args) throws IOException {
        System.out.println("-----创建服务器-----");
        //1.指定端口 使用ServerSocket 创建服务器
        ServerSocket server = new ServerSocket(8888);
        //2.阻塞式等待连接 accept
        Socket client = server.accept();
        System.out.println("一个客户端建立了连接");
        //3.操作:输入输出流操作
        InputStream is = new BufferedInputStream(client.getInputStream());
        OutputStream os = new BufferedOutputStream(new FileOutputStream("src/tcp.png"));
        byte []flush = new byte[1024];
        int len = -1;
        while ((len=is.read(flush))!=-1){
            os.write(flush,0,len);
        }
        os.flush();
        os.close();
        is.close();
        //4.释放资源

        client.close();
        server.close();
    }
}

多用户登录

import java.io.*;
import java.net.Socket;

public class LoginMultiClient {
    public static void main(String[] args) throws IOException {
        System.out.println("-----Client-----");
        Socket client = new Socket("localhost",8888);
        new Send(client).send();
        new Recieve(client).recieve();
        client.close();

    }
    static class Send{
        private Socket client;
        private BufferedReader br;
        private DataOutputStream dos;
        private String msg;
        public Send(Socket client){
            try {
                this.client = client;
                br = new BufferedReader(new InputStreamReader(System.in));
                this.msg = init();
                dos = new DataOutputStream(client.getOutputStream());
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        private String init(){
            try {
                System.out.println("请输入用户名");
                String uname = br.readLine();
                System.out.println("请输入密码");
                String upwd = br.readLine();
                return "uname=" + uname + "&pwd=" + upwd;
            }catch (IOException e){
                e.printStackTrace();
            }
            return "";
        }
        public void send(){
            try {
                dos.writeUTF(this.msg);
                dos.flush();
            }catch (IOException e){
                e.printStackTrace();
            }
        }
    }
    static class Recieve{
        private Socket client;
        private DataInputStream dis;
        public Recieve(Socket client){
            this.client = client;
            try {
                dis = new DataInputStream(client.getInputStream());
            }catch (IOException e){
                e.printStackTrace();
            }
        }
        public void recieve(){
            String response;
            try {
                response = dis.readUTF();
                System.out.println(response);
            }catch (IOException e){
                e.printStackTrace();
            }
        }
    }
}


import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

public class LoginMultiServer{
    public static void main(String[] args) throws IOException {
        System.out.println("-----server-----");
        ServerSocket server = new ServerSocket(8888);
        boolean isRuning  = true;
        while (isRuning){
            Socket socket = server.accept();
            System.out.println("一个客户端建立了连接");
            new Thread(new Channel(socket)).start();
        }
        server.close();

    }
    static class Channel implements Runnable{
        private Socket socket;
        private DataInputStream dis;
        private DataOutputStream dos;

        public Channel(Socket client){
            this.socket = client;
            try {
                dis = new DataInputStream(socket.getInputStream());
                dos = new DataOutputStream(socket.getOutputStream());
            }catch (IOException e){
                e.printStackTrace();
                release();
            }
        }
        public String recieve(){
            String datas = "";
            try {
                datas = dis.readUTF();
            }catch (IOException e){
                e.printStackTrace();
            }
            return datas;
        }
        public void send(String msg){
            try {
                dos.writeUTF(msg);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        public void release(){
            if (null!=dos){
                try {
                    dos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (null!=dis){
                try {
                    dis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (null!=dos){
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        @Override
        public void run() {
            String datas = recieve();
            String []dataArray = datas.split("&");
            String uname = null;
            String upwd = null;
            for (String info:dataArray) {
                String[] userinfo = info.split("=");
                if ("uname".equals(userinfo[0])) {
                    uname = userinfo[1];
                    System.out.println("用户名:" + uname);
                } else if ("pwd".equals(userinfo[0])) {
                    upwd = userinfo[1];
                    System.out.println("密码:" + upwd);
                }
            }
            if (uname.equals("zs")&& upwd.equals("123")){
                send("登录成功,欢迎回来");
            }else {
                send("用户名或密码错误");
            }
            release();
        }
    }

}

手写聊天室

基础简易版

import java.io.*;
import java.net.Socket;

/**
 * 在线聊天室: 客户端
 * 目标: 实现一个客户可以正常收发多条消息
 */
public class TMultiClient {
    public static void main(String[] args) throws IOException {
        System.out.println("-----Client-----");
        //1.建立连接: 使用Socket创建客户端 + 服务的地址和端口
        Socket client = new Socket("localhost",8888);
        //2.客户端发送消息
        BufferedReader console = new BufferedReader(new InputStreamReader(System.in));
        DataOutputStream dos = new DataOutputStream(client.getOutputStream());
        DataInputStream dis = new DataInputStream(client.getInputStream());
        boolean isRunning = true;
        while (isRunning) {
            String msg = console.readLine();
            dos.writeUTF(msg);
            dos.flush();
            //3.获取消息
            msg = dis.readUTF();
            System.out.println(msg);
        }
        //4.释放资源
        dos.close();
        dis.close();
        client.close();

    }
}


import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * 在线聊天室 :服务端
 * 目标:实现一个客户可以正常收发多条信息
 * 问题:其他客户必须等待之前的客户退出,才能继续 排队
 * 问题:
 * 1.代码不好维护
 * 2.哭护短读写没有分开 必须先写后读
 */
public class TMultiChat {
    public static void main(String[] args) throws IOException {
        System.out.println("-----创建服务器-----");
        //1.指定端口 使用ServerSocket 创建服务器
        ServerSocket server = new ServerSocket(8888);
        //2.阻塞式等待连接 accept
        while (true) {
            Socket client = server.accept();
            System.out.println("一个客户端建立了连接");
            //3.接收消息
            new Thread(()->{
                DataInputStream dis =null;
                DataOutputStream dos= null;
                try {
                    dis = new DataInputStream(client.getInputStream());
                    dos = new DataOutputStream(client.getOutputStream());
                } catch (IOException e) {
                    e.printStackTrace();
                }
                boolean isRunning = true;
                while (isRunning) {
                    String msg = null;
                    try {
                        msg = dis.readUTF();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                    //4.返回消息
                    try {
                        dos.writeUTF(msg);
                        dos.flush();
                    } catch (IOException e) {
                        //e.printStackTrace();
                        isRunning = false;//停止线程
                    }
                    //释放资源
                }
                try {
                    if (null==dos){
                        dos.close();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
                try {
                    if (null==dis){
                        dis.close();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
                try {
                    if (null==client){
                        client.close();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }).start();

        }


    }
}

最终版

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.channels.Channel;
import java.util.concurrent.CopyOnWriteArrayList;

/**
 * 在线聊天室 :服务器
 * 目标:私聊
 */
public class Chat {
    private static CopyOnWriteArrayList<Channel> all = new CopyOnWriteArrayList<Channel>();
    public static void main(String[] args) throws IOException {
        System.out.println("-----Server-----");
        //1.指定端口 使用ServerSocket创建服务器
        ServerSocket server = new ServerSocket(8888);
        //2.阻塞式等待连接 accept
        while (true) {
            Socket client = server.accept();
            System.out.println("一个客户端进行了连接");
            Channel c = new Channel(client);
            all.add(c);  //管理所有的成员
            new Thread(c).start();
        }
    }

    //一个客户代表一个Channel
    static class Channel implements Runnable {
        private DataInputStream dis;
        private DataOutputStream dos;
        private Socket client;
        private boolean isRunning;
        private String name;

        public Channel(Socket client) {
            this.client = client;
            try {
                dis = new DataInputStream(client.getInputStream());
                dos = new DataOutputStream(client.getOutputStream());
                isRunning = true;
                //获取名称
                this.name= recieve();
                //欢迎你的到来
                this.send("欢迎你的到来");
                sendOthers(this.name+"来到了太理1号楼308宿舍聊天室",true);
            } catch (IOException e) {
                System.out.println("-----1-----");
                release();
            }
        }

        //接收消息
        private String recieve() {
            String msg = "";
            try {
                msg = dis.readUTF();
            } catch (IOException e) {
                System.out.println("-----2-----");
                release();
            }
            return msg;
        }

        //发送消息
        private void send(String msg) {
            try {
                dos.writeUTF(msg);
                dos.flush();
            } catch (IOException e) {
                System.out.println("-----3-----");
                release();
            }
        }

        /**
         * 群聊:获取自己的消息 发给其他人
         * 私聊:约定数据格式
         */
        private void sendOthers(String msg,boolean isSys) {
            boolean isPrivate = msg.startsWith("@");
            if (isPrivate) { //私聊
                int idx = msg.indexOf(":");
                //获取目标和数据
                String targetName = msg.substring(1, idx);
                msg = msg.substring(idx+1);
                for (Channel other : all) {
                    if (other.name.equals(targetName)) { //目标
                        other.send(this.name + "悄悄地对您说:" + msg);
                        break;
                    }
                }
            } else {
                for (Channel other : all) {
                    if (other == this) { //自己
                        continue;
                    }
                    if (!isSys) {
                        other.send(this.name + "对所有人说:" + msg);//群聊消息
                    } else {
                        other.send(msg); //系统消息
                    }
                }
            }
        }

        //释放资源
        private void release() {
            this.isRunning = false;
            SxtUtils.close(dis,dos,client);
            //退出
            all.remove(this);
            sendOthers(this.name + "离开大家庭...", true);
        }

        @Override
        public void run() {
            while (isRunning) {
                String msg = recieve();
                if (!msg.equals("")) {
                    //send (msg)
                    sendOthers(msg, false);
                }
            }
        }
    }
}


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

/**
 * 在线聊天室 :客户端
 * 目标 :私聊
 */
public class Client {
    public static void main(String[] args) throws IOException {
        System.out.println("-----Client-----");
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        System.out.println("请输入用户名:");
        String name = br.readLine();
        //1.建立连接:使用Socket创建客户端+服务的地址和端口
        Socket client = new Socket("localhost",8888);
        //2.客户端发送消息
        new Thread(new Send(client,name)).start();
        new Thread(new Recieve(client)).start();


    }
}


import java.io.DataInputStream;
import java.io.IOException;
import java.net.Socket;

/**
 * 使用多线程封装:接收端
 * 1.接收消息
 * 2.释放资源
 * 3.重写run
 */
public class Recieve implements Runnable{
    private DataInputStream dis;
    private Socket client;
    private boolean isRunning;
    public Recieve(Socket client){
        this.client = client;
        this.isRunning = true;
        try {
            dis = new DataInputStream(client.getInputStream());
        }catch (IOException e){
            System.out.println("=====2=====");
            release();
        }
    }
    //接受消息
    private String recieve(){
        String msg  =  "";
        try {
            msg = dis.readUTF();
        }catch (IOException e){
            System.out.println("=====4=====");
            release();
        }
        return msg;
    }

    @Override
    public void run() {
        while (isRunning){
            String msg = recieve();
            if (!msg.equals("")){
                System.out.println(msg);
            }
        }
    }
    //释放资源
    private void release(){
        this.isRunning = false;
        SxtUtils.close(dis,client);
    }
}


import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;

/**
 * 使用多线程封装:发送端
 * 1.发送消息
 * 2.从控制台获取消息
 * 3.释放资源
 * 4.重写run
 *
 */
public class Send implements Runnable{
    private BufferedReader console;
    private DataOutputStream dos;
    private Socket client;
    private boolean  isRunning;
    private String name;
    public Send(Socket client,String name){
        this.client = client;
        console = new BufferedReader(new InputStreamReader(System.in));
        this.isRunning = true;
        this.name = name;
        try {
            dos = new DataOutputStream(client.getOutputStream());
            //发送名称
            send(name);
        }catch (IOException e){
            System.out.println("===1===");
            this.release();
        }
    }

    @Override
    public void run() {
        while (isRunning){
            String msg = getStrFromConsole();
            if (!msg.equals("")){
                send(msg);
            }
        }
    }
    //发送消息
    private void send(String msg){
        try {
            dos.writeUTF(msg);
            dos.flush();
        }catch (IOException e){
            System.out.println(e);
            System.out.println("===3===");
            release();
        }
    }
    /**
     * 从控制台获取消息
     */
    private String getStrFromConsole(){
        try {
            return console.readLine();
        }catch (IOException e){
            e.printStackTrace();
        }
        return "";
    }
    //释放资源
    private void release(){
        this.isRunning = false;
        SxtUtils.close(dos,client);
    }
}


import java.io.Closeable;

/**
 * 工具类
 */
public class SxtUtils {
    /**
     * 释放资源
     */
    public static void close(Closeable... targets) {
        for (Closeable target:targets){
            try {
                if(null!=target){
                    target.close();
                }
            }catch (Exception e){

            }
        }

    }
}