Java面向对象-网络编程(通信)

目录

一.网络通信三要素

        1.三要素概述、要素一:IP地址

        2.IP地址操作类-InetAddress

        3.要素二:端口号

        4.要素三:协议

二.UDP通信-快速入门

1.UDP通信:快速入门

2.UDP通信:多发多收

三.UDP通信-广播、组播

四.TCP通信-快速入门

1.编写客户端代码

2.编写服务端代码、原理分析

五.TCP通信-多发多收消息

六.TCP通信-同时接受多个客户端消息

七.TCP通信-使用线程池优化

八.TCP通信实战案例-即时通信

九.TCP通信实战案例-模拟BS系统


Java面向对象-网络编程(通信)_第1张图片

 Java面向对象-网络编程(通信)_第2张图片

 Java面向对象-网络编程(通信)_第3张图片

 Java面向对象-网络编程(通信)_第4张图片

一.网络通信三要素

        1.三要素概述、要素一:IP地址

Java面向对象-网络编程(通信)_第5张图片

 Java面向对象-网络编程(通信)_第6张图片

 Java面向对象-网络编程(通信)_第7张图片

 Java面向对象-网络编程(通信)_第8张图片

  Java面向对象-网络编程(通信)_第9张图片

 Java面向对象-网络编程(通信)_第10张图片

 Java面向对象-网络编程(通信)_第11张图片

        2.IP地址操作类-InetAddress

Java面向对象-网络编程(通信)_第12张图片

package com.wjh.d1_inetAddress;
/*
    目标:
        public static InetAddress getLocalHost()	        返回本主机的地址对象
        public static InetAddress getByName (String host)	得到指定主机的IP地址对象,参数是域名或者IP地址
        public String getHostName()	                        获取此IP地址的主机名
        public String getHostAddress()	                    返回IP地址字符串
        public boolean isReachable(int timeout)	            在指定毫秒内连通该IP地址对应的主机,连通返回true
 */

import java.net.InetAddress;

public class InetAddressDemo01 {
    public static void main(String[] args) throws Exception{
        //1.获取本机地址对象
        InetAddress ip1 = InetAddress.getLocalHost();
        System.out.println(ip1);  //主机名/IP地址    ->  (已封装toString,不打地址)
        System.out.println(ip1.getHostName());  //主机名
        System.out.println(ip1.getHostAddress());   //IP地址

        //2.获取域名IP对象
        InetAddress ip2 = InetAddress.getByName("www.baidu.com");
        System.out.println(ip2);    //www.baidu.com/14.119.104.254

        //3.获取公网IP对象
        InetAddress ip3 = InetAddress.getByName("14.119.104.254");
        System.out.println(ip3.getHostName());  //14.119.104.254
        System.out.println(ip3.getHostAddress());   //14.119.104.254

        //4.判断是否能通:ping 5s之前测试是否可通
        System.out.println(ip3.isReachable(5000));  //5s之后联通   -> true
        
    }
}

wangjunhua/192.168.184.1
wangjunhua
192.168.184.1
www.baidu.com/14.119.104.189
14.119.104.254
14.119.104.254
true

进程已结束,退出代码为 0
 

Java面向对象-网络编程(通信)_第13张图片

        3.要素二:端口号

Java面向对象-网络编程(通信)_第14张图片

 Java面向对象-网络编程(通信)_第15张图片

 Java面向对象-网络编程(通信)_第16张图片

        4.要素三:协议

Java面向对象-网络编程(通信)_第17张图片

 Java面向对象-网络编程(通信)_第18张图片

 Java面向对象-网络编程(通信)_第19张图片

 Java面向对象-网络编程(通信)_第20张图片

 Java面向对象-网络编程(通信)_第21张图片Java面向对象-网络编程(通信)_第22张图片

Java面向对象-网络编程(通信)_第23张图片

 Java面向对象-网络编程(通信)_第24张图片

 Java面向对象-网络编程(通信)_第25张图片

 Java面向对象-网络编程(通信)_第26张图片

二.UDP通信-快速入门

1.UDP通信:快速入门

Java面向对象-网络编程(通信)_第27张图片

 Java面向对象-网络编程(通信)_第28张图片

 Java面向对象-网络编程(通信)_第29张图片

package com.wjh.d2_UDP1;
/*
    发送端:(一发一收)
 */

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.nio.charset.StandardCharsets;

