首页 > 编程语言 >JAVA进阶--网络通信--2022年9月15日

JAVA进阶--网络通信--2022年9月15日

时间:2022-09-18 14:34:06浏览次数:87  
标签:JAVA 进阶 java -- new import public Socket socket

第一节   网络编程

  1、什么是网络编程

    网络编程可以让程序与网络上的其他设备中的程序进行数据交互

  2、网络通信基本模式

    常见的通信模式有如下2中形式:Client-Server(CS)、Browser/Server(BS)

    

 

     

 

第二节   网络通信三要素

  1、说说网络通信至少需要几个要素

    IP地址:设备在网络中的地址,是唯一的标识

    端口:应用程序在设备中唯一的标识

    协议:数据在网络中传输的规则,常见的协议有UDP协议和TCP协议

    

  2、IP地址是做什么的,具体有几种

    定位网络上的设备,有IPv4,IPv6

    

 

     ================================================================================================

    

 

     ===================================================================================

    

  3、如何查看本机IP地址,如何看是否与对方互通

    ipconfig

    ping 192.168.10.23

    

  4、本机IP是谁

    127.0.0.1或者是localhost

  5、IP地址的代表类是谁

    InetAddress类

    

  6、如何获取本机IP对象

    public static InetAddress getLocalhost()

  7、如何判断与该IP地址对象是否互通

    public boolean isReachable(int timeout)

 1 package com.itheima.d1_inetAddress;
 2 import java.net.InetAddress;
 3 /**
 4     目标:InetAddress类概述(了解)
 5          一个该类的对象就代表一个IP地址对象。
 6 
 7     InetAddress类成员方法:
 8          static InetAddress getLocalHost()
 9             * 获得本地主机IP地址对象。
10          static InetAddress getByName(String host)
11             * 根据IP地址字符串或主机名获得对应的IP地址对象。
12          String getHostName()
13             * 获得主机名。
14          String getHostAddress()
15             * 获得IP地址字符串。
16  */
17 public class InetAddressDemo01 {
18     public static void main(String[] args) throws Exception {
19         // 1.获取本机地址对象。
20         InetAddress ip1 = InetAddress.getLocalHost();
21         System.out.println(ip1.getHostName());
22         System.out.println(ip1.getHostAddress());
23 
24         // 2.获取域名ip对象
25         InetAddress ip2 = InetAddress.getByName("www.baidu.com");
26         System.out.println(ip2.getHostName());
27         System.out.println(ip2.getHostAddress());
28 
29         // 3.获取公网IP对象。
30         InetAddress ip3 = InetAddress.getByName("112.80.248.76");
31         System.out.println(ip3.getHostName());
32         System.out.println(ip3.getHostAddress());
33 
34         // 4.判断是否能通: ping  5s之前测试是否可通
35         System.out.println(ip3.isReachable(5000));
36     }
37 }
InetAddressDemo01

  8、端口号的作用是什么?

    唯一标识正在计算机设备上运行的进程(程序)

  9、一个设备中,能否出现2个应用程序的端口号一样,为什么

    不可以,如果一样会出现端口冲突错误

  

  注意:一个程序在不同电脑上的端口应一致,不然会出错,就比如QQ的端口号是8888,那QQ在别人电脑上也应该是8888

  10、通信协议是什么

    计算机网络中,连接和通信数据的规则被称为网络通信协议

    

    ===================================================================================================

    

  11、TCP通信协议的特点是什么样的

    它是一种面向连接的可靠通信协议

    传输前,采用“三次握手”方式建议连接,点对点的通信,所以可靠

    传输后,采用“四次挥手”方式解除连接

    在连接中可进行大数据量的传输

    通信效率较低

    

 

     

 

     =============================================================================================

    

 

     

  12、UDP协议的特点是什么

    用户数据报协议(User Datagram Protocol)

    UDP是面向无连接,不可靠传输的通信协议

    速度快,有大小限制一次最多发送63K,数据不安全,易丢失数据

    

