1.网络编程三要素
1.IP地址
设备在网络中的地址,是唯一的标识。
2.端口
应用程序在设备中唯一的标识。
3.协议
数据在网络中传输的规则,常见的协议有UDP协议和TCP协议。
2.IP
IP:全称”互联网协议地址”,也称IP地址。是分配给上网设备的数字标签。常见的IP分类为:ipv4和ipv6
IPv6:由于互联网的蓬勃发展,IP地址的需求量愈来愈大,而IPv4的模式下IP的总数是有限的。 采用128位地址长度,分成8组。
InetAddress 的使用
为了方便我们对IP地址的获取和操作,Java提供了一个类InetAddress 供我们使用 InetAddress:此类表示Internet协议(IP)地址
3.端口
端口:应用程序在设备中唯一的标识。
端口号:用两个字节表示的整数,它的取值范围是0~65535。 其中0~1023之间的端口号用于一些知名的网络服务或者应用。 我们自己使用1024以上的端口号就可以了。 注意:一个端口号只能被一个应用程序使用。
4.协议
协议:计算机网络中,连接和通信的规则被称为网络通信协议
UDP协议
1.用户数据报协议(User Datagram Protocol)
2.UDP是面向无连接通信协议。 速度快,有大小限制一次最多发送64K,数据不安全,易丢失数据。
TCP协议
1. 传输控制协议 (Transmission Control Protocol)
2. TCP协议是面向连接的通信协议。 速度慢,没有大小限制,数据安全。
5.UDP通信
大致步骤
udp发送端步骤
1.创建发送端的DatagramSocket对象
2.创建数据,并把数据打包(DatagramPacket)
3.调用DatagramSocket对象的方法发送数据
4.释放资源
UDP接收端步骤
1.创建接收端的DatagramSocket对象
2.创建一个箱子,用于接收数据
3.调用DatagramSocket的方法接收数据并将数据放入箱子中
4.解析数据包,并把数据在控制台显示
5.释放资源
6.UDP通信---单播
客户端代码:
public class ClientDemo {
private static String host = "127.0.0.1";
private static int port = 10000;
private static Scanner sc = new Scanner(System.in);
public static void main(String[] args) {
DatagramSocket ds = null;
String msg;
try {
ds = new DatagramSocket();// 创建连接对象
do {
System.out.println("请输入要发送的消息");
msg = sc.nextLine();
byte[] bytes = msg.getBytes(StandardCharsets.UTF_8);
DatagramPacket dp = new DatagramPacket(bytes, bytes.length, InetAddress.getByName(host), port); // 创建一个包裹 并指定 ip地址和端口号
ds.send(dp); // 发送数据
} while (!"886".equals(msg));
}catch (Exception e){
e.printStackTrace();
}finally {
ds.close();
}
}
}
服务端代码:
public class ServerDemo {
public static void main(String[] args) throws IOException {
DatagramSocket ds = new DatagramSocket(10000); //指定监听的端口号
byte[] bytes = new byte[1024];
DatagramPacket dp = new DatagramPacket(bytes, bytes.length);
while (true) {
ds.receive(dp); //这里如果没有 发送端来连接 会在这里阻塞 死等
int length = dp.getLength();
byte[] data = dp.getData();
String msg = new String(data, 0, length);
if("886".equals(msg)){
System.out.println("接收端stop");
ds.close();
break;
}
System.out.println("接收端:" + msg);
}
}
}
7.UDP通信---组播
组播地址:224.0.0.0 ~ 239.255.255.255 其中224.0.0.0 ~ 224.0.0.255 为预留的组播地址
客户端代码
public class clientDemo {
public static void main(String[] args) throws IOException {
DatagramSocket ds = new DatagramSocket();
byte[] bytes = "你好 我是xxx".getBytes(StandardCharsets.UTF_8);
InetAddress address = InetAddress.getByName("224.0.1.0"); // 创建组播地址
int port = 10000;
DatagramPacket dp = new DatagramPacket(bytes, bytes.length, address, port); // 创建 包裹 制动组播地址 和端口号
ds.send(dp); // 发送
ds.close();
}
}
服务端1代码
public class ServerDemo1 {
public static void main(String[] args) throws IOException {
MulticastSocket ms = new MulticastSocket(10000); // 定义组播通信对象 并指定端口号
DatagramPacket dp = new DatagramPacket(new byte[1024], 1024);
ms.joinGroup(InetAddress.getByName("224.0.1.0")); // 将本机加入到组播中
ms.receive(dp);
byte[] data = dp.getData();
int length = dp.getLength();
System.out.println("接收端1:");
System.out.println(new String(data, 0, length));
}
}
服务端2代码
public class ServerDemo2 {
public static void main(String[] args) throws IOException {
MulticastSocket ms = new MulticastSocket(10000); // 定义组播通信对象 并指定端口号
DatagramPacket dp = new DatagramPacket(new byte[1024], 1024);
ms.joinGroup(InetAddress.getByName("224.0.1.0")); // 将本机加入到组播中
ms.receive(dp);
byte[] data = dp.getData();
int length = dp.getLength();
System.out.println("接收端2:");
System.out.println(new String(data, 0, length));
}
}
8.UDP通信---广播
广播地址:255.255.255.255
客户端代码
public class clientDemo {
public static void main(String[] args) throws IOException {
DatagramSocket ds = new DatagramSocket();
byte[] bytes = "你好 我是xxx".getBytes(StandardCharsets.UTF_8);
InetAddress address = InetAddress.getByName("255.255.255.255");// 指定255.255.255.255 说明是广播地址
int port = 10000;
DatagramPacket dp = new DatagramPacket(bytes, bytes.length, address, port); // 创建包裹
ds.send(dp);
ds.close();
}
}
服务端代码
// 组播代码
public class ServerDemo1 {
public static void main(String[] args) throws IOException {
MulticastSocket ms = new MulticastSocket(10000); // 创建组播连接对象
DatagramPacket dp = new DatagramPacket(new byte[1024], 1024); // 创建包裹
ms.joinGroup(InetAddress.getByName("224.0.1.0")); // 将本机加入到 组播中
ms.receive(dp);
byte[] data = dp.getData();
int length = dp.getLength();
System.out.println("接收端1:");
System.out.println(new String(data, 0, length));
}
}
// 组播代码
public class ServerDemo1 {
public static void main(String[] args) throws IOException {
MulticastSocket ms = new MulticastSocket(10000); // 创建组播连接对象
DatagramPacket dp = new DatagramPacket(new byte[1024], 1024); // 创建包裹
ms.joinGroup(InetAddress.getByName("224.0.1.0")); // 将本机加入到 组播中
ms.receive(dp);
byte[] data = dp.getData();
int length = dp.getLength();
System.out.println("接收端2:");
System.out.println(new String(data, 0, length));
}
}
//注意:组播 和 单播不能同时监听统一端口
//单播代码
public class ServerDemo3 {
public static void main(String[] args) throws IOException {
DatagramSocket ds = new DatagramSocket(10000); // 创建单播连接对象
DatagramPacket dp = new DatagramPacket(new byte[1024], 1024); // 创建 包裹
ds.receive(dp);
byte[] data = dp.getData();
int length = dp.getLength();
System.out.println("单播的接受端:");
System.out.println(new String(data, 0, length));
}
}
9.TCP通信
TCP通信协议是一种可靠的网络协议,它在通信的两端各建立一个Socket对象。
通信之前要保证连接已经建立。
通过Socket产生IO流来进行网络通信。
TCP发送数据步骤
发送数据的步骤
① 创建客户端的Socket对象(Socket)与指定服务端连接
Socket(String host, int port)
② 获取输出流,写数据
OutputStream getOutputStream()
③ 释放资源
void close()
TCP接收数据 接收数据的步骤
接收数据的步骤
① 创建服务器端的Socket对象(ServerSocket)
ServerSocket(int port)
② 监听客户端连接,返回一个Socket对象
Socket accept()
③ 获取输入流,读数据,并把数据显示在控制台
InputStream getInputStream()
④ 释放资源
void close()
10.TCP三次握手
11.TCP四次挥手
12.TCP通信---代码
客户端代码
public class ClientSocket {
public static void main(String[] args) throws IOException {
Socket socket = new Socket("127.0.0.1", 10000);// 创建 socket对象 指定发送的IP地址和端口号
OutputStream os = socket.getOutputStream(); // 获取 输出流 可以将数组 输出到网络通道中
os.write("hello".getBytes());
socket.shutdownOutput(); // 发送结束标志 表示客户端已经 发送完毕(如果不声明 服务端将无法获取停止标志 意味着服务端 将会一直在这个线程中死循环)
InputStream inputStream = socket.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));
String s;
while ((s = br.readLine()) != null){
System.out.println(s);
}
os.close();
br.close();
socket.close();
}
}
服务端代码
public class ServerSocketDemo {
public static void main(String[] args) throws IOException {
ServerSocket ss = new ServerSocket(10000); // 创建tcp连接 并指定监听端口
Socket accept = ss.accept(); // 接受客户端的数据 如果没有连接 将会死等 阻塞状态
InputStream is = accept.getInputStream();
int b;
while ((b = is.read()) != -1){
System.out.print((char) b); // 获取客户端的数据并打印
}
OutputStream os = accept.getOutputStream();
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(os)); // 给客户端 回数据
bw.write("你谁啊?");
bw.newLine();
bw.flush();
is.close();
bw.close();
ss.close();
}
}
13.TCP实现图片上传(多线程上传)
要求:
客户端:将本地文件上传到服务器。接收服务器的反馈。
服务器:接收客户端上传的文件,上传完毕之后给出反馈。
客户端代码
public class clientDemo {
public static void main(String[] args) throws IOException {
Socket socket = new Socket("127.0.0.1", 10000); // 创建 socket对象 指定发送的IP地址和端口号
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("src/main/resources/a1.jpeg")); // 指定本地数组地址
BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream()); // 使用字节缓冲流 写数据 效率高
int len;
byte[] bytes = new byte[1024 * 8];
while ((len = bis.read(bytes)) != -1){
bos.write(bytes, 0, len);
}
socket.shutdownOutput(); // 结束标志
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream())); // 使用转换流 将字节流变成 字符流
String line;
while ((line = br.readLine()) != null){ //将服务端的 回文 显示出来
System.out.println(line);
}
bis.close();
br.close();
socket.close();
}
}
服务端代码
// 使用 线程池的方式 创建多线程
public class serverDemo {
public static void main(String[] args) throws IOException {
ServerSocket ss = new ServerSocket(10000);
ThreadPoolExecutor pool = new ThreadPoolExecutor(
3,// 核心线程数
10, // 最大线程数
60, // 临时线程的空闲时间 超过多少时间销毁
TimeUnit.SECONDS, // 临时线程的空闲时间的单位 超过多少时间销毁的单位
new ArrayBlockingQueue<>(5), // 阻塞队列 最多5个线程阻塞
Executors.defaultThreadFactory(), //创建线程的方式
new ThreadPoolExecutor.AbortPolicy() // 拒绝策略
);
while (true){
Socket accept = ss.accept();
MyTask myTask = new MyTask(accept);
pool.submit(myTask);
}
}
}
线程代码
public class MyTask implements Runnable{
private Socket accept; //定义 tcp通信对象
public MyTask(Socket a){
this.accept = a;
}
@Override
public void run() {
BufferedOutputStream bos = null;
try {
InputStream is = accept.getInputStream();
BufferedInputStream bis = new BufferedInputStream(is);
bos = new BufferedOutputStream(new FileOutputStream("src/main/resources/"+ UUID.randomUUID().toString() +".jpeg"));
int len;
byte[] bytes = new byte[1024];
while ((len = bis.read(bytes)) != -1){
bos.write(bytes, 0 ,len);
}
// 给客户端回消息
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(accept.getOutputStream()));
bw.write("上传完成");
bw.newLine();
bw.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
accept.close();
if(bos != null) {
bos.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}