public class ClientDemo1 {
    public static void main(String[] args) throws Exception {
        System.out.println("==========客户端启动=========");
        //1.创建发送端对象:发送端口自带默认的端口号
        DatagramSocket socket = new DatagramSocket();

        //2.创建一个数据包对象封装数据(韭菜盘子)
        /*
            public DatagramPacket(byte buf[], int length,InetAddress address, int port) {
               this(buf, 0, length, address, port); }
               参数一:封装要发送的数据(韭菜)
               参数二:发送数据的大小
               参数三:服务端的IP地址
               参数四:服务端的端口
         */
        byte[] buffer = "回去下面给你吃?".getBytes();
        DatagramPacket packet = new DatagramPacket(buffer, buffer.length, InetAddress.getLocalHost(), 8889);

        //3.发送数据出去
        socket.send(packet);

        socket.close();
    }

}

package com.wjh.d2_UDP1;
/*
    接受端:
 */

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;

public class ServerDemo2 {
    public static void main(String[] args) throws Exception {
        System.out.println("==========服务端启动=========");
        //1.创建接受端对象,注册端口(人)
        DatagramSocket socket = new DatagramSocket(8889);

        //2.创建一个数据包对象(韭菜盘子)
        byte[] buffer = new byte[1024 * 64]; // 1KB * 64 = 64KB
        DatagramPacket packet = new DatagramPacket(buffer, buffer.length);

        //3.等待接受数据即可!
        socket.receive(packet);

        //4.取出数据即可
        //读多少倒出多少
        int len = packet.getLength();
        String rs = new String(buffer,0, len);
        System.out.println(rs+ " 数据已收到!");

        socket.close();
        
        //先启动服务端,再启动客户端

    }
}

 ==========服务端启动=========

ps:(没有 "进程已结束,退出代码为 0" 提示:说明该进程没有断开,而是在等待......)

 ==========客户端启动=========

进程已结束,退出代码为 0

 ==========服务端启动=========
回去下面给你吃? 数据已收到!

进程已结束,退出代码为 0

Java面向对象-网络编程(通信)_第30张图片

 Java面向对象-网络编程(通信)_第31张图片

 Java面向对象-网络编程(通信)_第32张图片

//获取发送端的IP和端口(在服务端写)
        String ip = packet.getSocketAddress().toString();
        System.out.println("来自IP地址 为:" + ip + "的数据!");
        //来自 /192.168.184.1:50773 的数据!

        int post = packet.getPort();
        System.out.println("来自端口号为:" + post + "的数据!");
        //来自端口号为:61849的数据!

Java面向对象-网络编程(通信)_第33张图片

2.UDP通信:多发多收

Java面向对象-网络编程(通信)_第34张图片

 Java面向对象-网络编程(通信)_第35张图片

 Java面向对象-网络编程(通信)_第36张图片

package com.wjh.d2_UDP1;
/*
    接受端:
 */

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;

public class ServerDemo2 {
    public static void main(String[] args) throws Exception {
        System.out.println("==========服务端启动=========");
        //1.创建接受端对象,注册端口(人)
        DatagramSocket socket = new DatagramSocket(1256);

        //2.创建一个数据包对象(韭菜盘子)
        byte[] buffer = new byte[1024 * 64]; // 1KB * 64 = 64KB
        DatagramPacket packet = new DatagramPacket(buffer, buffer.length);

        while (true) {
            //3.等待接受数据即可!
            socket.receive(packet);

            //4.取出数据即可
            //读多少倒出多少
            int len = packet.getLength();
            String rs = new String(buffer,0, len);
            System.out.println(packet.getAddress().toString() + ",port:" + packet.getPort());
            System.out.println(rs);

            //socket.close();
        }

        //先启动服务端,再启动客户端

    }
}
package com.wjh.d3_UDP2;
/*
    发送端:(多发多收)
 */

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Scanner;

public class ClientDemo1 {
    public static void main(String[] args) throws Exception {
        System.out.println("==========客户端启动=========");
        //1.创建发送端对象:发送端口自带默认的端口号
        DatagramSocket socket = new DatagramSocket(6569);

        //2.创建一个数据包对象封装数据(韭菜盘子)
        /*
            public DatagramPacket(byte buf[], int length,InetAddress address, int port) {
               this(buf, 0, length, address, port); }
               参数一:封装要发送的数据(韭菜)
               参数二:发送数据的大小ff
               参数三:服务端的IP地址
               参数四:服务端的端口
         */

        Scanner sc = new Scanner(System.in);
        while (true) {
            System.out.println("请输入要发送的数据内容:");
            String str1 =sc.nextLine();

            if("exit".equals(str1)){
                System.out.println("离线成功!");
                socket.close();
                break;
            }


            byte[] buffer = str1.getBytes();
            DatagramPacket packet = new DatagramPacket
                    (buffer, buffer.length, InetAddress.getLocalHost(), 1256);
            //3.发送数据出去
            socket.send(packet);


        }

    }

}