第三节   UDP通信

  0、UDP协议的特点

    UDP是一种无连接、不可靠传输的协议

    将数据源IP、目的地IP和端口以及数据封装成数据包,大小限制在64KB内,直接发送出去即可

  1、UDP发送端和接收端的对象是哪个

    public DatagramSocket():创建发送端的Socket对象  默认会有端口号

    public DatagramSocket(int port):创建接收端的Socket对象

  2、数据包对象是哪个

    DatagramPacket

  3、如何发送、接收数据包

    使用DatagramSocket的如下方法:

    public void send(DatagramPacket dp):发送数据包

    publis void receive(DatagramPacket dp):接收数据包

  

 

   ==============================================================================================

  

 

   

 

   ==================================================================================

  

 

   

 1 package com.itheima.d2_udp1;
 2 
 3 import java.net.DatagramPacket;
 4 import java.net.DatagramSocket;
 5 import java.net.InetAddress;
 6 import java.net.SocketException;
 7 
 8 /**
 9   发送端  一发 一收
10  */
11 public class ClientDemo1 {
12     public static void main(String[] args) throws Exception {
13         System.out.println("=====客户端启动======");
14 
15         // 1、创建发送端对象:发送端自带默认的端口号(人)
16         DatagramSocket socket = new DatagramSocket(6666);
17 
18         // 2、创建一个数据包对象封装数据(韭菜盘子)
19         /**
20          public DatagramPacket(byte buf[], int length,
21          InetAddress address, int port)
22          参数一:封装要发送的数据(韭菜)
23          参数二:发送数据的大小
24          参数三:服务端的主机IP地址
25          参数四:服务端的端口
26          */
27         byte[] buffer = "我是一颗快乐的韭菜,你愿意吃吗?".getBytes();
28         DatagramPacket packet = new DatagramPacket( buffer, buffer.length,
29                 InetAddress.getLocalHost() , 8888);
30 
31         // 3、发送数据出去
32         socket.send(packet);
33 
34         socket.close();
35     }
36 }
ClientDemo
 1 package com.itheima.d2_udp1;
 2 
 3 import java.net.DatagramPacket;
 4 import java.net.DatagramSocket;
 5 import java.net.SocketException;
 6 
 7 /**
 8   接收端
 9  */
