目录
网络通信基本模式
1.Client-Server(CS)编辑
2.Browser-Server(BS)编辑
一.网络通信的三要素
1.IP地址: 设备在网络中的地址, 是唯一的标识
2.端口: 应用程序在设备中的唯一的标识
3.协议: 数据在网络中传输的规则, 常见的协议有UDP协议和TCP协议
UDP通信
1.DatagramSocket:发送端和接收端对象
2.DatagramPacket:数据包对象(韭菜盘子)
3.多发多收
TCP通信
网络通信基本模式
1.Client-Server(CS)
2.Browser-Server(BS)
一.网络通信的三要素
1.IP地址: 设备在网络中的地址, 是唯一的标识
IP地址形式:
公网地址和私有地址(局域网使用)。
192.168.开头的就是常见的局域网地址,范围即为192.168.0.0--192168.255.255,专门为组织机构内部使用
IP常用命令:
ipconfig: 查看本机IP地址
ping IP地址:检查网络是否连通
特殊IP地址
本机IP: 127.0.0.1或者localhost: 称为回送地址也可称本地回环地址, 只会寻找当前所在本机lnetAddress 的使用
此类表示Internet协议 (IP) 地址
InetAddress的API
名称 说明
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.io.IOException; import java.net.InetAddress; import java.net.UnknownHostException; public class ipDemo1 { public static void main(String[] args) throws IOException { //1.获取本机地址对象 InetAddress ip1 = InetAddress.getLocalHost(); //System.out.println(ip1.getHostName());//主机名 System.out.println(ip1.getHostAddress());//IP地址字符串 //2.获取域名IP InetAddress ip2 = InetAddress.getByName("www.baidu.com"); System.out.println(ip2.getHostName()); System.out.println(ip2.getHostAddress()); //3.获取公网ip对象 InetAddress ip3 = InetAddress.getByName("14.215.177.38"); System.out.println(ip3.getHostName()); System.out.println(ip3.getHostAddress()); //4.判断是否能通 System.out.println(ip2.isReachable(3000));//3000代表3000ms,表示在3000ms内是否能通 } }
结果展示:
2.端口: 应用程序在设备中的唯一的标识
3.协议: 数据在网络中传输的规则, 常见的协议有UDP协议和TCP协议
UDP通信
UDP协议的特点
UDP是一种无连接、不可靠传输的协议
将数据源IP, 目的地IP和端口以及数据封装成数据包, 大小限制在64KB内, 直接发送出去即可1.DatagramSocket:发送端和接收端对象
DatagramSocket类构造方法
构造方法 说明
public DatagramSocket() 创建发送端的Socket对象,系统会随机分配一个端口号
public DatagramSocket(int port) 创建接收端的socket对象并指定端口号
DatagramSocket类成员方法
方法 说明
public void send(DatagramPacket dp) 发送数据包
public void receive(DatagramPacket p) 接收数据包2.DatagramPacket:数据包对象(韭菜盘子)
构造方法
public DatagramPacket(byte[ ] buf, int length, InetAddress address, int port)
创建发送端数据包对象
buf:要发送的内容,字节数组 length: 要发送内容的字节长度
address:接收端的IP地址对象 port:接收端的端口号
public DatagramPacket(byte[ ] buf,int length)创建接收端的数据包对象
buf:用来存储接收的内容 length: 能够接收内容的长度
代码示范: 第一段代码时客户端代码, 第二段是服务端代码
import java.io.IOException; import java.net.*; //客户端 public class ClientDemo1 { public static void main(String[] args) throws IOException { System.out.println("=====客户端启动====="); //1.创建发送端对象 DatagramSocket socket = new DatagramSocket(); //2.创建一个数据包对象封装数据 byte[] by1 = "要发送的数据".getBytes(); DatagramPacket packet = new DatagramPacket(by1, by1.length, InetAddress.getLocalHost(), 6666); //3发送数据出去 socket.send(packet); //关闭 socket.close(); } }
import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.SocketException; //服务端 public class ServerDemo1 { public static void main(String[] args) throws IOException { System.out.println("=====服务端启动====="); //1.创建接收端对象 DatagramSocket socket = new DatagramSocket(6666); //2.创建接收数据包对象 byte[] by2 = new byte[1024*64]; DatagramPacket packet = new DatagramPacket(by2, 0, by2.length); //3.等待接收数据 socket.receive(packet); //4.取出数据 int len = packet.getLength(); String s1 = new String(by2,0,len); System.out.println("收到: "+s1); //关闭 socket.close(); } }
结果展示: 运行代码时,要先运行服务端的代码,再运行客户端的代码
3.多发多收
代码示范:
import java.io.IOException; import java.net.*; import java.util.Scanner; //客户端 public class ClientDemo1 { public static void main(String[] args) throws IOException { System.out.println("=====客户端启动====="); //1.创建发送端对象 DatagramSocket socket = new DatagramSocket(); //2.创建一个数据包对象封装数据 Scanner sc = new Scanner(System.in); while (true) { System.out.println("请输入: "); String str = sc.next(); if("exit".equals(str)){ System.out.println("退出"); socket.close(); break; } byte[] by1 = str.getBytes(); DatagramPacket packet = new DatagramPacket(by1, by1.length, InetAddress.getLocalHost(), 6666); //3发送数据出去 socket.send(packet); } } }
import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.SocketException; //服务端 public class ServerDemo1 { public static void main(String[] args) throws IOException { System.out.println("=====服务端启动====="); //1.创建接收端对象 DatagramSocket socket = new DatagramSocket(6666); //2.创建接收数据包对象 byte[] by2 = new byte[1024*64]; DatagramPacket packet = new DatagramPacket(by2, 0, by2.length); while (true) { //3.等待接收数据 socket.receive(packet); //4.取出数据 int len = packet.getLength(); String s1 = new String(by2,0,len); System.out.println("收到了来自: "+packet.getAddress()+" 对方的端口是"+packet.getPort()+"的信息: "+s1); } } }
结果展示:
TCP通信
原理图:
Socket
构造方法 说明
public Socket(String host ,int port) 创建发送端的Socket对象与服务端连接,参数为服务端程序的ip和端口
Socket类成员方法 说明
OutputStream getOutputStream() 获得字节输出流对象
InputStream getInputStream() 获得字节输入流对象ServerSocket(服务端)
构造方法 说明
public ServerSocket(int port) 注册服务端端口
ServerSocket类成员方法 说明
public Socket accept() 等待接收客户端的Socket通信连接
连接成功返回Socket对象与客户端建立端到端通信代码示范:
import java.io.IOException; import java.io.OutputStream; import java.io.PrintStream; import java.net.Socket; public class ClientDemo1 { public static void main(String[] args) throws IOException { System.out.println("====客户端===="); //1.创建Socket通信管道和请求服务端的连接 Socket socket = new Socket("127.0.0.1",6666); //2.从socket通信段GG中得到一个字符输出流,用来发送数据 OutputStream os = socket.getOutputStream(); //3.把第几字节流包装成打印流 PrintStream ps = new PrintStream(os); //4.发送信息 ps.println("我是发送出来的信息"); ps.flush(); } }
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 ServerDemo1 { public static void main(String[] args) throws IOException { System.out.println("====服务端===="); //1.注册端口 ServerSocket serverSocket = new ServerSocket(6666); //2.必须调用accept方法,的带客户端的连接请求,建立Socket通道 Socket socket = serverSocket.accept(); //3.从socket管道中得到一个字节输入流 InputStream inputStream = socket.getInputStream(); //4.接收信息 BufferedReader br = new BufferedReader(new InputStreamReader(inputStream)); //5.读取信息 String s1 = br.readLine(); if(s1 != null){ System.out.println(socket.getRemoteSocketAddress()+" 发送了: "+s1); } } }
结果展示:
多发多收但只能连接一个客户端
代码示范:
import java.io.IOException; import java.io.OutputStream; import java.io.PrintStream; import java.net.Socket; import java.util.Scanner; public class ClientDemo2 { public static void main(String[] args) throws IOException { System.out.println("====客户端===="); //1.创建Socket通信管道和请求服务端的连接 Socket socket = new Socket("127.0.0.1",6666); //2.从socket通信段GG中得到一个字符输出流,用来发送数据 Scanner sc = new Scanner(System.in); while(true){ System.out.println("请输入: "); String str = sc.next(); OutputStream os = socket.getOutputStream(); //3.把第几字节流包装成打印流 PrintStream ps = new PrintStream(os); //4.发送信息 ps.println(str); ps.flush(); } } }
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 ServerDemo2 { public static void main(String[] args) throws IOException { System.out.println("====服务端===="); //1.注册端口 ServerSocket serverSocket = new ServerSocket(6666); //2.必须调用accept方法,的带客户端的连接请求,建立Socket通道 Socket socket = serverSocket.accept(); //3.从socket管道中得到一个字节输入流 InputStream inputStream = socket.getInputStream(); //4.接收信息 BufferedReader br = new BufferedReader(new InputStreamReader(inputStream)); //5.读取信息 String s1 ; while((s1= br.readLine()) != null){ System.out.println(socket.getRemoteSocketAddress()+" 发送了: "+s1); } } }
结果展示:
多发多收而且能连接多个客户端
代码示范: 第一段是线程类代码, 第二段是客户端代码, 第三段是服务端代码
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.net.Socket; public class ServerSocketThread extends Thread{ private Socket socket; public ServerSocketThread(Socket socket){ this.socket = socket; } @Override public void run() { //3.从socket管道中得到一个字节输入流 try { InputStream inputStream = socket.getInputStream(); //4.接收信息 BufferedReader br = new BufferedReader(new InputStreamReader(inputStream)); //5.读取信息 String s1 ; while((s1= br.readLine()) != null) { System.out.println(socket.getRemoteSocketAddress() + " 发送了: " + s1); } } catch (Exception e) { throw new RuntimeException(e); } } }
import java.io.IOException; import java.io.OutputStream; import java.io.PrintStream; import java.net.Socket; import java.util.Scanner; public class ClientDemo2 { public static void main(String[] args) throws IOException { System.out.println("====客户端===="); //1.创建Socket通信管道和请求服务端的连接 Socket socket = new Socket("127.0.0.1",6666); //2.从socket通信段GG中得到一个字符输出流,用来发送数据 Scanner sc = new Scanner(System.in); while(true){ System.out.println("请输入: "); String str = sc.next(); OutputStream os = socket.getOutputStream(); //3.把第几字节流包装成打印流 PrintStream ps = new PrintStream(os); //4.发送信息 ps.println(str); ps.flush(); } } }
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 ServerDemo2 { public static void main(String[] args) throws IOException { System.out.println("====服务端===="); //1.注册端口 ServerSocket serverSocket = new ServerSocket(6666); //定义一个死循环不断接收客户端的Socket管道 while (true) { //把接收到的客户端Socket管道,交给一个独立的子线程 Socket socket = serverSocket.accept(); //创建独立线程处理socket new ServerSocketThread(socket).start(); } } }
结果展示:
用线程池进行优化
代码示范:
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() { //3.从socket管道中得到一个字节输入流 try { InputStream inputStream = socket.getInputStream(); //4.接收信息 BufferedReader br = new BufferedReader(new InputStreamReader(inputStream)); //5.读取信息 String s1 ; while((s1= br.readLine()) != null) { System.out.println(socket.getRemoteSocketAddress() + " 发送了: " + s1); } } catch (Exception e) { throw new RuntimeException(e); } } }
import java.io.IOException; import java.io.OutputStream; import java.io.PrintStream; import java.net.Socket; import java.util.Scanner; public class ClientDemo3 { public static void main(String[] args) throws IOException { System.out.println("====客户端===="); //1.创建Socket通信管道和请求服务端的连接 Socket socket = new Socket("127.0.0.1",6666); //2.从socket通信段GG中得到一个字符输出流,用来发送数据 Scanner sc = new Scanner(System.in); while(true){ System.out.println("请输入: "); String str = sc.next(); OutputStream os = socket.getOutputStream(); //3.把第几字节流包装成打印流 PrintStream ps = new PrintStream(os); //4.发送信息 ps.println(str); ps.flush(); } } }
import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; import java.util.concurrent.*; public class ServerDemo3 { private static ExecutorService pool = new ThreadPoolExecutor( 3,6,5, TimeUnit.SECONDS,new ArrayBlockingQueue<>(3), Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy()); public static void main(String[] args) throws IOException { System.out.println("====服务端===="); //1.注册端口 ServerSocket serverSocket = new ServerSocket(6666); //定义一个死循环不断接收客户端的Socket管道 while (true) { Socket socket = serverSocket.accept(); ServerReaderRunnable srr = new ServerReaderRunnable(socket); pool.execute(srr); } }
结果展示: