网络编程
编程 : 使用java语言编写程序,实现不同计算机应用程序之间的数据传输。
组成部分
为什么可以在百度的平台上,查询一些数据?
1.百度也是一台计算机(服务器)----> 服务器一直开启
2.另外一台计算机请求一些数据---->百度服务器响应
https://www.baidu.com/: 百度服务器的路径
https: 协议
www.baidu.com: 域名 (花钱购买) 方便用户记忆== 计算机的ip+端口
协议
*** TCP/IP 协议族**: 传输控制协议/互联网协议 (打电话)—>三次握手
https: 超文本传输协议+s(数字安全证书)
http: 超文本传输协议
ftp: 文件传输协议
smtp: 简单邮件传输协议
pop3: qq邮箱 邮箱协议
UDP: 用户数据报协议 (发短信)—>丢包—> 直播(花屏)
程序项目开发:
- C/S : 全称为Client/Server结构,是指客户端和服务器结构。常见程序有QQ、迅雷等软件。
- *** B/S**: 全称为Browser/Server结构,是指浏览器和服务器结构。常见浏览器有谷歌、火狐等。
网络通信协议
-
**网络通信协议:**通过计算机网络可以使多台计算机实现连接,位于同一个网络中的计算机在进行连接和通信时需要遵守一定的规则,这就好比在道路中行驶的汽车一定要遵守交通规则一样。在计算机网络中,这些连接和通信的规则被称为网络通信协议,它对数据的传输格式、传输速率、传输步骤等做了统一规定,通信双方必须同时遵守才能完成数据交换。
-
TCP/IP协议: 传输控制协议/因特网互联协议( Transmission Control Protocol/Internet Protocol),是Internet最基本、最广泛的协议。它定义了计算机如何连入因特网,以及数据如何在它们之间传输的标准。它的内部包含一系列的用于处理数据通信的协议,并采用了4层的分层模型,每一层都呼叫它的下一层所提供的协议来完成自己的需求。
上图中,TCP/IP协议中的四层分别是应用层、传输层、网络层和链路层,每层分别负责不同的通信功能。
链路层:链路层是用于定义物理传输通道,通常是对某些网络连接设备的驱动协议,例如针对光纤、网线提供的驱动。
网络层:网络层是整个TCP/IP协议的核心,它主要用于将传输的数据进行分组,将分组数据发送到目标计算机或者网络。
运输层:主要使网络程序进行通信,在进行网络通信时,可以采用TCP协议,也可以采用UDP协议。
应用层:主要负责应用程序的协议,例如HTTP协议、FTP协议等。
协议分类
通信的协议还是比较复杂的,java.net
包中包含的类和接口,它们提供低层次的通信细节。我们可以直接使用这些类和接口,来专注于网络程序开发,而不用考虑通信的细节。
java.net
包中提供了两种常见的网络协议的支持:
-
UDP:用户数据报协议(User Datagram Protocol)。UDP是无连接通信协议,即在数据传输时,数据的发送端和接收端不建立逻辑连接。简单来说,当一台计算机向另外一台计算机发送数据时,发送端不会确认接收端是否存在,就会发出数据,同样接收端在收到数据时,也不会向发送端反馈是否收到数据。
由于使用UDP协议消耗资源小,通信效率高,所以通常都会用于音频、视频和普通数据的传输例如视频会议都使用UDP协议,因为这种情况即使偶尔丢失一两个数据包,也不会对接收结果产生太大影响。
但是在使用UDP协议传送数据时,由于UDP的面向无连接性,不能保证数据的完整性,因此在传输重要数据时不建议使用UDP协议。UDP的交换过程如下图所示。
特点:数据被限制在64kb以内,超出这个范围就不能发送了。
数据报(Datagram):网络传输的基本单位
-
TCP:传输控制协议 (Transmission Control Protocol)。TCP协议是面向连接的通信协议,即传输数据之前,在发送端和接收端建立逻辑连接,然后再传输数据,它提供了两台计算机之间可靠无差错的数据传输。
在TCP连接中必须要明确客户端与服务器端,由客户端向服务端发出连接请求,每次连接的创建都需要经过“三次握手”。
- 三次握手:TCP协议中,在发送数据的准备阶段,客户端与服务器之间的三次交互,以保证连接的可靠。
- 第一次握手,客户端向服务器端发出连接请求,等待服务器确认。
- 第二次握手,服务器端向客户端回送一个响应,通知客户端收到了连接请求。
- 第三次握手,客户端再次向服务器端发送确认信息,确认连接。整个交互过程如下图所示。
- 三次握手:TCP协议中,在发送数据的准备阶段,客户端与服务器之间的三次交互,以保证连接的可靠。
完成三次握手,连接建立后,客户端和服务器就可以开始进行数据传输了。由于这种面向连接的特性,TCP协议可以保证传输数据的安全,所以应用十分广泛,例如下载文件、浏览网页等。
网络编程三要素
- 协议 2.IP地址 3.端口
IP地址
-
IP地址:指互联网协议地址(Internet Protocol Address),俗称IP。
-
IPv4:是一个32位的二进制数,通常被分为4个字节,表示成
a.b.c.d
的形式,例如192.168.65.100
。其中a、b、c、d都是0~255之间的十进制整数,那么最多可以表示42亿个。 -
IPv6:IPv6重新定义地址空间,采用128位地址长度,每16个字节一组,分成8组十六进制数,表示成
ABCD:EF01:2345:6789:ABCD:EF01:2345:6789
,号称可以为全世界的每一粒沙子编上一个网址,这样就解决了网络地址资源数量不够的问题。
常用命令
- 查看本机IP地址,在控制台输入:
ipconfig
- 检查网络是否连通,在控制台输入:
ping 空格 IP地址
ping 220.181.57.216
特殊的IP地址
- 本机IP地址:
127.0.0.1
、localhost
。
端口
0-65535 计算机软件应用程序制定端口(端口唯一) 0-1024 是系统保留 80本机端口
tomcat: 8080
mysql: 3306
oracl: 1521
netstat -ano
netstat -aon|findstr "49157"
常用类
java.net.*
InetAddtress —>
*** 代表的就是计算机的ip地址**。
Inet4Address , Inet6Address
此类表示Internet协议(IP)地址。
static InetAddress getLocalHost() 获得本机的ip地址
static InetAddress getByName(String host) 根据指定的计算机名称获得ip
public static void main(String[] args) {
try {
//创建对象
// InetAddress inetAddress = InetAddress.getLocalHost();
// System.out.println(inetAddress);//Lisa/192.168.12.75
// System.out.println("getHostName:" + inetAddress.getHostName());
// System.out.println("getHostAddress:" + inetAddress.getHostAddress());
// System.out.println("getAddress:" + Arrays.toString(inetAddress.getAddress()));
System.out.println(InetAddress.getByName("JAVA-20200618FB"));//192.168.12.228
InetAddress inetAddress = Inet6Address.getByName("Lisa");
System.out.println(inetAddress);
//fe80::a811:5ea3:f814:61dd%6
} catch (UnknownHostException e) {
e.printStackTrace();
}
}
URL
https://www.baidu.com/ 路径 万维网的资源的指针 统一资源定位符
http://192.168.12.75:80/demo/a.html?name=jim&pass=1234#abc
URL(String spec)
//通过url可以访问服务(接口): 抓取小说内容
//http/https: 数据读写IO
public static void main(String[] args) {
String path = "http://www.javasm.cn";
try {
URL url = new URL(path);
System.out.println(url);
System.out.println(url.getPath());// /demo/a.html
System.out.println(url.getAuthority());// 192.168.12.75:80
System.out.println(url.getDefaultPort());//80
System.out.println(url.getPort());//8081
System.out.println(url.getProtocol());//http
System.out.println(url.getFile());// /demo/a.html?name=jim&pass=1234
System.out.println(url.getHost());//192.168.12.75
System.out.println(url.getQuery());// ? 参数的数据
System.out.println(url.getRef());// 锚记 #abc
System.out.println(url.getContent());//内容 IO的对象 输入流 sun.net.www.protocol.http.HttpURLConnection$HttpInputStream@3d075dc0
// InputStream inputStream = url.openStream();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
Socket
基于TCP协议的网络编程。
两个进程间可以通过一个双向的网络通信连接实现数据交换,这种通信链路的端点被称为“套接字”(Socket)
服务端
1.创建服务端应用程序
ServerSocket:
指定在哪一台机器上创建服务端程序,并监听指定端口 1025-65535
ServerSocket(int port)
ServerSocket serverSocket = new ServerSocket(6666);
- 服务端等待客户端的主动连接
Socket clientSocket = serverSocket.accept();//阻塞 clientSocket客户端
System.out.println("clientSocket:" + clientSocket);
- 服务端读写数据
while(true) {
Socket clientSocket = serverSocket.accept();//阻塞 clientSocket客户端
System.out.println("clientSocket:" + clientSocket);
//3.数据传输 IO读写
//服务端给客户端发送信息 ----> 将信息写给客户端---> 输出流
String msg = "server: 欢迎你,"+clientSocket.getInetAddress().getHostAddress();
//数据流: writeUTF() DataOutputStream
DataOutputStream dataOutputStream = new DataOutputStream(clientSocket.getOutputStream());
dataOutputStream.writeUTF(msg);
DataInputStream dataInputStream = new DataInputStream(clientSocket.getInputStream());
System.out.println(dataInputStream.readUTF());
}
客户端
- 创建客户端 主动连接服务端程序
Socket(InetAddress address, int port)
Socket(String host, int port)
//-----------------------------------------------
//1 创建客户端程序(主动发起连接)--->连接哪一台主机上面的端口为哪个的服务端程序
Socket socket = new Socket(InetAddress.getLocalHost(),6666);
//socket: 服务端程序
- 客户端读写数据
try {
//1 创建客户端程序(主动发起连接)--->连接哪一台主机上面的端口为哪个的服务端程序
Socket socket = new Socket(InetAddress.getLocalHost(),6666);
//socket: 服务端程序
//客户端读取服务端发送的信息----> readUTF
DataInputStream dataInputStream = new DataInputStream(socket.getInputStream());
System.out.println(dataInputStream.readUTF());
//客户端给服务发信息--->write
String msg = "client: 你好,服务器";
DataOutputStream dataOutputStream = new DataOutputStream(socket.getOutputStream());
dataOutputStream.writeUTF(msg);
} catch (IOException e) {
e.printStackTrace();
}
动态交互数据
public class Server {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
final String server = "server: ";
try {
ServerSocket serverSocket = new ServerSocket(9999);
System.out.println("------------------服务端启动-----------------");
while (true) {
Socket client = serverSocket.accept();
while (true) {
//读写数据
//1.写
DataOutputStream dataOutputStream = new DataOutputStream(client.getOutputStream());
String msg = input.nextLine();
if(msg.equals("bye")){
break;
}
dataOutputStream.writeUTF(server + msg);
//2.读
DataInputStream dataInputStream = new DataInputStream(client.getInputStream());
System.out.println(dataInputStream.readUTF());
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
public class Client {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
final String server = "client: ";
try {
Socket socket = new Socket("192.168.12.75", 9999);
while (true) {
//读写数据
//2.读
DataInputStream dataInputStream = new DataInputStream(socket.getInputStream());
System.out.println(dataInputStream.readUTF());
//1.写
DataOutputStream dataOutputStream = new DataOutputStream(socket.getOutputStream());
String msg = input.nextLine();
dataOutputStream.writeUTF(server + msg);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
优化封装代码
----将读 写功能封装成类 并调用时可以多线程监听 这样就可以多次聊天
//服务端
public class Server {
public static void main(String[] args) {
final String server = "server: ";
try {
ServerSocket serverSocket = new ServerSocket(9999);
System.out.println("------------------服务端启动-----------------");
while (true) {
Socket client = serverSocket.accept();
//线程读写
new ReadThread(client, server).start();
new WriteThread(client, server).start();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
//客户端
public class Client {
public static void main(String[] args) {
final String client = "client: ";
try {
Socket socket = new Socket("192.168.12.75", 9999);
new ReadThread(socket, client).start();
new WriteThread(socket, client).start();
} catch (IOException e) {
e.printStackTrace();
}
}
}
//读重写
public class ReadThread extends Thread {
private Socket socket;//null
public ReadThread(Socket socket, String name) {
super(name);
this.socket = socket;
}
@Override
public void run() {
DataInputStream dataInputStream = null;
try {
dataInputStream = new DataInputStream(socket.getInputStream());
while (true) {
System.out.println(dataInputStream.readUTF());
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
//写
public class WriteThread extends Thread {
private Socket socket;
public WriteThread(Socket socket, String name) {
super(name);
this.socket = socket;
}
@Override
public void run() {
Scanner input = new Scanner(System.in);
DataOutputStream dataOutputStream = null;
while (true) {
try {
dataOutputStream = new DataOutputStream(socket.getOutputStream());
System.out.print(getName());
String msg = input.nextLine();
dataOutputStream.writeUTF(getName()+msg);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
UDP
了解
发送数据:
发送者/接收者: DatagramSocket DatagramPacket
DatagramPacket(byte[] buf, int length, InetAddress address, int port) 发送数据
DatagramPacket(byte[] buf, int length) 接收数据
DatagramSocket(int port) 此类表示用于发送和接收数据报数据包的套接字。
DatagramSocket(int port, InetAddress laddr)
public class ReceiveMsgUDP {//服务端
public static void main(String[] args) {
try {
//创建接收数据socket
DatagramSocket socket = new DatagramSocket(6666,InetAddress.getLocalHost());
//存储接收的数据的
byte[] buf = new byte[1024];
DatagramPacket packet = new DatagramPacket(buf,buf.length);
//接收数据
socket.receive(packet);
// System.out.println(new String(buf));
// byte[] data = packet.getData();
// int length = packet.getLength();
System.out.println(new String( packet.getData(),0,packet.getLength()));
} catch (SocketException e) {
e.printStackTrace();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public class SendMsgUDP {//等同于客户端
public static void main(String[] args) {
//创建发送数据的socket
try {
DatagramSocket datagramSocket = new DatagramSocket();
String msg = "hello,world";
//将发送的数据存储到数据包中
byte[] bytes = msg.getBytes();
DatagramPacket packet = new DatagramPacket(bytes, bytes.length, InetAddress.getLocalHost(), 6666);
//DatagramPacket(byte[] buf, int length, InetAddress address, int port)
datagramSocket.send(packet);
} catch (SocketException e) {
e.printStackTrace();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}