网络通信3要素
![在这里插入图片描述](https://img-blog.csdnimg.cn/3c739f5333754e538b18259540974724.png)
![在这里插入图片描述](https://img-blog.csdnimg.cn/035758e3ba3141f08375de4fee9aa3fe.png)
![在这里插入图片描述](https://img-blog.csdnimg.cn/15c9be2b4ed94dc59ad2b2dcab66f76c.png)
要素1:IP地址
![在这里插入图片描述](https://img-blog.csdnimg.cn/eba2165a1e4a4dac80dad8d92274c445.png)
![在这里插入图片描述](https://img-blog.csdnimg.cn/4a98c00f4e974de0bc360f432c27e978.png)
![在这里插入图片描述](https://img-blog.csdnimg.cn/d906d6ffb38045ccad9b2d9e29a62482.jpeg#pic_center)
![在这里插入图片描述](https://img-blog.csdnimg.cn/b807ee1775664dd0bf0aa595d1592428.jpeg#pic_center)
IP地址操作类: InetAddress
![在这里插入图片描述](https://img-blog.csdnimg.cn/aed4d24d75c9408594e365e35f77a474.png)
package com.heima.test;
import java.net.InetAddress;
import java.net.UnknownHostException;
public class InetAddressDemo {
public static void main(String[] args) throws Exception {
//获取本机地址对象
InetAddress ip1 = InetAddress.getLocalHost();
//本机局域网ip地址
System.out.println(ip1);
//主机名
System.out.println(ip1.getHostName());
//局域网ip地址
System.out.println(ip1.getHostAddress());
//获取域名ip对象
InetAddress ip2 = InetAddress.getByName("www.baidu.com");
System.out.println(ip2.getHostName());
System.out.println(ip2.getHostAddress());
//获取公网ip对象
InetAddress ip3 = InetAddress.getByName("119.63.197.151");
System.out.println(ip3.getHostName());
System.out.println(ip3.getHostAddress());
//判断是否能通:ping 5s之内测试是否可通
System.out.println(ip3.isReachable(5000));
}
}
![在这里插入图片描述](https://img-blog.csdnimg.cn/35c15a7791e34960ab298ed2e9745af1.png)
要素2:端口号
![在这里插入图片描述](https://img-blog.csdnimg.cn/592decb691664d5991e89daa18d09ff3.png)
要素3:协议
![在这里插入图片描述](https://img-blog.csdnimg.cn/9665ed6ee1064044adbb2d55aa285343.png)
![在这里插入图片描述](https://img-blog.csdnimg.cn/8fb259d9279c489a8253c67ab325c54d.png)
![在这里插入图片描述](https://img-blog.csdnimg.cn/2bcf1cb3fe1144069b39ea4c4a2deb9c.png)
![在这里插入图片描述](https://img-blog.csdnimg.cn/0379f41d587842c1a1c4256a023a6bf1.png)
![在这里插入图片描述](https://img-blog.csdnimg.cn/565b1822d41f49db818a82b3a6bf1840.png)
![在这里插入图片描述](https://img-blog.csdnimg.cn/4e2660fb5a7d4149ab5a9b712002ed0b.png)
![在这里插入图片描述](https://img-blog.csdnimg.cn/816d31cb953b471398b1214a1b7dc367.png)
UDP通信
基础知识
![在这里插入图片描述](https://img-blog.csdnimg.cn/e3527860dcc74bbc88d6b9dc4776dc5f.png)
![在这里插入图片描述](https://img-blog.csdnimg.cn/c1a42c4b5fd64d28bd1b8c412a6a4cd0.png)
![在这里插入图片描述](https://img-blog.csdnimg.cn/393cb3ca471e43f092cd488fc1748ae3.png)
package com.heima.test.TCP;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
//接收端
public class ServerDemo {
public static void main(String[] args) throws Exception {
System.out.println("============服务端先启动=============");
//创建接收端对象,注册端口号要与发送端一致
DatagramSocket socket = new DatagramSocket(8888);
//创建数据包对象接收数据
byte[] buffer = new byte[1024 * 64];
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
//等待接受数据
socket.receive(packet);
//取出数据
//读取多少倒出多少
int len = packet.getLength();
String s = new String(buffer, 0, len);
System.out.println("收到了 :" + s);
//获取发送端的ip和端口
String ip = packet.getSocketAddress().toString();
System.out.println("对方的地址 :" + ip);
int port = packet.getPort();
System.out.println("对方端口 : " + port);
socket.close();
}
}
![在这里插入图片描述](https://img-blog.csdnimg.cn/ee0eb3c4699a4f989f78c9851d0540ee.png)
package com.heima.test.TCP;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
//发送端
public class ClientDemo {
public static void main(String[] args) throws Exception {
System.out.println("=================客户端后启动===================");
//创建发送端对象,自带默认端口
DatagramSocket socket = new DatagramSocket(6666);
//创建一个数据包对象封装数据
// public DatagramPacket(byte buf[], int length,
// InetAddress address, int port) {
// this(buf, 0, length, address, port);
//buf[] 封装要发送的数据
//length 此字节数组的长度
//服务端ip地址
//服务端端口
byte[] buffer = "我是一个中国人".getBytes();
DatagramPacket packet = new DatagramPacket(buffer, buffer.length, InetAddress.getLocalHost(), 8888);
//发送数据
socket.send(packet);
//关闭管道
socket.close();
}
}
![在这里插入图片描述](https://img-blog.csdnimg.cn/5583a84b270344eeb096e2432b448d4c.png)
![在这里插入图片描述](https://img-blog.csdnimg.cn/0dff98d4c7514a6bba9d487952ccb69d.png)
多发多收
![在这里插入图片描述](https://img-blog.csdnimg.cn/9e1079dd8ea54bd388a1a4cb7b6a5299.png)
![在这里插入图片描述](https://img-blog.csdnimg.cn/6e3d593565bd409a971b48ca534ea72e.png)
![在这里插入图片描述](https://img-blog.csdnimg.cn/cfb0514ea22d4618b870cb155449840e.png)
![在这里插入图片描述](https://img-blog.csdnimg.cn/4485e988a99440d8bf13837938c725f8.png)
package com.heima.test.TCP;
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();
Scanner sc = new Scanner(System.in);
while (true) {
//按行收发消息
System.out.println("请你说 : ");
String msg = sc.nextLine();
if ("exit".equals(msg)){
System.out.println("离线成功");
socket.close();
break;
}
//创建一个数据包对象封装数据
byte[] buffer = msg.getBytes();
//DatagramPacket packet = new DatagramPacket(buffer, buffer.length, InetAddress.getLocalHost(), 8888);
DatagramPacket packet = new DatagramPacket(buffer, buffer.length, InetAddress.getByName("192.168.0.109"), 9999);
//发送数据
socket.send(packet);
}
}
}
package com.heima.test.TCP;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
//接收端
public class ServerDemo1 {
public static void main(String[] args) throws Exception {
System.out.println("============服务端1先启动=============");
//创建接收端对象,注册端口号要与发送端一致
DatagramSocket socket = new DatagramSocket(9999);
//创建数据包对象接收数据
byte[] buffer = new byte[1024 * 64];
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
while (true) {
//等待接受数据
socket.receive(packet);
//取出数据
//读取多少倒出多少
int len = packet.getLength();
String s = new String(buffer, 0, len);
System.out.println("收到了来自 :" + packet.getAddress() + ",对方端口是" + packet.getPort() + "的消息 : " + s);
}
}
}
![在这里插入图片描述](https://img-blog.csdnimg.cn/93bfe3e7befb4d74b07bb382ba794b81.png)
![在这里插入图片描述](https://img-blog.csdnimg.cn/9b24bf8c3a034d6182cf55dc120d24c1.png)
广播,组播
![在这里插入图片描述](https://img-blog.csdnimg.cn/c23ca9ddc8b44d9b8fcca884290f8cd1.png)
![在这里插入图片描述](https://img-blog.csdnimg.cn/5a819e8c46b44b9589fbee7b8d88b7a6.png)
package com.hyway.delivergoods.test;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Scanner;
public class UDPClientBroadcast {
public static void main(String[] args) throws Exception {
System.out.println("=========windows笔记本客户端启动=========");
DatagramSocket socket = new DatagramSocket();
Scanner sc = new Scanner(System.in);
while (true) {
System.out.println("请输入消息 : ");
String msg = sc.nextLine();
if ("exit".equals(msg)) {
System.out.println("离线成功");
socket.close();
return;
}
byte[] buffer = msg.getBytes();
DatagramPacket packet = new DatagramPacket(buffer, buffer.length, InetAddress.getByName("255.255.255.255"), 9999);
socket.send(packet);
}
}
}
package com.hyway.delivergoods.test;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
public class UDPServerBroadcast {
public static void main(String[] args) throws Exception {
System.out.println("=============windows笔记本服务端启动==============");
DatagramSocket socket = new DatagramSocket(9999);
byte[] buffer = new byte[1024 * 8];
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
while (true) {
socket.receive(packet);
int len = packet.getLength();
String s = new String(buffer, 0, len);
System.out.println("收到了来自mac :" + packet.getAddress() + ",对方端口是 " + packet.getPort() + "的消息 :" + s);
}
}
}
![在这里插入图片描述](https://img-blog.csdnimg.cn/08d69cb160eb4b0f96e639125de642d5.png)
![在这里插入图片描述](https://img-blog.csdnimg.cn/35cc6d05a78c471ca218585a09989e71.png)
- 组播
package com.hyway.delivergoods.test;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Scanner;
public class UDPClientGroupcast {
public static void main(String[] args) throws Exception {
System.out.println("=========windows笔记本客户端启动=========");
DatagramSocket socket = new DatagramSocket();
Scanner sc = new Scanner(System.in);
while (true) {
System.out.println("请输入消息 : ");
String msg = sc.nextLine();
if ("exit".equals(msg)) {
System.out.println("离线成功");
socket.close();
return;
}
byte[] buffer = msg.getBytes();
DatagramPacket packet = new DatagramPacket(buffer, buffer.length, InetAddress.getByName("224.0.1.1"), 9999);
socket.send(packet);
}
}
}
package com.hyway.delivergoods.test;
import java.net.*;
public class UDPServerGroupcast {
public static void main(String[] args) throws Exception {
System.out.println("=============windows笔记本服务端启动==============");
MulticastSocket socket = new MulticastSocket(9999);
//当前接收端加入一个组播组中去,绑定对应的组播消息的组播IP
//此方法可用,可是过时了
//socket.joinGroup(InetAddress.getByName("224.0.1.1"));
//第二个参数是当前主机所在的网段
socket.joinGroup(new InetSocketAddress(InetAddress.getByName("224.0.1.1"),9999),
NetworkInterface.getByInetAddress(InetAddress.getLocalHost()));
byte[] buffer = new byte[1024 * 8];
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
while (true) {
socket.receive(packet);
int len = packet.getLength();
String s = new String(buffer, 0, len);
System.out.println("收到了来自mac :" + packet.getAddress() + ",对方端口是 " + packet.getPort() + "的消息 :" + s);
}
}
}
![在这里插入图片描述](https://img-blog.csdnimg.cn/b926b7bf5f64470a8ad0574cd189640b.png)
![在这里插入图片描述](https://img-blog.csdnimg.cn/7b497eeabef040c98ca547fe79025fa9.png)
![在这里插入图片描述](https://img-blog.csdnimg.cn/bb2dc3a8787a41cdbde135f31e060581.png)
TCP通信
基础知识-Socket套接字
![在这里插入图片描述](https://img-blog.csdnimg.cn/b7ebbb45863646bd82fbe8c2daff2418.png)
![在这里插入图片描述](https://img-blog.csdnimg.cn/03e50a016907457e964186fe2f9d2112.png)
![在这里插入图片描述](https://img-blog.csdnimg.cn/63574813e0504ad2bd1915151c114acd.png)
![在这里插入图片描述](https://img-blog.csdnimg.cn/6fe030468ddb45c085086a9cd8efe78f.png)
package com.heima.test.TCP1;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.Socket;
//Socket网络编程的客户端,实现一发一收
public class SocketClient {
public static void main(String[] args) {
try {
System.out.println("==============客户端启动成功==============");
//创建Socket通信管道请求服务端的连接
//服务端的IP地址,服务端的端口
Socket socket = new Socket("127.0.0.1", 7777);
//从socket通信管道中得到一个字节输出流,负责发送数据
OutputStream os = socket.getOutputStream();
//把低级的字节流包装成打印流
PrintStream ps = new PrintStream(os);
//发送消息
//因为服务端只能接收一行消息,会导致服务器端挂掉,Connection reset
//ps.print("我是TCP客户端,我已经与你对接,并发出邀请:约吗?");
ps.println("我是TCP客户端,我已经与你对接,并发出邀请:约吗?");
ps.flush();
//不要关闭资源,会导致有些信息发送丢失,除非用户点离线才关闭
//socket.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
![在这里插入图片描述](https://img-blog.csdnimg.cn/37f4e236f88e4030b19824a198d40671.png)
![在这里插入图片描述](https://img-blog.csdnimg.cn/adde35980d43415ca0d0b326593bf409.png)
![在这里插入图片描述](https://img-blog.csdnimg.cn/38a32f2e653e423288c3c655b0c06d08.png)
package com.heima.test.TCP1;
//Socket网络编程的服务端,实现接受消息
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
public class SocketServer {
public static void main(String[] args) {
try {
System.out.println("==============服务端启动成功==============");
//注册端口
ServerSocket serverSocket = new ServerSocket(7777);
//必须调用accept方法:等待接收客户端的Socket连接请求,建立Socket通信管道
//进入等待状态
Socket socket = serverSocket.accept();
//从socket通信管道得到一个字节输入流
InputStream is = socket.getInputStream();
//把字节输入流包装成缓冲字符输入流进行消息的接收
//BufferedReader br = new BufferedReader(new InputStreamReader(is,"UTF-8"));
BufferedReader br = new BufferedReader(new InputStreamReader(is));
//按照行读取消息
String msg;
//while ((msg = br.readLine()) != null) {
//while接收多行消息,服务器还是会死掉
if ((msg = br.readLine()) != null) {
System.out.println(socket.getRemoteSocketAddress() + "远程地址说了 : " + msg);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
![在这里插入图片描述](https://img-blog.csdnimg.cn/364447665ee849a68e366b40b0e3a11b.png)
多发多收消息
![在这里插入图片描述](https://img-blog.csdnimg.cn/f29698397b764e81a6c2eecab926f7c0.png)
package com.heima.test.TCP1;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.Socket;
import java.util.Scanner;
//Socket网络编程的客户端,实现多发多收
public class MultiSocketClient {
public static void main(String[] args) {
try {
System.out.println("==============客户端启动成功==============");
//创建Socket通信管道请求服务端的连接
//服务端的IP地址,服务端的端口
Socket socket = new Socket("127.0.0.1", 7777);
//从socket通信管道中得到一个字节输出流,负责发送数据
OutputStream os = socket.getOutputStream();
//把低级的字节流包装成打印流
PrintStream ps = new PrintStream(os);
Scanner sc = new Scanner(System.in);
while (true) {
System.out.println("请说 : ");
String msg = sc.nextLine();
//发送消息
ps.println(msg);
ps.flush();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
package com.heima.test.TCP1;
//Socket网络编程的服务端,实现接受消息
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
public class MultiSocketServer {
public static void main(String[] args) {
try {
System.out.println("==============服务端启动成功==============");
//注册端口
ServerSocket serverSocket = new ServerSocket(7777);
//必须调用accept方法:等待接收客户端的Socket连接请求,建立Socket通信管道
//进入等待状态
Socket socket = serverSocket.accept();
//从socket通信管道得到一个字节输入流
InputStream is = socket.getInputStream();
//把字节输入流包装成缓冲字符输入流进行消息的接收
//BufferedReader br = new BufferedReader(new InputStreamReader(is,"UTF-8"));
BufferedReader br = new BufferedReader(new InputStreamReader(is));
//按照行读取消息
String msg;
while ((msg = br.readLine()) != null) {
System.out.println(socket.getRemoteSocketAddress() + "远程地址说了 : " + msg);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
![在这里插入图片描述](https://img-blog.csdnimg.cn/f532b2ef92914306ae4a9b32d4e1c4f3.png)
![在这里插入图片描述](https://img-blog.csdnimg.cn/d769e154a50148e8a8a72e99d6c96b7b.png)
![在这里插入图片描述](https://img-blog.csdnimg.cn/1eb092d773534db1847d68fdca735408.png)
同时接受多个客户端消息(重点)
![在这里插入图片描述](https://img-blog.csdnimg.cn/5fed6474944b4e1b83bcf7cf84f75ec3.png)
![在这里插入图片描述](https://img-blog.csdnimg.cn/be8e04e73f494397839d8beaaf6e9795.png)
![在这里插入图片描述](https://img-blog.csdnimg.cn/b41d10abc9614f569a518cd36eef0667.png)
package com.heima.test.TCP1;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.Socket;
import java.util.Scanner;
//Socket网络编程的客户端,实现服务端可以同时处理多个客户端消息
public class ThreadSocketClient {
public static void main(String[] args) {
try {
System.out.println("==============客户端启动成功==============");
//创建Socket通信管道请求服务端的连接
//服务端的IP地址,服务端的端口
Socket socket = new Socket("127.0.0.1", 7777);
//从socket通信管道中得到一个字节输出流,负责发送数据
OutputStream os = socket.getOutputStream();
//把低级的字节流包装成打印流
PrintStream ps = new PrintStream(os);
Scanner sc = new Scanner(System.in);
while (true) {
System.out.println("请说 : ");
String msg = sc.nextLine();
//发送消息
ps.println(msg);
ps.flush();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
package com.heima.test.TCP1;
//Socket网络编程的服务端,实现服务端可以同时处理多个客户端消息
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
public class ThreadSocketServer {
public static void main(String[] args) {
try {
System.out.println("==============服务端启动成功==============");
//注册端口
ServerSocket serverSocket = new ServerSocket(7777);
//定义一个死循环由主线程负责不断地接收客户端的Socket管道连接
while (true) {
//每接收到一个客户端的Socket管道,交给一个独立的子线程负责读取消息
Socket socket = serverSocket.accept();
System.out.println(socket.getRemoteSocketAddress()+" 上线了!");
//创建独立线程处理socket
new ServerReaderThread(socket).start();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
package com.heima.test.TCP1;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.Socket;
public class ServerReaderThread extends Thread {
private Socket socket;
public ServerReaderThread(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
try {
//从socket通信管道得到一个字节输入流
InputStream is = socket.getInputStream();
//把字节输入流包装成缓冲字符输入流进行消息的接收
BufferedReader br = new BufferedReader(new InputStreamReader(is));
//按照行读取消息
String msg;
while ((msg = br.readLine()) != null) {
System.out.println(socket.getRemoteSocketAddress() + " 远程地址说了 : " + msg);
}
} catch (Exception e) {
// e.printStackTrace();
System.out.println(socket.getRemoteSocketAddress() + " 离开了!!!");
}
}
}
![在这里插入图片描述](https://img-blog.csdnimg.cn/786d897b6a3c475e914eb8cab64eddf6.png)
使用线程池优化
![在这里插入图片描述](https://img-blog.csdnimg.cn/41f61c4b8df34aa8b6c78191664218e4.png)
![在这里插入图片描述](https://img-blog.csdnimg.cn/5104b02d57e34f04959629aac53504da.png)
package com.heima.test.TCP1;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.Socket;
import java.util.Scanner;
//Socket网络编程的客户端,实现服务端可以同时处理多个客户端消息
//使用线程池优化代码
//客户端不用动
public class ThreadSocketClient {
public static void main(String[] args) {
try {
System.out.println("==============客户端启动成功==============");
//创建Socket通信管道请求服务端的连接
//服务端的IP地址,服务端的端口
Socket socket = new Socket("127.0.0.1", 6666);
//从socket通信管道中得到一个字节输出流,负责发送数据
OutputStream os = socket.getOutputStream();
//把低级的字节流包装成打印流
PrintStream ps = new PrintStream(os);
Scanner sc = new Scanner(System.in);
while (true) {
System.out.println("请说 : ");
String msg = sc.nextLine();
//发送消息
ps.println(msg);
ps.flush();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
package com.heima.test.TCP1;
//Socket网络编程的服务端,实现服务端可以同时处理多个客户端消息
//使用线程池优化代码
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.*;
public class ThreadSocketServer {
//使用静态变量记住一个线程池对象,用于处理任务
//上限是5线程或7任务
private static ExecutorService pool = new ThreadPoolExecutor(3, 5, 6,
TimeUnit.SECONDS, new ArrayBlockingQueue<>(2),
Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());
public static void main(String[] args) {
try {
System.out.println("==============服务端启动成功==============");
//注册端口
ServerSocket serverSocket = new ServerSocket(6666);
//定义一个死循环由主线程负责不断地接收客户端的Socket管道连接
while (true) {
//每接收到一个客户端的Socket管道,交给一个独立的子线程负责读取消息
Socket socket = serverSocket.accept();
System.out.println(socket.getRemoteSocketAddress() + " 上线了!");
//创建任务对象交给线程池处理
//任务对象负责读取消息
Runnable target = new ServerReaderRunnable(socket);
pool.execute(target);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
package com.heima.test.TCP1;
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(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
try {
//从socket通信管道得到一个字节输入流
InputStream is = socket.getInputStream();
//把字节输入流包装成缓冲字符输入流进行消息的接收
BufferedReader br = new BufferedReader(new InputStreamReader(is));
//按照行读取消息
String msg;
while ((msg = br.readLine()) != null) {
System.out.println(socket.getRemoteSocketAddress() + " 远程地址说了 : " + msg);
}
} catch (Exception e) {
System.out.println(socket.getRemoteSocketAddress() + " 离开了!!!");
}
}
}
![在这里插入图片描述](https://img-blog.csdnimg.cn/91d333e21f4349698f73fd2a1ee2ca08.png)
实战案例 - 即时通信
![在这里插入图片描述](https://img-blog.csdnimg.cn/2c21e3694b3f48fab5d8f3808cf885dc.png)
![在这里插入图片描述](https://img-blog.csdnimg.cn/665517f369444348b61fce272e56451b.png)
![在这里插入图片描述](https://img-blog.csdnimg.cn/40a32d9864604a1cae3d11b3bdca5f6d.png)
package com.heima.test.TCP2;
import java.io.*;
import java.net.Socket;
import java.util.Scanner;
//客户端既能收消息,也可以发送消息
public class ClientMSG {
public static void main(String[] args) {
try {
System.out.println("==============客户端启动成功==============");
//创建Socket通信管道请求服务端的连接
//服务端的IP地址,服务端的端口
Socket socket = new Socket("127.0.0.1", 6666);
//创建一个独立的线程专门负责这个客户端的读消息(服务端随时可能转发消息过来!)
new ClientReaderThread(socket).start();
//从socket通信管道中得到一个字节输出流,负责发送数据
OutputStream os = socket.getOutputStream();
//把低级的字节流包装成打印流
PrintStream ps = new PrintStream(os);
Scanner sc = new Scanner(System.in);
while (true) {
System.out.println("请说 : ");
String msg = sc.nextLine();
//发送消息
ps.println(msg);
ps.flush();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
//客户端读线程
class ClientReaderThread extends Thread {
private Socket socket;
public ClientReaderThread(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
try {
//从socket通信管道得到一个字节输入流
InputStream is = socket.getInputStream();
//把字节输入流包装成缓冲字符输入流进行消息的接收
BufferedReader br = new BufferedReader(new InputStreamReader(is));
//按照行读取消息
String msg;
while ((msg = br.readLine()) != null) {
System.out.println(" 收到了消息 : " + msg);
}
} catch (Exception e) {
System.out.println("服务端把你踢出去了。。。");
}
}
}
package com.heima.test.TCP2;
import com.heima.test.TCP1.ServerReaderRunnable;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
public class ServerMSG {
//定义一个静态的List集合存储当前全部在线socket管道
public static List<Socket> allOnlineSocket = new ArrayList<>();
public static void main(String[] args) {
try {
System.out.println("==============服务端启动成功==============");
//注册端口
ServerSocket serverSocket = new ServerSocket(6666);
//循环接收客户端socket管道请求
while (true) {
//开始接收客户端的socket管道连接请求
//注意:在这里等待客户端的socket管道连接
Socket socket = serverSocket.accept();
System.out.println(socket.getRemoteSocketAddress() + " 上线了!");
allOnlineSocket.add(socket);//上线完成
//创建一个独立的线程来单独处理这个socket管道
new ServerReaderThread(socket).start();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
class ServerReaderThread extends Thread {
private Socket socket;
public ServerReaderThread(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
try {
//从socket通信管道得到一个字节输入流
InputStream is = socket.getInputStream();
//把字节输入流包装成缓冲字符输入流进行消息的接收
BufferedReader br = new BufferedReader(new InputStreamReader(is));
//按照行读取消息
String msg;
while ((msg = br.readLine()) != null) {
System.out.println(socket.getRemoteSocketAddress() + " 发来了 : " + msg);
//把这个消息进行端口转发给全部客户端socket管道
sendMsgToAll(msg);
}
} catch (Exception e) {
System.out.println(socket.getRemoteSocketAddress() + " 离开了!!!");
ServerMSG.allOnlineSocket.remove(socket);
}
}
private void sendMsgToAll(String msg) throws Exception {
for (Socket socket : ServerMSG.allOnlineSocket) {
PrintStream ps = new PrintStream(socket.getOutputStream());
ps.println(msg);
ps.flush();
}
}
}
实战案例 - 模拟BS系统
![在这里插入图片描述](https://img-blog.csdnimg.cn/bcba8ede111140a19731aa84f0f9c086.png)
![在这里插入图片描述](https://img-blog.csdnimg.cn/b18214f52ce14e8390f65fc0958ea478.png)
package com.heima.test.TCP3;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class BSserver {
public static void main(String[] args) {
try {
System.out.println("==============服务端启动成功==============");
//注册端口
ServerSocket ss = new ServerSocket(8080);
//创建一个循环接收多个客户端请求
while (true) {
Socket socket = ss.accept();
//交给一个独立线程处理
new ServerReaderThread(socket).start();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
class ServerReaderThread extends Thread {
private Socket socket;
public ServerReaderThread(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
try {
//浏览器已经与本线程建立了socket管道
//响应消息给浏览器显示
PrintStream 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("<span style='color:red;font-size:90px'>我是响应信息</span>");
ps.close();
} catch (Exception e) {
System.out.println(socket.getRemoteSocketAddress() + " 离开了!!!");
}
}
}
![在这里插入图片描述](https://img-blog.csdnimg.cn/c7cbcdc2266d46c4878805db7f76b151.png)
package com.heima.test.TCP3;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.*;
public class BSserver {
//使用静态变量记住一个线程池对象,用于处理任务
//上限是5线程或7任务
private static ExecutorService pool = new ThreadPoolExecutor(3, 5, 6,
TimeUnit.SECONDS, new ArrayBlockingQueue<>(2),
Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());
public static void main(String[] args) {
try {
System.out.println("==============服务端启动成功==============");
//注册端口
ServerSocket ss = new ServerSocket(8080);
//创建一个循环接收多个客户端请求
while (true) {
Socket socket = ss.accept();
//交给一个独立线程处理
pool.execute(new ServerReaderRunnable(socket));
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
class ServerReaderRunnable implements Runnable {
private Socket socket;
public ServerReaderRunnable(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
try {
//浏览器已经与本线程建立了socket管道
//响应消息给浏览器显示
PrintStream 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("<span style='color:red;font-size:90px'>我是响应信息2</span>");
ps.close();
} catch (Exception e) {
System.out.println(socket.getRemoteSocketAddress() + " 离开了!!!");
}
}
}
![在这里插入图片描述](https://img-blog.csdnimg.cn/e588e3f721d9493e822d8329f881445c.png)
![在这里插入图片描述](https://img-blog.csdnimg.cn/72e7e44f938447c0a4b9b3d405f240b1.png)