10 public class ServerDemo2 {
11     public static void main(String[] args) throws Exception {
12         System.out.println("=====服务端启动======");
13         // 1、创建接收端对象:注册端口(人)
14         DatagramSocket socket = new DatagramSocket(8888);
15 
16         // 2、创建一个数据包对象接收数据(韭菜盘子)
17         byte[] buffer = new byte[1024 * 64];
18         DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
19 
20         // 3、等待接收数据。
21         socket.receive(packet);
22 
23         // 4、取出数据即可
24         // 读取多少倒出多少
25         int len = packet.getLength();
26         String rs = new String(buffer,0, len);
27         System.out.println("收到了:" + rs);
28 
29         // 获取发送端的ip和端口
30         String ip  =packet.getSocketAddress().toString();
31         System.out.println("对方地址:" + ip);
32 
33         int port  = packet.getPort();
34         System.out.println("对方端口:" + port);
35 
36         socket.close();
37     }
38 }
ServerDemo

  4、UDP通信:多发多收:UDP的接收端为什么可以接收很多发送端的消息?

    接收端只负责接收数据包,无所谓是哪个发送端的数据包

  

   ==========================================================================================

  

   =========================================================================================

  

 1 package com.itheima.d3_udp2;
 2 
 3 import java.net.DatagramPacket;
 4 import java.net.DatagramSocket;
 5 import java.net.InetAddress;
 6 import java.net.MulticastSocket;
 7 import java.util.Scanner;
 8 
 9 /**
10   发送端  多发 多收
11  */
12 public class ClientDemo1 {
13     public static void main(String[] args) throws Exception {
14         System.out.println("=====客户端启动======");
15 
16         // 1、创建发送端对象:发送端自带默认的端口号(人)
17         DatagramSocket socket = new DatagramSocket(7777);
18         
19 
20         Scanner sc = new Scanner(System.in);
21         while (true) {
22             System.out.println("请说:");
23             String msg = sc.nextLine();
24 
25             if("exit".equals(msg)){
26                 System.out.println("离线成功!");
27                 socket.close();
28                 break;
29             }
30 
31             // 2、创建一个数据包对象封装数据(韭菜盘子)
32             byte[] buffer = msg.getBytes();
33             DatagramPacket packet = new DatagramPacket( buffer, buffer.length,
34                     InetAddress.getLocalHost() , 8888);
35 
36             // 3、发送数据出去
37             socket.send(packet);
38         }
39 
40     }
41 }
ClientDemo
 1 package com.itheima.d3_udp2;
 2 
 3 import java.net.DatagramPacket;
 4 import java.net.DatagramSocket;
 5 
 6 /**
 7   接收端
 8  */
 9 public class ServerDemo2 {
10     public static void main(String[] args) throws Exception {
11         System.out.println("=====服务端启动======");
12         // 1、创建接收端对象:注册端口(人)
13         DatagramSocket socket = new DatagramSocket(8888);
14 
15         // 2、创建一个数据包对象接收数据(韭菜盘子)
16         byte[] buffer = new byte[1024 * 64];
17         DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
18 
19         while (true) {
20             // 3、等待接收数据。
21             socket.receive(packet);
22             // 4、取出数据即可
23             // 读取多少倒出多少
24             int len = packet.getLength();
25             String rs = new String(buffer,0, len);
26             System.out.println("收到了来自:" + packet.getAddress() +", 对方端口是" + packet.getPort() +"的消息:" + rs);
27         }
28     }
29 }
ServerDemo

  5、如何实现广播,具体怎么操作

    发送端目的IP使用广播IP:255.255.255.255  9999

    所在网段的其他主机对应了端口(9999)即可接收信息

    

    

  6、如何实现组播,具体怎么操作

    发送端目的IP使用组播IP,且指定端口

    所在网段的其他主机注册了该组播IP和对应端口即可接收信息

    

 1 package com.itheima.d4_upd3;
 2 
 3 import java.net.DatagramPacket;
 4 import java.net.DatagramSocket;
 5 import java.net.InetAddress;
 6 import java.util.Scanner;
 7 
 8 /**
 9   发送端  多发 多收
10  */
11 public class ClientDemo1 {
12     public static void main(String[] args) throws Exception {
13         System.out.println("=====客户端启动======");
14 
15         // 1、创建发送端对象:发送端自带默认的端口号(人)
16         DatagramSocket socket = new DatagramSocket();
17         
18 
19         Scanner sc = new Scanner(System.in);
20         while (true) {
21             System.out.println("请说:");
22             String msg = sc.nextLine();
23 
24             if("exit".equals(msg)){
25                 System.out.println("离线成功!");
26                 socket.close();
27                 break;
28             }
29 
30             // 2、创建一个数据包对象封装数据(韭菜盘子)
31             byte[] buffer = msg.getBytes();
32             // 注意:只要目的地IP是 255.255.255.255 这个消息将以广播的形式对外发送
33 //            DatagramPacket packet = new DatagramPacket( buffer, buffer.length,
34 //                    InetAddress.getByName("255.255.255.255") , 8888);
35 
36             DatagramPacket packet = new DatagramPacket( buffer, buffer.length,
37                     InetAddress.getByName("224.0.1.1") , 9898);
38 
39                     // 3、发送数据出去
40             socket.send(packet);
41         }
42 
43     }
44 }
ClientDemo
 1 package com.itheima.d4_upd3;
 2 
 3 import java.net.DatagramPacket;
 4 import java.net.DatagramSocket;
 5 
 6 /**
 7   接收端
 8  */
 9 public class ServerDemo2 {
10     public static void main(String[] args) throws Exception {
11         System.out.println("=====服务端启动======");
12         // 1、创建接收端对象:注册端口(人)
13         DatagramSocket socket = new DatagramSocket(8888);
14 
15         // 2、创建一个数据包对象接收数据(韭菜盘子)
16         byte[] buffer = new byte[1024 * 64];
17         DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
18 
19         while (true) {
20             // 3、等待接收数据。
21             socket.receive(packet);
22             // 4、取出数据即可
23             // 读取多少倒出多少
24             int len = packet.getLength();
25             String rs = new String(buffer,0, len);
26             System.out.println("收到了来自:" + packet.getAddress() +", 对方端口是" + packet.getPort() +"的消息:" + rs);
27         }
28     }
29 }
ServerDemo1
 1 package com.itheima.d4_upd3;
 2 
 3 import java.net.*;
 4 
 5 /**
 6   接收端
 7  */
 8 public class ServerDemo3 {
 9     public static void main(String[] args) throws Exception {
10         System.out.println("=====服务端启动======");
11         // 1、创建接收端对象:注册端口(人)
12         MulticastSocket socket = new MulticastSocket(9898);
13 
14         // 注意:绑定组播地址(加群)
15         socket.joinGroup(new InetSocketAddress(InetAddress.getByName("224.0.1.1") , 9898),
16                 NetworkInterface.getByInetAddress(InetAddress.getLocalHost()));
17 
18         // 2、创建一个数据包对象接收数据(韭菜盘子)
19         byte[] buffer = new byte[1024 * 64];
20         DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
21 
22 
23         while (true) {
24             // 3、等待接收数据。
25             socket.receive(packet);
26             // 4、取出数据即可
27             // 读取多少倒出多少
28             int len = packet.getLength();
29             String rs = new String(buffer,0, len);
30             System.out.println("收到了来自:" + packet.getAddress() +", 对方端口是" + packet.getPort() +"的消息:" + rs);
31         }
32     }
33 }
ServerDemo2

