Java学习笔记 第十章 网络编程

JAVA学习笔记第十章

10.网络编程

10.1引入

image-20210601115242973

image-20210601115608318

image-20210601120234610

image-20210601120349735

image-20210601120808343

TCP建立连接:

image-20210601120613329

释放连接:

image-20210601120654942

image-20210601120755773

image-20210601120741148

10.2InetAddress & InetSocketAddress

image-20210601155342380

image-20210601155212394

InetAddress有两个方法:

image-20210601155313663

InetSocketAddress封装了ip和端口号

image-20210601155731764

10.3套接字

image-20210601161300976

10.4TCP通信

10.4.1客户端和服务端通信

客户端发送一句话到服务器

public class TestClient { // 客户端
    public static void main(String[] args) throws IOException {
        // 创建套接字:指定服务器ip和端口号
        Socket s = new Socket("127.0.0.1", 8888);
        //对程序员来说,向外发送数据 感受 --》 利用输出流;
        OutputStream os = s.getOutputStream();
        DataOutputStream dos = new DataOutputStream(os);
        //利用OutputStream就可以向外发送数据流,但是没有直接发送String的方法
        //所以我们又在OutputStream外面套了一个处理流:DataOutputStream
        dos.writeUTF("你好");

        // 关闭流 + 关闭网络资源
        dos.close();
        os.close();
        s.close();

    }
}
public class TestServer { // 服务器
    public static void main(String[] args) throws IOException {
        // 1.创建套接字:指定服务器的端口
        ServerSocket ss = new ServerSocket(8888);
        // 2.等待客户端发送来的信息
        Socket s = ss.accept(); // 阻塞方法:等待客户端的数据,什么时候收到数据,什么时候程序继续向下执行
        // 3.accept返回值为Socket,这个Socket其实就是客户端的Socket
        //接到这个Socket之后,客户端和服务端才真正产生了连接,才真正可以通信了
        //感受到的操作流
        InputStream is = s.getInputStream();
        DataInputStream dis = new DataInputStream(is);

        // 4.读取客户端发来的数据
        String str = dis.readUTF();
        System.out.println("客户端发来的数据为:" + str);

        // 5.关闭流 + 关闭网络资源
        dis.close();
        is.close();
        s.close();
    }
}

先开服务器,然后开启客户端,在服务器端可以看到控制台打印出客户端发来的数据为:你好

如果先开客户端,会报出连接被拒绝的错误

服务端也可以向客户端发送信息

public class TestServer { // 服务器
    public static void main(String[] args) throws IOException {
        // 1.创建套接字:指定服务器的端口
        ServerSocket ss = new ServerSocket(8888);
        // 2.等待客户端发送来的信息
        Socket s = ss.accept(); // 阻塞方法:等待客户端的数据,什么时候收到数据,什么时候程序继续向下执行
        // 3.accept返回值为Socket,这个Socket其实就是客户端的Socket
        //接到这个Socket之后,客户端和服务端才真正产生了连接,才真正可以通信了
        //感受到的操作流
        InputStream is = s.getInputStream();
        DataInputStream dis = new DataInputStream(is);

        // 4.读取客户端发来的数据
        String str = dis.readUTF();
        System.out.println("客户端发来的数据为:" + str);

        // 6.向客户端发送数据
        OutputStream os = s.getOutputStream();
        DataOutputStream dos = new DataOutputStream(os);
        dos.writeUTF("服务器端接收到你的消息");

        // 5.关闭流 + 关闭网络资源
        dos.close();
        os.close();
        dis.close();
        is.close();
        s.close();
    }
}

public class TestClient { // 客户端
    public static void main(String[] args) throws IOException {
        // 创建套接字:指定服务器ip和端口号
        Socket s = new Socket("127.0.0.1", 8888);
        //对程序员来说,向外发送数据 感受 --》 利用输出流;
        OutputStream os = s.getOutputStream();
        DataOutputStream dos = new DataOutputStream(os);
        //利用OutputStream就可以向外发送数据流,但是没有直接发送String的方法
        //所以我们又在OutputStream外面套了一个处理流:DataOutputStream
        dos.writeUTF("你好");

        //客户端接收服务器的数据
        InputStream is = s.getInputStream();
        DataInputStream dis = new DataInputStream(is);
        String str = dis.readUTF();
        System.out.println("服务器对我说:" + str);

        // 关闭流 + 关闭网络资源
        dis.close();
        is.close();
        dos.close();
        os.close();
        s.close();

    }
}

10.4.2登录验证

模拟登录时输入账号密码,并进行验证的过程

public class User implements Serializable {
    private static final long serialVersionUID = 6158646660109509935L;
    private String name;
    private String pwd;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPwd() {
        return pwd;
    }

    public void setPwd(String pwd) {
        this.pwd = pwd;
    }

    public User(String name, String pwd) {
        this.name = name;
        this.pwd = pwd;
    }
}

需要实现Serializable接口,并且通过idea创建UID

public class Client {  //客户端
    public static void main(String[] args) throws IOException {
        // 1.创建套接字
        Socket s = new Socket("127.0.0.1", 8888);

        // 2.录入账号和密码
        Scanner sc = new Scanner(System.in);
        System.out.println("username:");
        String name = sc.next();
        System.out.println("password:");
        String pwd = sc.next();

        // 3.将账号和密码封装为一个User对象
        User user = new User(name, pwd);

        // 4.向外发送对象,利用输出流
        OutputStream os = s.getOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(os);
        oos.writeObject(user);

        // 5.接收服务端发送的结果
        InputStream is = s.getInputStream();
        DataInputStream dis = new DataInputStream(is);
        Boolean flag = dis.readBoolean();
        System.out.println(flag);

        // 6.关闭流 + 网络资源
        dis.close();
        is.close();
        oos.close();
        os.close();
        s.close();
    }
}

public class Server {  //服务端
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        // 1.创建套接字
        ServerSocket ss = new ServerSocket(8888);

        // 2.等待客户端发来的信息
        Socket s = ss.accept();

        // 3.获取传入的数据
        InputStream is = s.getInputStream();
        ObjectInputStream ois = new ObjectInputStream(is);

        // 4.读取客户端发送的数据
        User user = (User) ois.readObject();

        // 5.对对象进行验证:
        boolean flag = false;
        if (user.getName().equals("wrr") && user.getPwd().equals("1234")){
            flag = true;
        }

        // 6.向客户端输出结果
        OutputStream os = s.getOutputStream();
        DataOutputStream dos = new DataOutputStream(os);
        dos.writeBoolean(flag);

        // 7.关闭流 + 网络资源
        dos.close();
        os.close();
        ois.close();
        is.close();
        ss.close();
    }
}

10.4.3完整的异常处理方式

Socket提出去,其他的流在外面初始化为null

关闭流和资源放到finally,再对里面的流进行异常处理

