1. 认识计算机网络
-
计算机网络是指将地理位置不同的具有独立功能的多台计算机及其外部设备,通过通信线路连接起来,在网络操作系统,网络管理软件及网络通信协议的管理和协调下,实现资源共享和信息传递的计算机系统。
- 实体:地理位置不同的多台计算机及其外部设备(用IP、端口确定位置)
- 媒介:通过通信线路连接(光纤、电缆、无线电等)
- 管理方法:使用通信协议管理和协调(HTTP、FTP、TCP、IP等)
- 用途:资源共享和信息传递
-
计算机网络的参考模型:
2. IP和端口
2.1 IP
-
IP全称InternetProtocol(互联网协议),用于区分不同的主机,具有定位的作用
-
IP一共分为五类:A类、B类、C类、D类和E类,前三类为主要的地址,D类和E类是特殊地址
- A类:(1.0.0.0-126.0.0.0)(默认子网掩码:255.0.0.0或 0xFF000000)第一个字节为网络号,后三个字节为主机号。该类IP地址的最前面为“0”,所以地址的网络号取值于1~126之间。一般用于大型网络。
- B类:(128.0.0.0-191.255.0.0)(默认子网掩码:255.255.0.0或0xFFFF0000)前两个字节为网络号,后两个字节为主机号。该类IP地址的最前面为“10”,所以地址的网络号取值于128~191之间。一般用于中等规模网络。
- C类:(192.0.0.0-223.255.255.0)(子网掩码:255.255.255.0或 0xFFFFFF00)前三个字节为网络号,最后一个字节为主机号。该类IP地址的最前面为“110”,所以地址的网络号取值于192~223之间。一般用于小型网络。
- D类:是多播地址。该类IP地址的最前面为“1110”,所以地址的网络号取值于224~239之间。一般用于多路广播用户[1] 。
- E类:是保留地址。该类IP地址的最前面为“1111”,所以地址的网络号取值于240~255之间。
- 全0和全1的地址都保留不用
- 127.0.0.1为回送地址,也是本机地址,等效于localhost
- 在主要的三类地中,各保留了一段区域作为私有地址
- A类私有地址:10.0.0.0~10.255.255.255
- B类私有地址:172.16.0.0~172.31.255.255
- C类私有地址:192.168.0.0~192.168.255.255
-
在Java中,用一个IP对象InetAddress表示IP
String address = "127.0.0.1"; // IP地址 InetAddress ip = InetAddress.getByName(address); // getByName()方法获取IP对象
2.2 端口
-
端口(Port)表示计算机上的一个程序的进程,一个端口号对应一个进程
-
端口号的范围:0~65535
- 公有端口:0~1023
- 程序注册端口:1024~49151
- 动态、私有端口:49152~65535
-
端口查询命令
netstat -ano # 查看所有的端口 netstat -ano|findstr "8080" # 查看指定的端口8080 tasklist|findstr "8080" # 查看指定端口8080对应的进程
3. 通信协议
- 通信协议是指通信各方事先约定好的协议,用于计算机网络之间的通信
- 两个重要的通信协议:TCP和UDP
- TCP和UDP的对比:
- TCP:
- 需要连接,稳定
- 有”三次握手“和”四次挥手“
- 分为客户端和服务端
- 传输完成要释放连接,效率低
- UDP:
- 不需要连接,不稳定
- 分为发送端和接收端,没有明确的界限
- 不用建立连接就可以直接传输,效率高
- TCP:
4. 使用TCP
-
使用TCP进行消息发送
-
服务端
import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.ServerSocket; import java.net.Socket; // TCP 服务端 public class TcpServerDemo01_Message { public static void main(String[] args) { int port = 9999; // 服务器的端口号 ServerSocket serverSocket = null; Socket socket = null; InputStream is = null; ByteArrayOutputStream baos = null; try { // 创建一个服务的端口 serverSocket = new ServerSocket(port); // 监听Socket连接 socket = serverSocket.accept(); // 读取客户端的信息 is = socket.getInputStream(); // 管道流 baos = new ByteArrayOutputStream(); byte[] buffer = new byte[1024]; int len; while((len=is.read(buffer))!=-1) { baos.write(buffer,0,len); } System.out.println(baos.toString()); } catch (IOException e) { e.printStackTrace(); } finally { if(baos!=null) { try { baos.close(); } catch (IOException e) { e.printStackTrace(); } } if(is!=null) { try { is.close(); } catch (IOException e) { e.printStackTrace(); } } if(socket!=null) { try { socket.close(); } catch (IOException e) { e.printStackTrace(); } } if(serverSocket!=null) { try { serverSocket.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
-
客户端
import java.io.IOException; import java.io.OutputStream; import java.net.InetAddress; import java.net.Socket; import java.net.UnknownHostException; // TCP 客户端 public class TcpClientDemo01_Message { public static void main(String[] args) { String address = "127.0.0.1"; // 服务器的地址(IP或域名) int port = 9999; // 服务器的端口号 String message = "你好!"; // 发送的消息 InetAddress serverIP; Socket socket = null; OutputStream os = null; try { // 获取服务器地址的对象 serverIP = InetAddress.getByName(address); // 创建一个Socket连接 socket = new Socket(serverIP, port); // 通过IO流发送消息 os = socket.getOutputStream(); os.write(message.getBytes()); // 通知服务端发送完成 socket.shutdownOutput(); } catch (UnknownHostException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { if(os!=null) { try { os.close(); } catch (IOException e) { e.printStackTrace(); } } if(socket!=null) { try { socket.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
-
先运行服务端,再运行客户端
-
-
使用TCP进行文件发送
-
服务端
import java.io.*; import java.net.ServerSocket; import java.net.Socket; // TCP 服务端 public class TcpServerDemo02_File { public static void main(String[] args) throws Exception { int port = 9090; // 服务器端口 String filePath = "receive.jpg"; // 文件路径 // 创建一个服务端口 ServerSocket serverSocket = new ServerSocket(port); // 监听Socket连接 Socket socket = serverSocket.accept(); // 读取客户端传输文件 InputStream is = socket.getInputStream(); // 文件流输出文件 FileOutputStream fos = new FileOutputStream(new File(filePath)); byte[] buffer = new byte[1024]; int len; while((len=is.read(buffer))!=-1) { fos.write(buffer,0,len); } // 通知客户端接收完成 OutputStream os = socket.getOutputStream(); os.write("接收完成".getBytes()); //关闭资源 fos.close(); is.close(); socket.close(); serverSocket.close(); } }
-
客户端
import java.io.*; import java.net.InetAddress; import java.net.Socket; // TCP 客户端 public class TcpClientDemo02_File { public static void main(String[] args) throws Exception { String address = "127.0.0.1"; // 服务器地址(IP或域名) int port = 9090; // 服务器端口 String filePath = "bilibili.jpg"; // 文件路径 // 获取服务器地址的对象 InetAddress serverIP = InetAddress.getByName(address); // 创建一个Socket连接 Socket socket = new Socket(serverIP, port); // 通过IO流发送文件 OutputStream os = socket.getOutputStream(); // 文件流输入文件 FileInputStream fis = new FileInputStream(new File(filePath)); byte[] buffer = new byte[1024]; int len; while((len=fis.read(buffer))!=-1) { os.write(buffer,0,len); } // 通知服务端发送完成 socket.shutdownOutput(); // 获取服务端接收完成消息 InputStream is = socket.getInputStream(); // 管道流 ByteArrayOutputStream baos = new ByteArrayOutputStream(); byte[] buffer2 = new byte[1024]; int len2; while((len2=is.read(buffer2))!=-1) { baos.write(buffer2,0,len2); } System.out.println(baos.toString()); // 关闭资源 baos.close(); is.close(); fis.close(); os.close(); socket.close(); } }
-
先运行服务端,再运行客户端
-
5. 使用UDP
-
使用UDP进行消息发送
-
接收方
import java.net.DatagramPacket; import java.net.DatagramSocket; // UDP 接收方 public class UdpReceiverDemo01_Message { public static void main(String[] args) throws Exception { int port = 9090; // 接收方的端口 // 创建一个接收端口 DatagramSocket socket = new DatagramSocket(port); // 准备一个接收空数据包 byte[] data = new byte[1024]; DatagramPacket packet = new DatagramPacket(data, 0, data.length); // 接收数据包 socket.receive(packet); System.out.println("发送方IP地址:"+packet.getAddress().getHostAddress()); String message = new String(packet.getData(),0,packet.getLength()); System.out.println("信息:"+message); // 关闭Socket socket.close(); } }
-
发送方
import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; // UDP 发送方 public class UdpSenderDemo01_Message { public static void main(String[] args) throws Exception { String address = "127.0.0.1"; // 接收方的地址(IP或域名) int port = 9090; // 接收方的端口 String message = "你好!"; // 发送的信息 // 创建一个Socket DatagramSocket socket = new DatagramSocket(); // 创建一个数据包 byte[] data = message.getBytes(); InetAddress receiverIP = InetAddress.getByName(address); DatagramPacket packet = new DatagramPacket(data, 0, data.length, receiverIP, port); // 发送数据包 socket.send(packet); // 关闭Socket socket.close(); } }
-
先运行接收方,再运行发送方
-
-
使用UDP和多线程实现聊天
-
接收类
import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.SocketException; // UDP 接收类 public class Receiver implements Runnable { private String receiverName; // 接收方的名字 private int port; // 接收方的端口 public Receiver(String receiverName, int port) { this.receiverName = receiverName; this.port = port; } @Override public void run() { DatagramSocket socket = null; try { // 创建一个接收端口 socket = new DatagramSocket(this.port); while (true) { // 准备一个接收空数据包 byte[] data = new byte[1024]; DatagramPacket packet = new DatagramPacket(data, 0, data.length); // 接收数据包 socket.receive(packet); String message = new String(packet.getData(), 0, packet.getLength()); System.out.println(message); // 结束 if(message.indexOf("bye")!=-1) { break; } } } catch (SocketException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { socket.close(); } } }
-
发送类
import java.io.*; import java.net.*; // UDP 发送类 public class Sender implements Runnable { private String senderName; // 发送方的名字 private String receiverIP; // 接收方的IP private int receiverPort; // 接收方的端口 public Sender(String senderName, String receiverIP, int receiverPort) { this.senderName = senderName; this.receiverIP = receiverIP; this.receiverPort = receiverPort; } @Override public void run() { DatagramSocket socket = null; InputStreamReader is = null; BufferedReader reader = null; try { // 创建一个Socket socket = new DatagramSocket(); is = new InputStreamReader(System.in); reader = new BufferedReader(is); while (true) { // 创建一个数据包 String data = reader.readLine(); byte[] dataBytes = (this.senderName+":"+data).getBytes(); InetAddress receiverIP = InetAddress.getByName(this.receiverIP); DatagramPacket packet = new DatagramPacket(dataBytes, 0, dataBytes.length, receiverIP, this.receiverPort); // 发送数据包 socket.send(packet); // 结束 if(data.indexOf("bye")!=-1) { break; } } } catch (SocketException | UnknownHostException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { if(reader!=null) { try { reader.close(); } catch (IOException e) { e.printStackTrace(); } } if(is!=null) { try { is.close(); } catch (IOException e) { e.printStackTrace(); } } if(socket!=null) { socket.close(); } } } }
-
客服
// 客服 public class Service { public static void main(String[] args) { new Thread(new Sender("客服","127.0.0.1",9091)).start(); new Thread(new Receiver("客服",9090)).start(); } }
-
顾客
// 顾客 public class Customer { public static void main(String[] args) { new Thread(new Sender("顾客","127.0.0.1",9090)).start(); new Thread(new Receiver("顾客",9091)).start(); } }
-
同时运行客服和顾客
-
6. URL
-
URL叫同一资源定位符,它用于定位网络上的某一个资源
-
URL由多个部分组成,其结构为:协议://IP地址(或域名):端口号/项目名/文件资源?get参数
import java.net.MalformedURLException; import java.net.URL; public class URLDemo { public static void main(String[] args) throws MalformedURLException { String strURL = "http://localhost:8080/Demo/index.html?name=admin&password=123"; // url地址 URL url = new URL(strURL); // 创建url System.out.println(url.getProtocol()); // 协议 System.out.println(url.getHost()); // IP System.out.println(url.getPort()); // 端口 System.out.println(url.getPath()); // 路径 System.out.println(url.getFile()); // 全路径 System.out.println(url.getQuery()); // 参数 System.out.println("结束"); /* 结果: http localhost 8080 /Demo/index.html /Demo/index.html?name=admin&password=123 name=admin&password=123 结束 */ } }
-
使用URL下载
import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.URL; // 使用URL下载 public class URLDown { public static void main(String[] args) throws IOException { String strURL = "https://dss0.bdstatic.com/5aV1bjqh_Q23odCf/static/superman/img/logo/bd_logo1-66368c33f8.png"; // url地址 String downFilePath = "baidu.jpg"; // 下载文件存放路径 // 创建url URL url = new URL(strURL); // 打开url资源流 HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection(); InputStream is = urlConnection.getInputStream(); // 接收 File downFile = new File(downFilePath); FileOutputStream fos = new FileOutputStream(downFile); byte[] buffer = new byte[1024]; int len; while ((len=is.read(buffer))!=-1) { fos.write(buffer,0,len); } // 关闭资源 fos.close(); is.close(); urlConnection.disconnect(); } }