第四节   TCP通信

  1、TCP通信快速入门

  

  =========================================================================

  

    A、TCP通信的客户端的代表类是谁?

      Socket类

      public Socket(String host,int port)

      

    B、TCP通信如何使用Socket管道发送、接收数据

      OutputStream getOutputStream():获得字节输出流对象(发)

      InputStream getInputStream():获得字节输入流对象(收)

     

 1 package com.itheima.d5_socket1;
 2 
 3 import java.io.IOException;
 4 import java.io.OutputStream;
 5 import java.io.PrintStream;
 6 import java.net.Socket;
 7 
 8 /**
 9    目标:完成Socket网络编程入门案例的客户端开发,实现1发1收。
10  */
11 public class ClientDemo1 {
12     public static void main(String[] args) {
13         try {
14             System.out.println("====客户端启动===");
15             // 1、创建Socket通信管道请求有服务端的连接
16             // public Socket(String host, int port)
17             // 参数一:服务端的IP地址
18             // 参数二:服务端的端口
19             Socket socket = new Socket("127.0.0.1", 7777);
20 
21             // 2、从socket通信管道中得到一个字节输出流 负责发送数据
22             OutputStream os = socket.getOutputStream();
23 
24             // 3、把低级的字节流包装成打印流
25             PrintStream ps = new PrintStream(os);
26 
27             // 4、发送消息
28             ps.println("我是TCP的客户端,我已经与你对接,并发出邀请:约吗?");
29             ps.flush();
30 
31             // 关闭资源。
32             // socket.close();
33 
34         } catch (Exception e) {
35             e.printStackTrace();
36         }
37     }
38 }
ClientDemo

    C、TCP通信服务端用的代表类?

      ServerSocket类,注册端口

      调用accept()方法阻塞等待接收客户端连接。得到Socket对象

      

    D、TCP通信的基本原理

      客户端怎么发,服务端就应该怎么收

      客户端如果没有消息,服务端会进入阻塞等待

      Socket一方关闭或者出现异常、对方Socket也会失效或者出错

    

     =================================================================================================

    

 1 package com.itheima.d5_socket1;
 2 
 3 import java.io.BufferedReader;
 4 import java.io.IOException;
 5 import java.io.InputStream;
 6 import java.io.InputStreamReader;
 7 import java.net.ServerSocket;
 8 import java.net.Socket;
 9 
10 /**
11    目标:开发Socket网络编程入门代码的服务端,实现接收消息
12  */
13 public class ServerDemo2 {
14     public static void main(String[] args) {
15         try {
16             System.out.println("===服务端启动成功===");
17             // 1、注册端口
18             ServerSocket serverSocket = new ServerSocket(7777);
19             // 2、必须调用accept方法:等待接收客户端的Socket连接请求,建立Socket通信管道
20             Socket socket = serverSocket.accept();
21             // 3、从socket通信管道中得到一个字节输入流
22             InputStream is = socket.getInputStream();
23             // 4、把字节输入流包装成缓冲字符输入流进行消息的接收
24             BufferedReader br = new BufferedReader(new InputStreamReader(is));
25             // 5、按照行读取消息
26             String msg;
27             if ((msg = br.readLine()) != null){
28                 System.out.println(socket.getRemoteSocketAddress() + "说了:: " + msg);
29             }
30         } catch (Exception e) {
31             e.printStackTrace();
32         }
33     }
34 }
ServerDemo 

  2、TCP通信:多发多收消息

    A、本次多发多收是如何实现的

      客户端使用循环反复地发送消息

      服务端使用循环反复地接收信息

    B、现在服务端为什么不可以同时接收多个客户端的消息

      目前服务端是单线程的,每次只能处理一个客户端的消息

    

 1 package com.itheima.d6_socket2;
 2 
 3 import java.io.OutputStream;
 4 import java.io.PrintStream;
 5 import java.net.Socket;
 6 import java.util.Scanner;
 7 
 8 /**
 9    目标:实现多发和多收
10  */
11 public class ClientDemo1 {
12     public static void main(String[] args) {
13         try {
14             System.out.println("====客户端启动===");
15             // 1、创建Socket通信管道请求有服务端的连接
16             // public Socket(String host, int port)
17             // 参数一:服务端的IP地址
18             // 参数二:服务端的端口
19             Socket socket = new Socket("127.0.0.1", 7777);
20 
21             // 2、从socket通信管道中得到一个字节输出流 负责发送数据
22             OutputStream os = socket.getOutputStream();
23 
24             // 3、把低级的字节流包装成打印流
25             PrintStream ps = new PrintStream(os);
26 
27             Scanner sc =  new Scanner(System.in);
28             while (true) {
29                 System.out.println("请说:");
30                 String msg = sc.nextLine();
31                 // 4、发送消息
32                 ps.println(msg);
33                 ps.flush();
34             }
35 
36             // 关闭资源。
37             // socket.close();
38 
39         } catch (Exception e) {
40             e.printStackTrace();
41         }
42     }
43 }
ClientDemo
 1 package com.itheima.d6_socket2;
 2 
 3 import java.io.BufferedReader;
 4 import java.io.InputStream;
 5 import java.io.InputStreamReader;
 6 import java.net.ServerSocket;
 7 import java.net.Socket;
 8 
 9 /**
10    目标:开发Socket网络编程入门代码的服务端,实现接收消息
11  */
12 public class ServerDemo2 {
13     public static void main(String[] args) {
14         try {
15             System.out.println("===服务端启动成功===");
16             // 1、注册端口
17             ServerSocket serverSocket = new ServerSocket(7777);
18             while (true) {
19                 // 2、必须调用accept方法:等待接收客户端的Socket连接请求,建立Socket通信管道
20                 Socket socket = serverSocket.accept();
21                 // 3、从socket通信管道中得到一个字节输入流
22                 InputStream is = socket.getInputStream();
23                 // 4、把字节输入流包装成缓冲字符输入流进行消息的接收
24                 BufferedReader br = new BufferedReader(new InputStreamReader(is));
25                 // 5、按照行读取消息
26                 String msg;
27                 while ((msg = br.readLine()) != null){
28                     System.out.println(socket.getRemoteSocketAddress() + "说了:: " + msg);
29                 }
30             }
31         } catch (Exception e) {
32             e.printStackTrace();
33         }
34     }
35 }
ServerDemo

  3、TCP通信:同时接收多个客户端消息

    A、本次是如何实现服务端接收多个客户端的消息的

      主线程定义了循环负责接收客户端Socket管道连接

      每接收到一个Socket通信管道后分配一个独立的线程负责处理它

      

 1 package com.itheima.d7_socket3;
 2 
 3 import java.io.OutputStream;
 4 import java.io.PrintStream;
 5 import java.net.Socket;
 6 import java.util.Scanner;
 7 
 8 /**
 9     目标:实现服务端可以同时处理多个客户端的消息。
10  */
11 public class ClientDemo1 {
12     public static void main(String[] args) {
13         try {
14             System.out.println("====客户端启动===");
15             // 1、创建Socket通信管道请求有服务端的连接
16             // public Socket(String host, int port)
17             // 参数一:服务端的IP地址
18             // 参数二:服务端的端口
19             Socket socket = new Socket("127.0.0.1", 7777);
20 
21             // 2、从socket通信管道中得到一个字节输出流 负责发送数据
22             OutputStream os = socket.getOutputStream();
23 
24             // 3、把低级的字节流包装成打印流
25             PrintStream ps = new PrintStream(os);
26 
27             Scanner sc =  new Scanner(System.in);
28             while (true) {
29                 System.out.println("请说:");
30                 String msg = sc.nextLine();
31                 // 4、发送消息
32                 ps.println(msg);
33                 ps.flush();
34             }
35 
36             // 关闭资源。
37             // socket.close();
38 
39         } catch (Exception e) {
40             e.printStackTrace();
41         }
42     }
43 }
Client
 1 package com.itheima.d7_socket3;
 2 
 3 import java.io.BufferedReader;
 4 import java.io.InputStream;
 5 import java.io.InputStreamReader;
 6 import java.net.ServerSocket;
 7 import java.net.Socket;
 8 
 9 /**
10    目标:实现服务端可以同时处理多个客户端的消息。
11  */
12 public class ServerDemo2 {
13     public static void main(String[] args) {
14         try {
15             System.out.println("===服务端启动成功===");
16             // 1、注册端口
17             ServerSocket serverSocket = new ServerSocket(7777);
18             // a.定义一个死循环由主线程负责不断的接收客户端的Socket管道连接。
19             while (true) {
20                 // 2、每接收到一个客户端的Socket管道,交给一个独立的子线程负责读取消息
21                 Socket socket = serverSocket.accept();
22                 System.out.println(socket.getRemoteSocketAddress()+ "它来了,上线了!");
23                 // 3、开始创建独立线程处理socket
24                 new ServerReaderThread(socket).start();
25             }
26         } catch (Exception e) {
27             e.printStackTrace();
28         }
29     }
30 }
ServerDemo
 1 package com.itheima.d7_socket3;
 2 
 3 import java.io.BufferedReader;
 4 import java.io.InputStream;
 5 import java.io.InputStreamReader;
 6 import java.net.Socket;
 7 
 8 public class ServerReaderThread extends Thread{
 9     private Socket socket;
10     public ServerReaderThread(Socket socket){
11         this.socket = socket;
12     }
13     @Override
14     public void run() {
15         try {
16             // 3、从socket通信管道中得到一个字节输入流
17             InputStream is = socket.getInputStream();
18             // 4、把字节输入流包装成缓冲字符输入流进行消息的接收
19             BufferedReader br = new BufferedReader(new InputStreamReader(is));
20             // 5、按照行读取消息
21             String msg;
22             while ((msg = br.readLine()) != null){
23                 System.out.println(socket.getRemoteSocketAddress() + "说了:: " + msg);
24             }
25         } catch (Exception e) {
26             System.out.println(socket.getRemoteSocketAddress() + "下线了!!!");
27         }
28     }
29 }
ServerReaderThread

  4、TCP通信:使用线程池优化

    A、上面多收多发的通信架构存在什么问题?

      客户端与服务端的线程模型是N-N的关系

      客户端并发越多,系统瘫痪的越快

      

    B、本次使用线程池的优势在哪里?

      服务端可以复用线程处理多个客户端,可以避免系统瘫痪

      合适客户端通信时长较短的场景

      

 1 package com.itheima.d8_socket4;
 2 
 3 import java.io.OutputStream;
 4 import java.io.PrintStream;
 5 import java.net.Socket;
 6 import java.util.Scanner;
 7 
 8 /**
 9     拓展:使用线程池优化:实现通信。
10  */
11 public class ClientDemo1 {
12     public static void main(String[] args) {
13         try {
14             System.out.println("====客户端启动===");
15             // 1、创建Socket通信管道请求有服务端的连接
16             // public Socket(String host, int port)
17             // 参数一:服务端的IP地址
18             // 参数二:服务端的端口
19             Socket socket = new Socket("127.0.0.1", 6666);
20 
21             // 2、从socket通信管道中得到一个字节输出流 负责发送数据
22             OutputStream os = socket.getOutputStream();
23 
24             // 3、把低级的字节流包装成打印流
25             PrintStream ps = new PrintStream(os);
26 
27             Scanner sc =  new Scanner(System.in);
28             while (true) {
29                 System.out.println("请说:");
30                 String msg = sc.nextLine();
31                 // 4、发送消息
32                 ps.println(msg);
33                 ps.flush();
34             }
35             // 关闭资源。
36             // socket.close();
37 
38         } catch (Exception e) {
39             e.printStackTrace();
40         }
41     }
42 }
Client
 1 package com.itheima.d8_socket4;
 2 import com.itheima.d7_socket3.ServerReaderThread;
 3 
 4 import java.net.ServerSocket;
 5 import java.net.Socket;
 6 import java.util.concurrent.*;
 7 
 8 /**
 9    目标:实现服务端可以同时处理多个客户端的消息。
10  */
11 public class ServerDemo2 {
12 
13     // 使用静态变量记住一个线程池对象
14     private static ExecutorService pool = new ThreadPoolExecutor(300,
15             1500, 6, TimeUnit.SECONDS,
16             new ArrayBlockingQueue<>(2)
17     , Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());
18 
19     public static void main(String[] args) {
20         try {
21             System.out.println("===服务端启动成功===");
22             // 1、注册端口
23             ServerSocket serverSocket = new ServerSocket(6666);
24             // a.定义一个死循环由主线程负责不断的接收客户端的Socket管道连接。
25             while (true) {
26                 // 2、每接收到一个客户端的Socket管道,
27                 Socket socket = serverSocket.accept();
28                 System.out.println(socket.getRemoteSocketAddress()+ "它来了,上线了!");
29 
30                 // 任务对象负责读取消息。
31                 Runnable target = new ServerReaderRunnable(socket);
32                 pool.execute(target);
33             }
34         } catch (Exception e) {
35             e.printStackTrace();
36         }
37     }
38 }
Server
 1 package com.itheima.d8_socket4;
 2 
 3 import java.io.BufferedReader;
 4 import java.io.InputStream;
 5 import java.io.InputStreamReader;
 6 import java.net.Socket;
 7 
 8 public class ServerReaderRunnable implements Runnable{
 9     private Socket socket;
10     public ServerReaderRunnable(Socket socket){
11         this.socket = socket;
12     }
13     @Override
14     public void run() {
15         try {
16             // 3、从socket通信管道中得到一个字节输入流
17             InputStream is = socket.getInputStream();
18             // 4、把字节输入流包装成缓冲字符输入流进行消息的接收
19             BufferedReader br = new BufferedReader(new InputStreamReader(is));
20             // 5、按照行读取消息
21             String msg;
22             while ((msg = br.readLine()) != null){
23                 System.out.println(socket.getRemoteSocketAddress() + "说了:: " + msg);
24             }
25         } catch (Exception e) {
26             System.out.println(socket.getRemoteSocketAddress() + "下线了!!!");
27         }
28     }
29 }
ServerReaderRunnable

  5、TCP通信实战案例:即时通信

    A、即时通信是什么含义,要实现怎么样的设计?

      即时通信,是指一个客户端的消息发出去,其他客户端可以接收到

      即使通信需要进行端口转发的设计思想

      服务端需要把在线的Socket管道存储起来

      一旦收到一个消息要推送给其他管道

      

 1 package com.itheima.d9_chat;
 2 
 3 import java.io.OutputStream;
 4 import java.io.PrintStream;
 5 import java.net.Socket;
 6 import java.util.Scanner;
 7 
 8 /**
 9     拓展:即时通信
10 
11     客户端:发消息的同时,随时有人发消息过来。
12     服务端:接收消息后,推送给其他所有的在线socket
13  */
14 public class ClientDemo1 {
15     public static void main(String[] args) {
16         try {
17             System.out.println("====客户端启动===");
18             // 1、创建Socket通信管道请求有服务端的连接
19             // public Socket(String host, int port)
20             // 参数一:服务端的IP地址
21             // 参数二:服务端的端口
22             Socket socket = new Socket("127.0.0.1", 6868);
23 
24             // 马上为客户端分配一个独立的线程负责读取它收到的消息
25             new ClientReaderThread(socket).start();
26 
27             // 2、从socket通信管道中得到一个字节输出流 负责发送数据
28             OutputStream os = socket.getOutputStream();
29 
30             // 3、把低级的字节流包装成打印流
31             PrintStream ps = new PrintStream(os);
32 
33             Scanner sc =  new Scanner(System.in);
34             while (true) {
35                 System.out.println("请说:");
36                 String msg = sc.nextLine();
37                 // 4、发送消息
38                 ps.println(msg);
39                 ps.flush();
40             }
41             // 关闭资源。
42             // socket.close();
43 
44         } catch (Exception e) {
45             e.printStackTrace();
46         }
47     }
48 }
ClientDemo
 1 package com.itheima.d9_chat;
 2 
 3 import java.io.BufferedReader;
 4 import java.io.InputStream;
 5 import java.io.InputStreamReader;
 6 import java.io.PrintStream;
 7 import java.net.Socket;
 8 
 9 public class ClientReaderThread extends Thread{
10     private Socket socket;
11     public ClientReaderThread(Socket socket){
12         this.socket = socket;
13     }
14     @Override
15     public void run() {
16         try {
17             // 3、从socket通信管道中得到一个字节输入流
18             InputStream is = socket.getInputStream();
19             // 4、把字节输入流包装成缓冲字符输入流进行消息的接收
20             BufferedReader br = new BufferedReader(new InputStreamReader(is));
21             // 5、按照行读取消息
22             String msg;
23             while ((msg = br.readLine()) != null){
24                 System.out.println(socket.getRemoteSocketAddress() + "收到了: " + msg);
25             }
26         } catch (Exception e) {
27             System.out.println("服务端把你踢出去了~~");
28         }
29     }
30 
31 }
ClientReaderThread
 1 package com.itheima.d9_chat;
 2 
 3 import java.net.ServerSocket;
 4 import java.net.Socket;
 5 import java.util.ArrayList;
 6 import java.util.List;
 7 
 8 /**
 9    目标: 即时通信
10  */
11 public class ServerDemo2 {
12 
13     public static List<Socket> onLineSockets = new ArrayList<>();
14 
15     public static void main(String[] args) {
16         try {
17             System.out.println("===服务端启动成功===");
18             // 1、注册端口
19             ServerSocket serverSocket = new ServerSocket(6868);
20             // a.定义一个死循环由主线程负责不断的接收客户端的Socket管道连接。
21             while (true) {
22                 // 2、每接收到一个客户端的Socket管道,交给一个独立的子线程负责读取消息
23                 Socket socket = serverSocket.accept();
24                 System.out.println(socket.getRemoteSocketAddress()+ "它来了,上线了!");
25                 // 把当前客户端管道Socket加入到在线集合中去
26                 onLineSockets.add(socket);
27 
28                 // 3、开始创建独立线程处理socket
29                 new ServerReaderThread(socket).start();
30             }
31         } catch (Exception e) {
32             e.printStackTrace();
33         }
34     }
35 }
ServerDemo
 1 package com.itheima.d9_chat;
 2 
 3 import java.io.*;
 4 import java.net.Socket;
 5 
 6 public class ServerReaderThread extends Thread{
 7     private Socket socket;
 8     public ServerReaderThread(Socket socket){
 9         this.socket = socket;
10     }
11     @Override
12     public void run() {
13         try {
14             // 3、从socket通信管道中得到一个字节输入流
15             InputStream is = socket.getInputStream();
16             // 4、把字节输入流包装成缓冲字符输入流进行消息的接收
17             BufferedReader br = new BufferedReader(new InputStreamReader(is));
18             // 5、按照行读取消息
19             String msg;
20             while ((msg = br.readLine()) != null){
21                 System.out.println(socket.getRemoteSocketAddress() + "说了:: " + msg);
22                 // 把这个消息发给当前所有在线socket
23                 sendMsgToAll(msg);
24             }
25         } catch (Exception e) {
26             System.out.println(socket.getRemoteSocketAddress() + "下线了!!!");
27             // 从在线集合中抹掉本客户端socket
28             ServerDemo2.onLineSockets.remove(socket);
29         }
30     }
31 
32     private void sendMsgToAll(String msg) {
33         try {
34             // 遍历全部的在线 socket给他们发消息
35             for (Socket onLineSocket : ServerDemo2.onLineSockets) {
36                 // 除了自己的socket,其他socket我都发!!
37                 if(onLineSocket != socket){
38                     PrintStream ps = new PrintStream(socket.getOutputStream());
39                     ps.println(msg);
40                     ps.flush();
41                 }
42             }
43         } catch (Exception e) {
44             e.printStackTrace();
45         }
46     }
47 }
ServerReaderDemo

  6、TCP通信实战案例:模拟BS系统

    A、TCP通信如何实现BS请求网页信息回来呢

      客户端使用浏览器发起请求(不需要开发客户端)

      服务端必须按照浏览器的协议规则响应数据

      浏览器使用什么协议规则呢

      HTTP协议

      

      ===========================================================================================================================

      

 1 package com.itheima.d10_bs;
 2 
 3 import java.io.PrintStream;
 4 import java.net.ServerSocket;
 5 import java.net.Socket;
 6 import java.util.concurrent.*;
 7 
 8 /**
 9     了解:BS-浏览器-服务器基本了解。
10 
11     引入:
12         之前客户端和服务端都需要自己开发。也就是CS架构。
13         接下来模拟一下BS架构。
14 
15     客户端:浏览器。(无需开发)
16     服务端:自己开发。
17     需求:在浏览器中请求本程序,响应一个网页文字给浏览器显示
18 
19 
20  */
21 public class BSserverDemo {
22     // 使用静态变量记住一个线程池对象
23     private static ExecutorService pool = new ThreadPoolExecutor(3,
24             5, 6, TimeUnit.SECONDS,
25             new ArrayBlockingQueue<>(2)
26             , Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());
27 
28     public static void main(String[] args) {
29         try {
30             // 1.注册端口
31             ServerSocket ss = new ServerSocket(8080);
32             // 2.创建一个循环接收多个客户端的请求。
33             while(true){
34                 Socket socket = ss.accept();
35                 // 3.交给一个独立的线程来处理!
36                 pool.execute(new ServerReaderRunnable(socket));
37             }
38         } catch (Exception e) {
39             e.printStackTrace();
40         }
41     }
42 }
BServer
 1 package com.itheima.d10_bs;
 2 
 3 import java.io.BufferedReader;
 4 import java.io.InputStream;
 5 import java.io.InputStreamReader;
 6 import java.io.PrintStream;
 7 import java.net.Socket;
 8 
 9 public class ServerReaderRunnable implements Runnable{
10     private Socket socket;
11     public ServerReaderRunnable(Socket socket){
12         this.socket = socket;
13     }
14     @Override
15     public void run() {
16         try {
17             // 浏览器 已经与本线程建立了Socket管道
18             // 响应消息给浏览器显示
19             PrintStream ps = new PrintStream(socket.getOutputStream());
20             // 必须响应HTTP协议格式数据,否则浏览器不认识消息
21             ps.println("HTTP/1.1 200 OK"); // 协议类型和版本 响应成功的消息!
22             ps.println("Content-Type:text/html;charset=UTF-8"); // 响应的数据类型:文本/网页
23 
24             ps.println(); // 必须发送一个空行
25 
26             // 才可以响应数据回去给浏览器
27             ps.println("<span style='color:red;font-size:90px'>《最牛的149期》 </span>");
28             ps.close();
29         } catch (Exception e) {
30             System.out.println(socket.getRemoteSocketAddress() + "下线了!!!");
31         }
32     }
33 }
ServerReaderRunnable 