Java面向对象-网络编程(通信)_第37张图片

三.UDP通信-广播、组播

Java面向对象-网络编程(通信)_第38张图片

Java面向对象-网络编程(通信)_第39张图片

package com.wjh.d4_UDP3;
/*
    发送端:(多发多收)
 */

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Scanner;

public class ClientDemo1 {
    public static void main(String[] args) throws Exception {
        System.out.println("==========客户端启动=========");
        //1.创建发送端对象:发送端口自带默认的端口号
        DatagramSocket socket = new DatagramSocket(6569);

        //2.创建一个数据包对象封装数据(韭菜盘子)
        /*
            public DatagramPacket(byte buf[], int length,InetAddress address, int port) {
               this(buf, 0, length, address, port); }
               参数一:封装要发送的数据(韭菜)
               参数二:发送数据的大小ff
               参数三:服务端的IP地址
               参数四:服务端的端口
         */

        Scanner sc = new Scanner(System.in);
        while (true) {
            System.out.println("请输入要发送的数据内容:");
            String str1 =sc.nextLine();

            if("exit".equals(str1)){
                System.out.println("离线成功!");
                socket.close();
                break;
            }


            byte[] buffer = str1.getBytes();

            //广播消息
            DatagramPacket packet = new DatagramPacket(buffer, buffer.length, InetAddress.getByName("255.255.255.255"), 9999);

            //组播消息
            

            //3.发送数据出去
            socket.send(packet);


        }

    }

}
package com.wjh.d2_UDP1;
/*
    接受端:
 */

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;

public class ServerDemo2 {
    public static void main(String[] args) throws Exception {
        System.out.println("==========服务端启动=========");
        //1.创建接受端对象,注册端口(人)
        DatagramSocket socket = new DatagramSocket(9999);

        //2.创建一个数据包对象(韭菜盘子)
        byte[] buffer = new byte[1024 * 64]; // 1KB * 64 = 64KB
        DatagramPacket packet = new DatagramPacket(buffer, buffer.length);

        while (true) {
            //3.等待接受数据即可!
            socket.receive(packet);

            //4.取出数据即可
            //读多少倒出多少
            int len = packet.getLength();
            String rs = new String(buffer,0, len);
            System.out.println(packet.getAddress().toString() + ",port:" + packet.getPort());
            System.out.println(rs);

            //socket.close();
        }

        //先启动服务端,再启动客户端

    }
}

==========客户端启动=========
请输入要发送的数据内容:
我是一个广播消息
请输入要发送的数据内容:

==========服务端启动=========
/192.168.0.194,port:6569
我是一个广播消息
 

Java面向对象-网络编程(通信)_第40张图片

socket.joinGroup(new InetSocketAddress(InetAddress.getByName("224.0.1.1"),9998)
                ,NetworkInterface.getByInetAddress(InetAddress.getLocalHost()));
package com.wjh.d5_UDP4;
/*
    发送端:(多发多收)
 */

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Scanner;

public class ClientDemo1 {
    public static void main(String[] args) throws Exception {
        System.out.println("==========客户端启动=========");
        //1.创建发送端对象:发送端口自带默认的端口号
        DatagramSocket socket = new DatagramSocket(6569);

        //2.创建一个数据包对象封装数据(韭菜盘子)
        /*
            public DatagramPacket(byte buf[], int length,InetAddress address, int port) {
               this(buf, 0, length, address, port); }
               参数一:封装要发送的数据(韭菜)
               参数二:发送数据的大小ff
               参数三:服务端的IP地址
               参数四:服务端的端口
         */

        Scanner sc = new Scanner(System.in);
        while (true) {
            System.out.println("请输入要发送的数据内容:");
            String str1 =sc.nextLine();

            if("exit".equals(str1)){
                System.out.println("离线成功!");
                socket.close();
                break;
            }


            byte[] buffer = str1.getBytes();

            //广播消息
            DatagramPacket packet = new DatagramPacket(buffer,
                    buffer.length, InetAddress.getByName("224.0.1.1"), 9998);

            //组播消息


            //3.发送数据出去
            socket.send(packet);


        }

    }

}