public class Client {  //客户端
    public static void main(String[] args){
        // 1.创建套接字
        Socket s = null;
        OutputStream os = null;
        ObjectOutputStream oos = null;
        InputStream is = null;
        DataInputStream dis = null;
        try {
            s = new Socket("127.0.0.1", 8888);
            // 2.录入账号和密码
            Scanner sc = new Scanner(System.in);
            System.out.println("username:");
            String name = sc.next();
            System.out.println("password:");
            String pwd = sc.next();

            // 3.将账号和密码封装为一个User对象
            User user = new User(name, pwd);

            // 4.向外发送对象,利用输出流
            os = s.getOutputStream();
            oos = new ObjectOutputStream(os);
            oos.writeObject(user);

            // 5.接收服务端发送的结果
            is = s.getInputStream();
            dis = new DataInputStream(is);
            Boolean flag = dis.readBoolean();
            System.out.println(flag);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 6.关闭流 + 网络资源
            try {
                if(dis != null) {
                    dis.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if(is != null) {
                    is.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if(oos != null) {
                    oos.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if(os != null) {
                    os.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if(s != null) {
                    s.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        
    }
}

public class Server {
    public static void main(String[] args){
        // 1.创建套接字
        ServerSocket ss = null;
        InputStream is = null;
        ObjectInputStream ois = null;
        OutputStream os = null;
        DataOutputStream dos = null;
        
        try {
            ss = new ServerSocket(8888);
            // 2.等待客户端发来的信息
            Socket s = ss.accept();

            // 3.获取传入的数据
            is = s.getInputStream();
            ois = new ObjectInputStream(is);

            // 4.读取客户端发送的数据
            User user = null;
            try {
                user = (User) ois.readObject();
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }

            // 5.对对象进行验证:
            boolean flag = false;
            if (user.getName().equals("wrr") && user.getPwd().equals("1234")){
                flag = true;
            }

            // 6.向客户端输出结果
            os = s.getOutputStream();
            dos = new DataOutputStream(os);
            dos.writeBoolean(flag);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 7.关闭流 + 网络资源
            try {
                if(dos != null) {
                    dos.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if(os != null) {
                    os.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if(ois != null) {
                    ois.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if(is != null) {
                    is.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if(ss != null) {
                    ss.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        

        
    }
}

10.4.4多个客户端和一个服务器

客户端的代码不变

public class Client {  //客户端
    public static void main(String[] args){
        // 1.创建套接字
        Socket s = null;
        OutputStream os = null;
        ObjectOutputStream oos = null;
        InputStream is = null;
        DataInputStream dis = null;
        try {
            s = new Socket("127.0.0.1", 8888);
            // 2.录入账号和密码
            Scanner sc = new Scanner(System.in);
            System.out.println("username:");
            String name = sc.next();
            System.out.println("password:");
            String pwd = sc.next();

            // 3.将账号和密码封装为一个User对象
            User user = new User(name, pwd);

            // 4.向外发送对象,利用输出流
            os = s.getOutputStream();
            oos = new ObjectOutputStream(os);
            oos.writeObject(user);

            // 5.接收服务端发送的结果
            is = s.getInputStream();
            dis = new DataInputStream(is);
            Boolean flag = dis.readBoolean();
            System.out.println(flag);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 6.关闭流 + 网络资源
            try {
                if(dis != null) {
                    dis.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if(is != null) {
                    is.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if(oos != null) {
                    oos.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if(os != null) {
                    os.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if(s != null) {
                    s.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }
}

服务端 Server.java

public class Server {
    public static void main(String[] args){
        // 1.创建套接字
        ServerSocket ss = null;
        Socket s = null;
        int count = 0; // 定义一个计数器,用来计数 客户端的请求
        try {
            ss = new ServerSocket(8888);
            // 2.等待客户端发来的信息
            while (true) { // 加入死循环,服务器一直监听客户端是否发送数据
                s = ss.accept();
                //每次过来的客户端的请求靠线程处理
                new ServerThread(s).start();
                count++;
                System.out.println("当前是第"+count+"个用户访问我们的服务器,对应的用户是"+s.getInetAddress());
            }

        } catch (IOException e) {
            e.printStackTrace();
        }

    }
}

新建ServerThread.java

public class ServerThread extends Thread{  // 线程:专门处理客户端的请求
    InputStream is = null;
    ObjectInputStream ois = null;
    OutputStream os = null;
    DataOutputStream dos = null;
    Socket s = null;
    public ServerThread(Socket s){
        this.s = s;
    }
    @Override
    public void run() {
        // 3.获取传入的数据
        try{
            is = s.getInputStream();
            ois = new ObjectInputStream(is);

            // 4.读取客户端发送的数据
            User user = null;
            try {
                user = (User) ois.readObject();
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }

            // 5.对对象进行验证:
            boolean flag = false;
            if (user.getName().equals("wrr") && user.getPwd().equals("1234")){
                flag = true;
            }

            // 6.向客户端输出结果
            os = s.getOutputStream();
            dos = new DataOutputStream(os);
            dos.writeBoolean(flag);
        } catch (IOException e){
            e.printStackTrace();
        } finally {
            try {
                if(dos != null) {
                    dos.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if(os != null) {
                    os.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if(ois != null) {
                    ois.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if(is != null) {
                    is.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

10.5UDP通信

image-20210602000804582

10.5.1单向通信

public class TestSend {
    public static void main(String[] args) throws IOException { //发送方
        System.out.println("学生上线");
        // 1.准备套接字,指定发送方的端口号
        DatagramSocket ds = new DatagramSocket(8888);
        // 2.准备数据包
        String str = "你好";
        byte[] bytes = str.getBytes();
        DatagramPacket dp = new DatagramPacket(bytes, bytes.length, InetAddress.getByName("localhost"), 9999);
        /*
        需要四个参数: 1.传送数据转为字节的数组 2.字节数组的长度 3.接收方的IP地址 4.接收方的端口号
         */

        // 3.发送
        ds.send(dp);

        // 4.关闭资源
        ds.close();

    }
}

public class TestReceive {
    public static void main(String[] args) throws IOException { //接收方
        System.out.println("接收消息");
        // 1.准备套接字
        DatagramSocket ds = new DatagramSocket(9999);

        // 2.有一个空的数据包,准备接收对方传过来的数据
        byte[] b = new byte[1024];
        DatagramPacket dp = new DatagramPacket(b, b.length);

        // 3.接收对方的数据包,然后放入到我们的dp数据包中填充
        ds.receive(dp); //接收完以后,dp里面就填充好内容了

        // 4.取出数据:
        byte[] data = dp.getData();
        String s = new String(data, 0, dp.getLength());  // dp.getLength()数组包中的有效长度
        System.out.println(s);

        // 5.关闭资源
        ds.close();

    }
}

10.5.2双向通信

public class TestReceive {
    public static void main(String[] args) throws IOException { //接收方
        System.out.println("接收消息");
        // 1.准备套接字
        DatagramSocket ds = new DatagramSocket(9999);

        // 2.有一个空的数据包,准备接收对方传过来的数据
        byte[] b = new byte[1024];
        DatagramPacket dp = new DatagramPacket(b, b.length);

        // 3.接收对方的数据包,然后放入到我们的dp数据包中填充
        ds.receive(dp); //接收完以后,dp里面就填充好内容了

        // 4.取出数据:
        byte[] data = dp.getData();
        String s = new String(data, 0, dp.getLength());  // dp.getLength()数组包中的有效长度
        System.out.println(s);

        // 5.回复
        String str = "Hello";
        byte[] bytes = str.getBytes();
        DatagramPacket dp1 = new DatagramPacket(bytes, bytes.length, InetAddress.getByName("localhost"), 8888);

        ds.send(dp1);

        // 5.关闭资源
        ds.close();

    }
}

public class TestSend {
    public static void main(String[] args) throws IOException { //发送方
        System.out.println("学生上线");
        // 1.准备套接字,指定发送方的端口号
        DatagramSocket ds = new DatagramSocket(8888);
        // 2.准备数据包
        String str = "你好";
        byte[] bytes = str.getBytes();
        DatagramPacket dp = new DatagramPacket(bytes, bytes.length, InetAddress.getByName("localhost"), 9999);
        /*
        需要四个参数: 1.传送数据转为字节的数组 2.字节数组的长度 3.接收方的IP地址 4.接收方的端口号
         */

        // 3.发送
        ds.send(dp);

        // 4.接收
        byte[] b = new byte[1024];
        DatagramPacket dp1 = new DatagramPacket(b, b.length);
        ds.receive(dp1);

        byte[] data = dp1.getData();
        String s = new String(data, 0, dp1.getLength());
        System.out.println(s);

        // 4.关闭资源
        ds.close();

    }
}

10.5.3完整的异常处理方式

与TCP协议的通信一致,如10.4.3

原文地址:https://www.cnblogs.com/wrrr/p/14871906.html