标签:JAVA,进阶,java,--,new,import,public,Socket,socket
From: https://www.cnblogs.com/Flower--Dance/p/16696812.html

相关文章

  • Csharp: Prototype Patterns
     ///<summary>///SummarydescriptionforSwimmer///geovindu,GeovinDu,涂聚文///原型模式(PrototypePatterns)///</summary>public......
  • doris环境部署(小白上手+部署适用)
    重要:doris不支持单机部署,至少三副本集群部署策略:节点1配置FE(Leader):192.168.30.37节点2配置BE:192.168.30.40节点4配置BE:192.168.30.41节点3配置BE:192.168.30.42环境部......
  • 从零打造“乞丐版” React(一)——从命令式编程到声明式编程
    这个系列的目的是通过使用JS实现“乞丐版”的React,让读者了解React的基本工作原理,体会React带来的构建应用的优势1HTML构建静态页面使用HTML和CSS,我们很容......
  • this.$set用法
    原文地址:https://www.cnblogs.com/birdy-silhouette/p/14793709.htmlthis.$set()的主要功能是解决改变数据时未驱动视图的改变的问题,也就是实际数据被改变了,但我们看到的......
  • 链表二
    继上次的链表一,已经熟悉了链表大致的结构,这篇则是讲基本链表的最终形态首先来确定一下需要学习链表的哪些东西:添加、打印、寻找、删除和清除voidadd(List*pList,in......
  • css 基础入门
    目录基础入门CSS语法CSS选择器基础选择器标签选择器类选择器id选择器群选择器全局选择器层级选择器子选择器基础入门前面部分我们知道可以通过直接指定style属性来配置D......
  • 用java实现按层数打印空心菱形
     //////////////打印空心菱形的代码classHomework15{publicstaticvoidmain(String[]args){ScannermyScanner=newScanner(System.in);......
  • vue 登录滑块验证
    实现效果:验证通过效果:添加组件sliderCheck.vue<template><divclass="drag"ref="dragDiv"><divclass="drag_bg"></div><divclass="drag_text">{{co......
  • samll point for java
    importjava.util.Scanner;publicclassMain{publicstaticvoidmain(String[]args){//Scannersc=newScanner(System.in);intcount[]=ne......
  • 关于朋友圈出现的小米新店广告骗局(非法获取个人消息)木马通过广东政务服务网(tyrz.gd.g
     前两天在朋友圈突然看到有发小米新店开业送千台扫地机器人的广告,出于天上不会掉馅饼到我身上的原则我选择忽略了,但是没多久看到他又晒了个物流订单,于是还是点开看......