1. 什么是网络编程?
在网络通信协议下,不同计算机上运行的程序,进行的数据传输。
应用场景:即时通信、网游对战、金融证券、国际贸易、邮件、等等。
不管是什么场景,都是计算机跟计算机之间通过网络进行数据传输。
Java中可以使用java.net包下的技术轻松开发出常见的网络应用程序。
2. 常见的软件架构
BS架构的优缺点
- 不需要开发客户端,只需要页面+服务端
- 用户不需要下载,打开浏览器就能使用
- 如果应用过大,用户体验受到影响
CS架构的优缺点
- 画面可以做的非常精美,用户体验好
- 需要开发客户端,也需要开发服务端
- 用户需要下载和更新的时候太麻烦
3. 网络编程三要素
IP:设备在网络中的地址,是唯一的标识。
端口号:应用程序在设备中唯一的标识。
协议:数据在网络中传输的规则,常见的协议有UDP、TCP、http、https、ftp。
3.1 IP地址
3.1.1 IP地址分为两大类
- IPv4:是给每个连接在网络上的主机分配一个32bit地址。按照TCP/IP规定,IP地址用二进制来表示,每个IP地址长32bit,也就是4个字节。例如一个采用二进制形式的IP地址是“11000000 10101000 00000001 01000010”。为了方便使用,IP地址经常被写成十进制的形式,中间使用符号“.”分隔不同的字节。于是,上面的IP地址可以表示为“192.168.1.66”。IP地址的这种表示法叫做“点分十进制表示法”
- IPv6:由于互联网的蓬勃发展,IP地址的需求量愈来愈大,但是网络地址资源有限,使得IP的分配越发紧张。为了扩大地址空间,通过IPv6重新定义地址空间,采用128位地址长度,每16位为一组,分成8组十六进制数,这样就解决了网络地址资源数量不够的问题
3.1.2 IPV4的地址分类形式
- 公网地址(万维网使用)和私有地址(局域网使用)。
- 192.168.开头的就是私有址址,范围即为192.168.0.0-192.168.255.255,专门为组织机构内部使用,以此节省IP
3.1.3 特殊IP地址
- 127.0.0.1,也可以是localhost : 是回送地址也称本地回环地址,也称本机IP,永远只会寻找当前所在本机。
3.1.4 InetAddress相关方法
方法名 | 说明 |
---|---|
static InetAddress getByName(String host) | 确定主机名称的IP地址。主机名称可以是机器名称,也可以是IP地址 |
String getHostName() | 获取此IP地址的主机名 |
String getHostAddress() | 返回文本显示中的IP地址字符串 |
代码实例:
package com.bobo.ip.InetAddress;
import java.net.InetAddress;
import java.net.UnknownHostException;
public class Test {
public static void main(String[] args) throws UnknownHostException {
//获取InetAddress对象
InetAddress address = InetAddress.getByName("bobo");
System.out.println(address);//bobo/192.168.1.5
String ip = address.getHostAddress();
System.out.println(ip);//192.168.1.5
String name = address.getHostName();
System.out.println(name);//bobo
}
}
3.2 端口号
应用程序在设备中唯一的标识。
- 由两个字节表示的整数,取值范围:0~65535
- 其中0~1023之间的端口号用于一些知名的网络服务或者应用。
- 我们自己使用1024以上的端口号就可以了。
注意:一个端口号只能被一个应用程序使用。
3.3 协议
计算机网络中,连接和通信的规则被称为网络通信协议
OS引参考模型:世界互联协议标准,全球通信规范,单模型过于理想化,未能在因特网上进行广泛推广
TCP/IP参考模型(或TCP/IP协议):事实上的国际标准。
UDP协议
- 用户数据报协议(User Datagram Protocol)
- UDP是面向无连接通信协议(直接发送信息,不管是否确认连接)
- 速度快,有大小限制一次最多发送64K,数据不安全,易丢失数据
- 通常都会用于音频、视频和普通数据的传输
TCP协议
- 传输控制协议TCP(Transmission Control Protocol)
- TCP协议是面向连接的通信协议(确认连接再发送信息)
- 速度慢,没有大小限制,数据安全。
- 通常用于上传文件、下载文件、浏览网页等
3.3.1 UDP通信程序(发送数据)
发送数据的步骤
- 创建发送端的Socket对象(DatagramSocket)
- 创建数据,并把数据打包
- 调用DatagramSocket对象的方法发送数据
- 关闭发送端
构造方法
方法名 | 说明 |
---|---|
DatagramSocket() | 创建数据报套接字并将其绑定到本机地址上的随机可用端口 |
DatagramPacket(byte[] buf,int len,InetAddress add,int port) | 创建数据包,发送长度为len的数据包到指定主机的指定端口 |
相关方法
方法名 | 说明 |
---|---|
void send(DatagramPacket p) | 发送数据报包 |
void close() | 关闭数据报套接字 |
void receive(DatagramPacket p) | 从此套接字接受数据报包 |
代码实例:
package com.bobo.ip.UDP;
import java.io.IOException;
import java.net.*;
public class Test {
public static void main(String[] args) throws IOException {
//1.创建DatagramSocket对象(快递公司)
//细节:
//绑定端口,以后我们就是通过这个端口往外发送
//空参:所有可用的端口中随机一个进行使用
//有参:指定端口号进行锦定
DatagramSocket ds = new DatagramSocket();
//2.打包数据
String str = "hello";
byte[] bytes = str.getBytes();
InetAddress address = InetAddress.getByName("127.0.0.1");
int port = 10086;
DatagramPacket dp = new DatagramPacket(bytes,bytes.length,address,port);
//3.发送数据
ds.send(dp);
//4.释放资源
ds.close();
}
}
3.3.2 UDP通信程序(接收数据)
接收数据的步骤
- 创建接收端的DatagramSocket对象
- 接收打包好的数据
- 解析数据包
- 释放资源
代码实例:
package com.bobo.ip.UDP;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
public class Test1 {
public static void main(String[] args) throws IOException {
/*
接收数据
*/
//1.创建DatagramSocket对象(快递公司)
DatagramSocket ds = new DatagramSocket(10086);
//2.接收数据包
byte[] bytes = new byte[1024];
DatagramPacket dp = new DatagramPacket(bytes, bytes.length);
ds.receive(dp);
//3.解析数据包
byte[] data = dp.getData();
int len = dp.getLength();
InetAddress address = dp.getAddress();
int port = dp.getPort();
System.out.println("数据是:" + new String(dp.getData(), 0, dp.getLength()));
System.out.println("该数据是从" + address + "这台电脑中的" + port + "这个端口发出的");
//4.释放资源
ds.close();
}
}
3.3.3 UDP的三种通信方式
-
单播
单播用于两个主机之间的端对端通信,(以前的代码就是单播) -
组播
组播用于对一组特定的主机进行通信
组播地址:224.0.0.0~239.255.255.255
其中224.0.0.0~224.0.0.255为预留的组播地址 -
广播
广播用于一个主机对整个局域网上所有主机上的数据通信
广播地址:255.255.255.255
组播代码实例:
package com.bobo.ip.UDP2;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
public class SendMessage {
public static void main(String[] args) throws IOException {
/*
组播 发送端代码
*/
//创建MulticastSocket对象
MulticastSocket ms = new MulticastSocket() ;
// 创建DatagramPacket对象
String s = "你好,你好!" ;
byte[] bytes = s.getBytes();
InetAddress address = InetAddress.getByName("224.0.0.1");
int port = 10000;
DatagramPacket datagramPacket = new DatagramPacket(bytes, bytes.length, address, port) ;
// 调用MulticastSocket发送数据方法发送数据
ms.send(datagramPacket);
// 释放资源
ms.close();
}
}
package com.bobo.ip.UDP2;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
public class ReceiveMessage {
public static void main(String[] args) throws IOException {
/*
组播接收端代码
*/
//1. 创建MulticastSocket对象
MulticastSocket ms = new MulticastSocket(10000);
//2. 将将当前本机,添加到224.0.0.1的这一组当中
InetAddress address = InetAddress.getByName("224.0.0.1");
ms.joinGroup(address);
//3. 创建DatagramPacket数据包对象
byte[] bytes = new byte[1024];
DatagramPacket dp = new DatagramPacket(bytes, bytes.length);
//4. 接收数据
ms.receive(dp);
//5. 解析数据
byte[] data = dp.getData();
int len = dp.getLength();
String ip = dp.getAddress().getHostAddress();
String name = dp.getAddress().getHostName();
System.out.println("ip为:" + ip + ",主机名为:" + name + "的人,发送了数据:" + new String(data,0,len));
//6. 释放资源
ms.close();
}
}
package com.bobo.ip.UDP2;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
public class ReceiveMessage1 {
public static void main(String[] args) throws IOException {
/*
组播接收端代码
*/
//1. 创建MulticastSocket对象
MulticastSocket ms = new MulticastSocket(10000);
//2. 将将当前本机,添加到224.0.0.1的这一组当中
InetAddress address = InetAddress.getByName("224.0.0.1");
ms.joinGroup(address);
//3. 创建DatagramPacket数据包对象
byte[] bytes = new byte[1024];
DatagramPacket dp = new DatagramPacket(bytes, bytes.length);
//4. 接收数据
ms.receive(dp);
//5. 解析数据
byte[] data = dp.getData();
int len = dp.getLength();
String ip = dp.getAddress().getHostAddress();
String name = dp.getAddress().getHostName();
System.out.println("ip为:" + ip + ",主机名为:" + name + "的人,发送了数据:" + new String(data,0,len));
//6. 释放资源
ms.close();
}
}
广播代码实例:
只需将 address 改成 255.255.255.255 即可
package com.bobo.ip.UDP3;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Scanner;
public class SendMessage {
public static void main(String[] args) throws IOException {
/*
UDP发送数据:
数据来自键盘录入,直到输入的数据是886,发送数据结束
*/
//创建发送端的Socket对象(DatagramSocket)
DatagramSocket ds = new DatagramSocket();
Scanner sc = new Scanner(System.in);
while (true) {
System.out.println("please input your words");
String str = sc.nextLine();
if ("886".equals(str)){
break;
}
//创建数据,并把数据打包
byte[] bytes = str.getBytes();
InetAddress address = InetAddress.getByName("255.255.255.255");
int port = 10086;
DatagramPacket dp = new DatagramPacket(bytes, bytes.length, address, port);
//调用DatagramSocket对象的方法发送数据
ds.send(dp);
}
//关闭发送端
ds.close();
}
}
3.3.4 TCP通信协议
TCP通信协议是一种可靠的网络协议,它在通信的两端各建立一个Socket对象
通信之前要保证连接已经建立
通过Socket产生IO流来进行网络通信
代码实例:
package com.bobo.ip.TCP;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
public class Client {
public static void main(String[] args) throws IOException {
/*
TCP协议,发送数据
*/
//1.创建Socket对象
//细节:在创建对象的同时会连接服务端
//如果连接不上,代码会报错
Socket socket = new Socket("127.0.0.1",10086);
//2.可以从连接通道中获取输出流
OutputStream os = socket.getOutputStream();
//写回数据
os.write("hello".getBytes());
os.write("你好".getBytes());
//3.释放资源
os.close();
socket.close();
}
}
package com.bobo.ip.TCP;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
public class Server {
public static void main(String[] args) throws IOException {
/*
TCP协议,接收数据
*/
//1.创建对象Se
ServerSocket ss = new ServerSocket(10086);
//2.监听客户端的链接
Socket socket = ss.accept();
//3.从连接通道中获取输入流读取数据
InputStream is = socket.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
int b;
while ((b = isr.read()) != -1){
System.out.println((char) b);
}
//4.释放资源
socket.close();//断开与客户端的连接
ss.close();
}
}
三次握手和四次挥手