package com.wjh.d2_UDP1;
/*
    接受端:
 */

import java.net.*;

public class ServerDemo2 {
    public static void main(String[] args) throws Exception {
        System.out.println("==========服务端启动=========");
        //1.创建接受端对象,注册端口(人)
        MulticastSocket socket = new MulticastSocket(9998);

        //把当前接受端加入到一个组播中去,绑定对应的组播消息的组播IP
        //socket.joinGroup(InetAddress.getByName("224.0.1.1"));
        socket.joinGroup(new InetSocketAddress(InetAddress.getByName("224.0.1.1"),9998)
                ,NetworkInterface.getByInetAddress(InetAddress.getLocalHost()));

        //2.创建一个数据包对象(韭菜盘子)
        byte[] buffer = new byte[1024 * 64]; // 1KB * 64 = 64KB
        DatagramPacket packet = new DatagramPacket(buffer, buffer.length);

        while (true) {
            //3.等待接受数据即可!
            socket.receive(packet);

            //4.取出数据即可
            //读多少倒出多少
            int len = packet.getLength();
            String rs = new String(buffer,0, len);
            System.out.println(packet.getAddress().toString() + ",port:" + packet.getPort());
            System.out.println(rs);

            //socket.close();
        }

        //先启动服务端,再启动客户端

    }
}

==========客户端启动=========
请输入要发送的数据内容:
我是组播消息
请输入要发送的数据内容:
exit
离线成功!

进程已结束,退出代码为 0
 

==========服务端启动=========
/192.168.0.194,port:6569
我是组播消息
 

Java面向对象-网络编程(通信)_第41张图片

四.TCP通信-快速入门

1.编写客户端代码

Java面向对象-网络编程(通信)_第42张图片

Java面向对象-网络编程(通信)_第43张图片

 Java面向对象-网络编程(通信)_第44张图片

 Java面向对象-网络编程(通信)_第45张图片

package com.wjh.d5_socket1;

import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.Socket;

/*
    目标:完成socket网络编程入口案例客户端开发,实现一发一收

 */
public class ClientDemo1 {
    public static void main(String[] args) throws Exception {
        //1.创建socket通信管道请求服务端的连接
        //public Socket(String, int port);
        //参数一:服务端的IP地址
        //参数二:服务端的端口号
        Socket socket = new Socket("127.0.1", 7777);

        //2.从socket通信管道中得到一个字节输出流,负责发送数据
        OutputStream os = socket.getOutputStream();

        //3.把低级的字节流高级的打印流
        PrintStream ps = new PrintStream(os);

        //4.发送消息
        ps.print("我是TCP的客户端,我已经与你对接,并发出邀请,约吗?");
        ps.close();
        
        //关闭资源
        //socket.close();
        
        
        

    }
}

Java面向对象-网络编程(通信)_第46张图片

2.编写服务端代码、原理分析

Java面向对象-网络编程(通信)_第47张图片

Java面向对象-网络编程(通信)_第48张图片

Java面向对象-网络编程(通信)_第49张图片

package com.wjh.d5_socket1;
/*
    目标:开发Service网络编程入门代码的服务端,实现接收数据
 */

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;

public class ServiceDemo2 {
    public static void main(String[] args) throws Exception{
        System.out.println("=====服务端启动成功=====");
        //1.注册端口
        ServerSocket serverSocket = new ServerSocket(7778);

        //2.必须调用accept方法:接受客户端的Socket连接请求,建立Socket通信管道
        Socket socket = serverSocket.accept();

        //3.从Socket通信管道中得到一个字节输入流
        InputStream is = socket.getInputStream();

        //4.把字节输入流包装成缓冲字符输入流进行消息的接受
        BufferedReader br = new BufferedReader(new InputStreamReader(is));

        //5.按照行读取消息
        String msg;
        if((msg = br.readLine()) != null){
            System.out.println(socket.getRemoteSocketAddress() + "说了:" + msg);

        }
    }
}

package com.wjh.d5_socket1;

import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.Socket;

/*
    目标:完成socket网络编程入口案例客户端开发,实现一发一收

 */
