设备在网络中的地址,唯一的标识
IP(Internet Protocol):全称“互联网协议地址”,是分配给上网设备的唯一标志
常见的IP分类
IP地址形式
IP常用命令
特殊IP地址
public class InetAddressDemoOne {
public static void main(String[] args) throws Exception {
//1.获取本机地址对象
InetAddress ip1 = InetAddress.getLocalHost();
System.out.println(ip1.getHostName());
System.out.println(ip1.getHostAddress());
System.out.println("-----------------");
//2.获取域名ip对象
InetAddress ip2 = InetAddress.getByName("www.baidu.com");
System.out.println(ip2.getHostName());
System.out.println(ip2.getHostAddress());
System.out.println("-----------------");
//3.获取公网ip对象
InetAddress ip3 = InetAddress.getByName("39.156.66.14");
System.out.println(ip3.getHostName());
System.out.println(ip3.getHostAddress());
//4.判断是否能通:ping 5s 之前测试是否可通
System.out.println(ip3.isReachable(5000));
}
}
注意:我们自己开发的程序选择注册端口,且一个设备中不能出现两个程序的端口号一样,否则出错
UDP协议
UDP是一种无连接、不可靠传输的协议
将数据源IP、目的地IP和端口封装称数据包,不需要建立连接
每个数据包的大小限制在64KB内
发送不管对方是否准备好,接收方收到不确认,故是不可靠的
可以广播发送,发送数据结束时无需释放资源,开销小,速度快
UDP协议通信场景
释放资源
Client(客户端)
public class Client01 {
public static void main(String[] args) throws Exception {
System.out.println("===========客户端============");
//1.创建发送端对象,发送端口自带默认的端口号(人)
DatagramSocket socket = new DatagramSocket(0220);
//2.创建一个数据包对象封装数据(韭菜盘子)
/*
* byte buf[], int length,InetAddress address, int port
* 参数一:字节数组
* 参数二:长度
* 参数三:服务端的主机IP地址
* 参数四:端口号
* */
byte[] buffer = "吃韭菜,吃韭菜".getBytes();
DatagramPacket packet = new DatagramPacket(buffer,buffer.length, InetAddress.getLocalHost(),8888);
//3.发数据出去
socket.send(packet);
//关闭资源
socket.close();
}
}
public class Server01 {
public static void main(String[] args) throws Exception {
System.out.println("===========服务端==========");
//1.创建接收端,注册端口(人)
DatagramSocket socket = new DatagramSocket(8888);
//2.创建一个数据包对象接收数据(韭菜盘子)
byte[] buffer = new byte[1024 * 64];// 1024为1K 而一次数据最多可有64K
DatagramPacket packet = new DatagramPacket(buffer,buffer.length);
//3.等待接收数据
socket.receive(packet);
//4.取出数据
//读多少,倒多少
int len = packet.getLength();
System.out.println("收到数据:"+new String(buffer,0,len));
//获取发送端的ip和端口
String ip = packet.getSocketAddress().toString();
int port = packet.getPort();
System.out.println("ip:"+ip+",端口:"+port);
socket.close();
}
}
分析
Client
public class Client01 {
public static void main(String[] args) throws Exception {
System.out.println("===========客户端============");
//1.创建发送端对象,发送端口自带默认的端口号(人)
DatagramSocket socket = new DatagramSocket(7777);
//2.创建一个数据包对象封装数据(韭菜盘子)
Scanner input = new Scanner(System.in);
String input_str;
do {
System.out.println("发送您要输入的信息:");
input_str = input.nextLine();
byte[] buffer = input_str.getBytes();
DatagramPacket packet = new DatagramPacket(buffer,buffer.length, InetAddress.getLocalHost(),8888);
//3.发数据出去
socket.send(packet);
}while(!input_str.equals("exit"));
//关闭资源
socket.close();
}
}
public class Server01 {
public static void main(String[] args) throws Exception {
System.out.println("===========服务端==========");
//1.创建接收端,注册端口(人)
DatagramSocket socket = new DatagramSocket(8888);
//2.创建一个数据包对象接收数据(韭菜盘子)
byte[] buffer = new byte[1024 * 64];// 1024为1K 而一次数据最多可有64K
DatagramPacket packet = new DatagramPacket(buffer,buffer.length);
String receive_str;
do {
//3.等待接收数据
socket.receive(packet);
//4.取出数据
//读多少,倒多少
int len = packet.getLength();
receive_str = new String(buffer, 0, len);
System.out.println("收到了来自ip:"+packet.getSocketAddress().toString()+"端口:"+ packet.getPort()+"的数据\n——"+receive_str);
//获取发送端的ip和端口
}while(!receive_str.equals("exit"));
socket.close();
}
}
public class Client01 {
public static void main(String[] args) throws Exception {
System.out.println("===========客户端============");
//1.创建发送端对象,发送端口自带默认的端口号(人)
DatagramSocket socket = new DatagramSocket(7777);
//2.创建一个数据包对象封装数据(韭菜盘子)
Scanner input = new Scanner(System.in);
String input_str;
do {
System.out.println("发送您要输入的信息:");
input_str = input.nextLine();
byte[] buffer = input_str.getBytes();
DatagramPacket packet = new DatagramPacket(buffer,buffer.length, InetAddress.getByName("255.255.255.255"),8888);
//3.发数据出去
socket.send(packet);
}while(!input_str.equals("exit"));
//关闭资源
socket.close();
}
}
public class Server01 {
public static void main(String[] args) throws Exception {
System.out.println("===========服务端==========");
//1.创建接收端,注册端口(人)
DatagramSocket socket = new DatagramSocket(8888);
//2.创建一个数据包对象接收数据(韭菜盘子)
byte[] buffer = new byte[1024 * 64];// 1024为1K 而一次数据最多可有64K
DatagramPacket packet = new DatagramPacket(buffer,buffer.length);
String receive_str;
do {
//3.等待接收数据
socket.receive(packet);
//4.取出数据
//读多少,倒多少
int len = packet.getLength();
receive_str = new String(buffer, 0, len);
System.out.println("收到了来自ip:"+packet.getSocketAddress().toString()+"端口:"+ packet.getPort()+"的数据\n——"+receive_str);
//获取发送端的ip和端口
}while(!receive_str.equals("exit"));
socket.close();
}
}
public class Client01 {
public static void main(String[] args) throws Exception {
System.out.println("===========客户端============");
//1.创建发送端对象,发送端口自带默认的端口号(人)
DatagramSocket socket = new DatagramSocket(7777);
//2.创建一个数据包对象封装数据(韭菜盘子)
/*
* byte buf[], int length,InetAddress address, int port
* 参数一:字节数组
* 参数二:长度
* 参数三:服务端的主机IP地址
* 参数四:端口号
* */
Scanner input = new Scanner(System.in);
String input_str;
do {
System.out.println("发送您要输入的信息:");
input_str = input.nextLine();
byte[] buffer = input_str.getBytes();
DatagramPacket packet = new DatagramPacket(buffer,buffer.length, InetAddress.getByName("224.0.1.1"),8888);
//3.发数据出去
socket.send(packet);
}while(!input_str.equals("exit"));
//关闭资源
socket.close();
}
}
public class Server01 {
public static void main(String[] args) throws Exception {
System.out.println("===========服务端==========");
//1.创建接收端,注册端口(人)
MulticastSocket socket = new MulticastSocket(8888);
//吧当前接收端加入到一个组播组中去,绑定对应的组播消息的组播IP
socket.joinGroup(InetAddress.getByName("224.0.1.1"));
//2.创建一个数据包对象接收数据(韭菜盘子)
byte[] buffer = new byte[1024 * 64];// 1024为1K 而一次数据最多可有64K
DatagramPacket packet = new DatagramPacket(buffer,buffer.length);
String receive_str;
do {
//3.等待接收数据
socket.receive(packet);
//4.取出数据
//读多少,倒多少
int len = packet.getLength();
receive_str = new String(buffer, 0, len);
System.out.println("收到了来自ip:"+packet.getSocketAddress().toString()+"端口:"+ packet.getPort()+"的数据\n——"+receive_str);
//获取发送端的ip和端口
}while(!receive_str.equals("exit"));
socket.close();
}
}
【TCP三次握手确立连接】
【TCP四次挥手断开连接】
注意:在Java中只要使用 java.net.Socket类实现通信。底层即是使用了TCP协议
public class Client01 {
public static void main(String[] args) {
try {
System.out.println("==========客户端===========");
//1.创建Scoket通信管道请求有服务端的连接
//参数一:IP地址 参数二:端口号
Socket socket = new Socket("127.0.0.1",8888);
//2.从socket管道中得到字节输出流,负责发送数据
OutputStream os = socket.getOutputStream();
//3.吧低级的字节流包装为打印流
PrintStream ps = new PrintStream(os);
//4.发送消息
ps.println("我是TCP的客户端,我已经与你对接,并发出信息:你好");
ps.flush();
}catch (Exception e){
e.printStackTrace();
}
}
}
public class Server01 {
public static void main(String[] args) throws Exception{
System.out.println("==========服务端===========");
//1.注册端口
ServerSocket serverSocket = new ServerSocket(8888);
//2.调用accept方法,等待接收客户端的Socket连接请求,建立Socket通信管道
Socket socket = serverSocket.accept();
//3.从socket通信管道中得到字节输入流
InputStream is = socket.getInputStream();
//4.包装为字符缓冲输入流
BufferedReader br = new BufferedReader(new InputStreamReader(is));
//5.读取信息
String line;
if((line = br.readLine()) != null){
System.out.println(socket.getRemoteSocketAddress()+"发送了信息:\n"+line);
}
}
}
使用TCP通信实现
Client
public class Client01 {
public static void main(String[] args) {
try {
System.out.println("==========客户端===========");
//1.创建Scoket通信管道请求有服务端的连接
//参数一:IP地址 参数二:端口号
Socket socket = new Socket("127.0.0.1",8888);
//2.从socket管道中得到字节输出流,负责发送数据
OutputStream os = socket.getOutputStream();
//3.吧低级的字节流包装为打印流
PrintStream ps = new PrintStream(os);
//4.发送消息
Scanner input = new Scanner(System.in);
String input_str;
do {
System.out.println("请输入您要发送的信息:\n");
input_str = input.nextLine();
ps.println(input_str);
}while(!input_str.equals("exit"));
ps.flush();
}catch (Exception e){
e.printStackTrace();
}
}
}
public class Server01 {
public static void main(String[] args) throws Exception{
System.out.println("==========服务端===========");
//1.注册端口
ServerSocket serverSocket = new ServerSocket(8888);
//2.调用accept方法,等待接收客户端的Socket连接请求,建立Socket通信管道
Socket socket = serverSocket.accept();
//3.从socket通信管道中得到字节输入流
InputStream is = socket.getInputStream();
//4.包装为字符缓冲输入流
BufferedReader br = new BufferedReader(new InputStreamReader(is));
//5.读取信息
String line;
while((line = br.readLine()) != null){
System.out.println(socket.getRemoteSocketAddress()+"发送了信息:\n"+line);
}
}
}
问题:本案例实现了多发多收,那么是否可以同时接收多个客户端的消息
【不可以,因为服务端只有一个线程,只能与一个客户端进行通信】——线程
public class ServerReaderThread extends Thread{
private Socket socket;
public ServerReaderThread(Socket socket){
this.socket = socket;
}
@Override
public void run() {
try {
//3.从socket通信管道中得到字节输入流
InputStream is = socket.getInputStream();
//4.包装为字符缓冲输入流
BufferedReader br = new BufferedReader(new InputStreamReader(is));
//5.读取信息
String line;
while((line = br.readLine()) != null){
System.out.println(socket.getRemoteSocketAddress()+"发送了信息:\n"+line);
}
} catch (Exception e) {
System.out.println(socket.getRemoteSocketAddress()+"下线了");
}
}
}
public class Server01 {
public static void main(String[] args) throws Exception{
System.out.println("==========服务端===========");
//1.注册端口
ServerSocket serverSocket = new ServerSocket(8888);
//定义死循环,由主线程负责一直不断的接收客户端Socket管道连接
while(true){
//2.每接收到一个客户端的socket管道,吧它交给线程
Socket socket = serverSocket.accept();
System.out.println(socket.getRemoteSocketAddress()+"上线了!");
new ServerReaderThread(socket).start();
}
}
}
存在问题
Client 不变
public class ServerReaderRunnable implements Runnable{
private Socket socket;
public ServerReaderRunnable(Socket socket){
this.socket = socket;
}
@Override
public void run() {
try {
//3.从socket通信管道中得到字节输入流
InputStream is = socket.getInputStream();
//4.包装为字符缓冲输入流
BufferedReader br = new BufferedReader(new InputStreamReader(is));
//5.读取信息
String line;
while((line = br.readLine()) != null){
System.out.println(socket.getRemoteSocketAddress()+"发送了信息:\n"+line);
}
} catch (Exception e) {
System.out.println(socket.getRemoteSocketAddress()+"下线了");
}
}
}
public class Server01 {
public static ExecutorService pools = new ThreadPoolExecutor(3,5,6, TimeUnit.SECONDS,new ArrayBlockingQueue<>(2),
Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy());
public static void main(String[] args) throws Exception{
System.out.println("==========服务端===========");
//1.注册端口
ServerSocket serverSocket = new ServerSocket(8888);
//定义死循环,由主线程负责一直不断的接收客户端Socket管道连接
while(true){
//2.每接收到一个客户端的socket管道,吧它交给线程
Socket socket = serverSocket.accept();
System.out.println(socket.getRemoteSocketAddress()+"上线了!");
pools.execute(new ServerReaderRunnable(socket));
}
}
}
public class Client {
public static void main(String[] args) throws Exception{
Socket socket = new Socket("127.0.0.1",8888);
Scanner input = new Scanner(System.in);
PrintStream ps = new PrintStream(socket.getOutputStream());
new ClientReaderThread(socket).start();
while(true){
System.out.println("请输入您要发送的消息:");
String mes = input.nextLine();
ps.println(mes);
ps.flush();
}
}
}
class ClientReaderThread extends Thread{
private Socket socket;
public ClientReaderThread(Socket socket){
this.socket = socket;
}
@Override
public void run() {
try {
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String line;
while((line = br.readLine())!=null){
System.out.println(socket.getRemoteSocketAddress()+"发送了消息:\n"+line);
}
} catch (Exception e) {
System.out.println("你被踢出去了!");
}
}
}
public class Server {
public static ArrayList<Socket> AllOnlineSockets = new ArrayList<>();
public static void main(String[] args) throws Exception{
ServerSocket serverSocket = new ServerSocket(8888);
while(true){
Socket socket = serverSocket.accept();
System.out.println(socket.getRemoteSocketAddress()+"上线了!");
new ServerReaderThread(socket).start();
AllOnlineSockets.add(socket);
}
}
}
class ServerReaderThread extends Thread{
private Socket socket;
public ServerReaderThread(Socket socket){
this.socket = socket;
}
@Override
public void run() {
try {
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String line;
while((line = br.readLine())!=null){
System.out.println(socket.getRemoteSocketAddress()+"发送了消息:\n"+line);
sendAllOnlineSockets(Server.AllOnlineSockets,line);
}
} catch (Exception e) {
System.out.println(socket.getRemoteSocketAddress()+"下线了!");
Server.AllOnlineSockets.remove(socket);
}
}
private void sendAllOnlineSockets(ArrayList<Socket> allOnlineSockets,String mes) {
allOnlineSockets.forEach(s -> {
try {
PrintStream ps = new PrintStream(s.getOutputStream());
ps.println(mes);
ps.flush();
} catch (IOException e) {
e.printStackTrace();
}
});
}
}