public class ClientDemo1 {
    public static void main(String[] args) throws Exception {
        System.out.println("=====客户端启动成功=====");
        //1.创建socket通信管道请求服务端的连接
        //public Socket(String, int port);
        //参数一:服务端的IP地址
        //参数二:服务端的端口号
        Socket socket = new Socket("127.0.1", 7778);

        //2.从socket通信管道中得到一个字节输出流,负责发送数据
        OutputStream os = socket.getOutputStream();

        //3.把低级的字节流高级的打印流
        PrintStream ps = new PrintStream(os);

        //4.发送消息
        //ps.print("我是TCP的客户端,我已经与你对接,并发出邀请,约吗?");
        //注意:Connection reset -> 连接重置

        ps.println("我是TCP的客户端,我已经与你对接,并发出邀请,约吗?");
        ps.flush();

        ps.close();

        //关闭资源
        //socket.close();




    }
}

=====服务端启动成功=====
/127.0.0.1:64182说了:我是TCP的客户端,我已经与你对接,并发出邀请,约吗?

进程已结束,退出代码为 0


=====客户端启动成功=====

进程已结束,退出代码为 0

Java面向对象-网络编程(通信)_第50张图片

五.TCP通信-多发多收消息

Java面向对象-网络编程(通信)_第51张图片

 Java面向对象-网络编程(通信)_第52张图片

package com.wjh.d6_socket2.d5_socket1;
/*
    目标:开发Service网络编程入门代码的服务端,实现接收数据
 */

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;

public class ServiceDemo2 {
    public static void main(String[] args) throws Exception{
        System.out.println("=====服务端启动成功=====");
        //1.注册端口
        ServerSocket serverSocket = new ServerSocket(7778);

        //2.必须调用accept方法:接受客户端的Socket连接请求,建立Socket通信管道
        Socket socket = serverSocket.accept();

        //3.从Socket通信管道中得到一个字节输入流
        InputStream is = socket.getInputStream();

        //4.把字节输入流包装成缓冲字符输入流进行消息的接受
        BufferedReader br = new BufferedReader(new InputStreamReader(is));

        //5.按照行读取消息
        String msg;
        while((msg = br.readLine()) != null){
            System.out.println(socket.getRemoteSocketAddress() + "说了:" + msg);

        }
    }
}

package com.wjh.d6_socket2.d5_socket1;

import java.io.OutputStream;
import java.io.PrintStream;
import java.net.Socket;
import java.util.Scanner;

/*
    目标:完成socket网络编程入口案例客户端开发,实现多发多收

 */
public class ClientDemo1 {
    public static void main(String[] args) throws Exception {
        System.out.println("=====客户端启动成功=====");
        //1.创建socket通信管道请求服务端的连接
        //public Socket(String, int port);
        //参数一:服务端的IP地址
        //参数二:服务端的端口号
        Socket socket = new Socket("127.0.1", 7778);

        //2.从socket通信管道中得到一个字节输出流,负责发送数据
        OutputStream os = socket.getOutputStream();

        //3.把低级的字节流高级的打印流
        PrintStream ps = new PrintStream(os);

        //4.发送消息
        //ps.print("我是TCP的客户端,我已经与你对接,并发出邀请,约吗?");
        //注意:Connection reset -> 连接重置

        Scanner sc = new Scanner(System.in);
        while (true){
            System.out.println("请说:");
            String msg = sc.nextLine();
            ps.println(msg);

            if ("exit".equals(msg)){
                ps.flush();
                break;
            }

        }


        //关闭资源
        //socket.close();




    }
}

=====客户端启动成功=====
请说:
我是谁
请说:
在干嘛
请说:
啥都会
请说:
 

=====客户端启动成功=====
请说:
苏安安
请说:
 

 =====服务端启动成功=====
/127.0.0.1:64857说了:我是谁
/127.0.0.1:64857说了:在干嘛
/127.0.0.1:64857说了:啥都会

Java面向对象-网络编程(通信)_第53张图片

六.TCP通信-同时接受多个客户端消息

Java面向对象-网络编程(通信)_第54张图片

Java面向对象-网络编程(通信)_第55张图片

package com.wjh.d7_socket3;

import java.io.OutputStream;
import java.io.PrintStream;
import java.net.Socket;
import java.util.Scanner;

/*
    目标:完成socket网络编程入口案例客户端开发,实现多发多收

 */
public class ClientDemo1 {
    public static void main(String[] args) throws Exception {
        System.out.println("=====客户端启动成功=====");
        //1.创建socket通信管道请求服务端的连接
        //public Socket(String, int port);
        //参数一:服务端的IP地址
        //参数二:服务端的端口号
        Socket socket = new Socket("127.0.1", 7771);

        //2.从socket通信管道中得到一个字节输出流,负责发送数据
        OutputStream os = socket.getOutputStream();

        //3.把低级的字节流高级的打印流
        PrintStream ps = new PrintStream(os);

        //4.发送消息
        //ps.print("我是TCP的客户端,我已经与你对接,并发出邀请,约吗?");
        //注意:Connection reset -> 连接重置

        Scanner sc = new Scanner(System.in);
        while (true){
            System.out.println("请说:");
            String msg = sc.nextLine();
            ps.println(msg);

            if ("exit".equals(msg)){
                ps.flush();
                break;
            }

        }


        //关闭资源
        //socket.close();




    }
}
package com.wjh.d7_socket3;

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

public class ServerReadThread extends Thread {
    private Socket socket;

    public ServerReadThread() {
    }

    public ServerReadThread(Socket socket) {
        this.socket = socket;
    }

    @Override
    public void run() {
        //3.从Socket通信管道中得到一个字节输入流
        try {
            InputStream is = socket.getInputStream();

            //4.把字节输入流包装成缓冲字符输入流进行消息的接受
            BufferedReader br = new BufferedReader(new InputStreamReader(is));

            //5.按照行读取消息
            String msg;
            while ((msg = br.readLine()) != null) {
                System.out.println(Thread.currentThread().getName() + "线程" + socket.getRemoteSocketAddress() + "说了:" + msg);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
package com.wjh.d7_socket3;
/*
    目标:实现服务端可以同时多个客户端连接
 */

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;

public class ServiceDemo2 {
    public static void main(String[] args) throws Exception{
        System.out.println("=====服务端启动成功=====");
        //1.注册端口
        ServerSocket serverSocket = new ServerSocket(7771);

        //a.定义一个死循环由主线程负责不断的接受客户端的Socket管道连接.
        while (true) {
            //2.每接受到一个客户端的socket管道,交给一个独立的子线程负责读取消息
            Socket socket = serverSocket.accept();

            //3.开始创建独立线程处理socket
            new ServerReadThread(socket).start();
        }
    }
}

=====客户端启动成功=====
请说:
你好
请说:

=====客户端启动成功=====
请说:
在吗
请说:
 

=====客户端启动成功=====
请说:
在干嘛
请说:
 

=====客户端启动成功=====
请说:
略略略
请说:
 

 =====服务端启动成功=====
Thread-0线程/127.0.0.1:50154说了:你好
Thread-1线程/127.0.0.1:50199说了:在吗
Thread-2线程/127.0.0.1:50213说了:在干嘛
Thread-3线程/127.0.0.1:50228说了:略略略

Java面向对象-网络编程(通信)_第56张图片

 扩展:

try {
            InputStream is = socket.getInputStream();

            //4.把字节输入流包装成缓冲字符输入流进行消息的接受
            BufferedReader br = new BufferedReader(new InputStreamReader(is));

            //5.按照行读取消息
            String msg;
            while ((msg = br.readLine()) != null) {
                System.out.println(Thread.currentThread().getName() + "线程" + socket.getRemoteSocketAddress() + "说了:" + msg);
            }
        } catch (Exception e) {
            System.out.println(socket.getRemoteSocketAddress() + "下线了");
        }
while (true) {
            //2.每接受到一个客户端的socket管道,交给一个独立的子线程负责读取消息
            Socket socket = serverSocket.accept();
            System.out.println(socket.getRemoteSocketAddress() + "它来了,上线了!");
            //3.开始创建独立线程处理socket
            new ServerReadThread(socket).start();
        }

=====服务端启动成功=====
/127.0.0.1:50767它来了,上线了!
Thread-0线程/127.0.0.1:50767说了:阿斯顿发生
Thread-0线程/127.0.0.1:50767说了:按时gas
/127.0.0.1:50789它来了,上线了!
Thread-1线程/127.0.0.1:50789说了:sadgas
Thread-1线程/127.0.0.1:50789说了:dsgj
/127.0.0.1:50767下线了
/127.0.0.1:50789下线了

七.TCP通信-使用线程池优化

Java面向对象-网络编程(通信)_第57张图片

Java面向对象-网络编程(通信)_第58张图片 Java面向对象-网络编程(通信)_第59张图片

package com.wjh.d8_socket4;

import java.io.OutputStream;
import java.io.PrintStream;
import java.net.Socket;
import java.util.Scanner;

/*
    扩展:使用线程池优化实现通信

 */
public class ClientDemo1 {
    public static void main(String[] args) throws Exception {
        System.out.println("=====客户端启动成功=====");
        //1.创建socket通信管道请求服务端的连接
        //public Socket(String, int port);
        //参数一:服务端的IP地址
        //参数二:服务端的端口号
        Socket socket = new Socket("127.0.0.1", 7771);

        //2.从socket通信管道中得到一个字节输出流,负责发送数据
        OutputStream os = socket.getOutputStream();

        //3.把低级的字节流高级的打印流
        PrintStream ps = new PrintStream(os);

        //4.发送消息
        //ps.print("我是TCP的客户端,我已经与你对接,并发出邀请,约吗?");
        //注意:Connection reset -> 连接重置

        Scanner sc = new Scanner(System.in);
        while (true){
            System.out.println("请说:");
            String msg = sc.nextLine();
            ps.println(msg);

            if ("exit".equals(msg)){
                ps.flush();
                break;
            }

        }


        //关闭资源
        //socket.close();




    }
}

package com.wjh.d8_socket4;
/*
    目标:实现服务端可以同时多个客户端连接
 */

import com.wjh.d7_socket3.ServerReadThread;

import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.*;

public class ServiceDemo2 {

    //使用静态变量记住一个线程池对象
    private static ExecutorService pool = new ThreadPoolExecutor(3, 5, 6, TimeUnit.SECONDS
            , new ArrayBlockingQueue<>(3), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());

    public static void main(String[] args) throws Exception{
        System.out.println("=====服务端启动成功=====");
        //1.注册端口
        ServerSocket serverSocket = new ServerSocket(7771);

        //a.定义一个死循环由主线程负责不断的接受客户端的Socket管道连接.
        while (true) {
            //2.每接受到一个客户端的socket管道,交给一个独立的子线程负责读取消息
            Socket socket = serverSocket.accept();

            System.out.println(socket.getRemoteSocketAddress() + "它来了,上线了!");

            //做成任务交给线程池(负责处理消息)
            Runnable target = new ServerReaderRunnable(socket);
            pool.execute(target);
        }
    }
}

package com.wjh.d8_socket4;

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

public class ServerReaderRunnable implements Runnable{
    private Socket socket;

    public ServerReaderRunnable() {
    }

    public ServerReaderRunnable(Socket socket) {
        this.socket = socket;
    }

    @Override
    public void run() {
        try {
            InputStream is = socket.getInputStream();

            //4.把字节输入流包装成缓冲字符输入流进行消息的接受
            BufferedReader br = new BufferedReader(new InputStreamReader(is));

            //5.按照行读取消息
            String msg;
            while ((msg = br.readLine()) != null) {
                System.out.println(Thread.currentThread().getName() + "线程" + socket.getRemoteSocketAddress() + "说了:" + msg);
            }
        } catch (Exception e) {
            System.out.println(socket.getRemoteSocketAddress() + "下线了");
        }

    }
}

 =====客户端启动成功=====
请说:
我是第二个线程
请说:

=====客户端启动成功=====
请说:
我是第三个线程
请说:

=====客户端启动成功=====
请说:
我是第四个线程
请说:
发送
请说:
我在消息队列
请说:
 

=====客户端启动成功=====
请说:
我是第五个线程
请说:
搜索
请说:
我在消息队列
请说:

进程已结束,退出代码为 -1

=====客户端启动成功=====
请说:
我是第六个线程
请说:
我是第六个线程
请说:
我在消息队列
请说:

=====客户端启动成功=====
请说:
我是第六个线程
请说:
我是第六个线程
请说:
我在消息队列
请说:

=====客户端启动成功=====
请说:
我是第七个线程
请说:
哈哈哈,前面的朋友
请说:
我有临时线程给我服务,你们继续等待把
请说:

=====客户端启动成功=====
请说:
我是第八个线程
请说:
啦啦啦
请说:
哎呦,这么多人啊
请说:
我先进去了
请说:

=====客户端启动成功=====
请说:
我是第九个线程
请说:
我去
请说:
???
请说:
报错了
请说:
 

 =====服务端启动成功=====
/127.0.0.1:52268它来了,上线了!
pool-1-thread-1线程/127.0.0.1:52268说了:我是第一个线程
/127.0.0.1:52296它来了,上线了!
pool-1-thread-2线程/127.0.0.1:52296说了:我是第二个线程
/127.0.0.1:52314它来了,上线了!
pool-1-thread-3线程/127.0.0.1:52314说了:我是第三个线程
/127.0.0.1:52327它来了,上线了!
/127.0.0.1:52268下线了
pool-1-thread-1线程/127.0.0.1:52327说了:我是第四个线程,由于我不是主线程,3个主线程都在忙,所以你收不到我的消息
pool-1-thread-1线程/127.0.0.1:52327说了:但是能看到我的上下线状态
pool-1-thread-1线程/127.0.0.1:52327说了:有一个线程关闭了
pool-1-thread-1线程/127.0.0.1:52327说了:我可以发送消息了
pool-1-thread-1线程/127.0.0.1:52327说了:现在我是第三个线程了
/127.0.0.1:52581它来了,上线了!
/127.0.0.1:52596它来了,上线了!
/127.0.0.1:52623它来了,上线了!
/127.0.0.1:52691它来了,上线了!
pool-1-thread-4线程/127.0.0.1:52691说了:我是第七个线程
pool-1-thread-4线程/127.0.0.1:52691说了:哈哈哈,前面的朋友
pool-1-thread-4线程/127.0.0.1:52691说了:我有临时线程给我服务,你们继续等待把
/127.0.0.1:52805它来了,上线了!
pool-1-thread-5线程/127.0.0.1:52805说了:我是第八个线程
pool-1-thread-5线程/127.0.0.1:52805说了:啦啦啦
pool-1-thread-5线程/127.0.0.1:52805说了:哎呦,这么多人啊
pool-1-thread-5线程/127.0.0.1:52805说了:我先进去了
/127.0.0.1:52856它来了,上线了!
Exception in thread "main" java.util.concurrent.RejectedExecutionException: Task com.wjh.d8_socket4.ServerReaderRunnable@52cc8049 rejected from java.util.concurrent.ThreadPoolExecutor@5b6f7412[Running, pool size = 5, active threads = 5, queued tasks = 3, completed tasks = 1]
    at java.base/java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2065)
    at java.base/java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:833)
    at java.base/java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1365)
    at com.wjh.d8_socket4.ServiceDemo2.main(ServiceDemo2.java:32)

        PS:由于代码抛异常时选择的直接抛,后面除了异常就会干掉程序,所以建议大家使用规范的try{        }catch{        }处理异常.

        还有如果队列里的线程下线了,第四个线程的任务会被立即执行!        

Java面向对象-网络编程(通信)_第60张图片

八.TCP通信实战案例-即时通信

Java面向对象-网络编程(通信)_第61张图片

 Java面向对象-网络编程(通信)_第62张图片

 Java面向对象-网络编程(通信)_第63张图片

九.TCP通信实战案例-模拟BS系统

Java面向对象-网络编程(通信)_第64张图片

Java面向对象-网络编程(通信)_第65张图片

package com.wjh.d10_bs;
/*

 */


import java.io.IOException;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.*;

public class BSServerDemo {

    //使用静态变量记住一个线程池对象
    private static ExecutorService pool = new ThreadPoolExecutor(3, 5, 6, TimeUnit.SECONDS
            , new ArrayBlockingQueue<>(3), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());

    public static void main(String[] args) {
        //1.注册端口
        try {
            ServerSocket ss = new ServerSocket(8080);
            //2.创建一个循环接受多个客户端的请求
            while (true) {
                Socket socket = ss.accept();
                //3.交给一个独立的线程来处理!
                pool.execute(new ServerReaderRunnable(socket));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    static class ServerReaderThread extends Thread {
        private Socket socket;

        public ServerReaderThread(Socket socket) {
            this.socket = socket;
        }

        @Override
        public void run() {
            //浏览器 已经与本线程建立了Socket管道
            //响应消息给浏览器显示
            PrintStream ps = null;
            try {
                ps = new PrintStream(socket.getOutputStream());
                //必须响应HTTP协议数据格式,否则浏览器不认识消息
                ps.println("HTTP/1.1 200 OK");  //协议类型和版本 响应成功的消息
                ps.println("Content-Type:text/html;charset=UTF-8");
                ps.println();   //必须发送一个空行
                //才可以响应数据回去给浏览器
                ps.println("最牛的ikun");
                ps.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

 Java面向对象-网络编程(通信)_第66张图片

Java面向对象-网络编程(通信)_第67张图片

 Java面向对象-网络编程(通信)_第68张图片

你可能感兴趣的:(Java面向对象进阶栏,网络,java,tcp/ip)