网络编程及三大协议(TCP + UDP + Http)

网络编程及三大协议(TCP + UDP + Http)

一、网络编程

1.计算机网络

是指将地理位置不同的具有独立功能的多台计算机及其外部设备,通过通信线路连接起来,在网络操作系统,网络管理软件及网络通信协议的管理和协调下,实现资源共享和信息传递的计算机系统。

2.网络编程

实现多台计算机之间实现数据的共享和传递,网络应用程序主要组成为:
网络编程+IO流+多线程

3.网络编程三要素

网络通讯的模型:请求-响应,客户端-服务端

三要素:IP地址,端口,协议(数据传输的规则)

1.IP地址

1.1.IP地址:网络中计算机的唯一标识(IP地址是一个32位的二进制数据,为了方便,将一个字节的二进制转换为一个十进制的数据)

1.2.IP地址的组成:网络号段+主机段

1.3.1.A类IP地址:第一段号码为网络号码,剩下的三段号码为本地计算机的号码
----可以配置256256256台主机

1.3.2.B类IP地址:前二段号码为网络号码,剩下的二段号码为本地计算机的号码
1.3.3.C类IP地址:前三段号码为网络号码,剩下的一段号码为本地计算机的号码
1.3.4.特殊地址:
127.0.0.1 回环地址,可用于测试本机的网络是否有问题. ping 127.0.0.1
DOS命令 ipconfig:查看本机IP地址

补充:
A类地址的表示范围为:0.0.0.0~126.255.255.255,默认网络屏蔽为:255.0.0.0;A类地址分配给规模特别大的网络使用。A类网络用第一组数字表示网络本身的地址,后面三组数字作为连接于网络上的主机的地址。分配给具有大量主机(直接个人用户)而局域网络个数较少的大型网络。例如IBM公司的网络。

B类地址的表示范围为:128.0.0.0~191.255.255.255,默认网络屏蔽为:255.255.0.0;

C类地址的表示范围为:192.0.0.0~223.255.255.255,默认网络屏蔽为:255.255.255.0;C类地址分配给小型网络,如一般的局域网和校园网,它可连接的主机数量是最少的,采用把所属的用户分为若干的网段进行管理。

2.端口号

正在运行的程序的标识

  1. A:每个网络程序都会至少有一个逻辑端口

  2. B:用于标识进程的逻辑地址,不同进程的标识不同

  3. C:有效端口:0-65535,其中0-1024系统使用或保留端口。

a) 80

b) ftp:23

c) www.baidu.com:80

  1. 通过第三方工具可以查看

注意:端口与协议有关:TCP和UDP的端口互不相干,同一个协议的端口不能重复,不同协议的可以重复

TCP:10086

UDP:10086

3.协议

通信规则,就是数据的传输规则

TCP、UDP都是传输层的协议

TCP建立连接,形成传输数据的通道;在连接中进行大数据量传输;通过三次握手完成连接,是可靠协议;必须建立连接,效率会稍低,例如:打电话

UDP将数据源和目的封装到数据包中,不需要建立连接;每个数据报的大小在限制在64k;因无连接,是不可靠协议;不需要建立连接,速度快:例如发短信

4.InetAddress – 主机类

import java.net.InetAddress;
import java.net.UnknownHostException;

public class Test01 {

	public static void main(String[] args) throws UnknownHostException {
		
		//获取到指定域名的服务器IP地址
//		InetAddress byName = InetAddress.getByName("www.baidu.com");
//  	System.out.println(byName);//14.215.177.39
	
		//获取到指定域名的所有服务器 IPd地址
//		InetAddress[] allByName = InetAddress.getAllByName("www.baidu.com");
//		for (InetAddress inetAddress : allByName) {
//			System.out.println(inetAddress);
//		}
		
		//获取到本机的IP地址
		InetAddress localHost = InetAddress.getLocalHost();
		System.out.println(localHost);
	}
}

二、TCP协议

Scoket也叫套接字,其表示的是IP地址和端口号的组合。

网络编程主要就是指Socket编程,网络间的通信其实就是Socket间的通信,数据就通过IO流在两个Scoket间进行传递。

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.Socket;
import java.net.UnknownHostException;

//客户端
public class Client {
	//注意:关闭流等于关闭Socket
	public static void main(String[] args) throws UnknownHostException, IOException {
		
		//武松
		Socket socket = new Socket("127.0.0.001", 8888);
		
		//1.向服务端发送消息
		PrintStream ps = new PrintStream(socket.getOutputStream());
		ps.println("武松:小二,上好酒好菜!");
		
		//4.接收来自服务端的消息
		BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream(), "GBK"));
		String readLine = br.readLine();
		System.out.println(readLine);
		
		//关闭资源
		ps.close();
		br.close();
		socket.close();
	}
}
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;
//服务端
public class Server {

	public static void main(String[] args) throws IOException {
		
		//客栈掌柜
		ServerSocket server = new ServerSocket(8888);
		
		System.out.println("等待端连接中...");
		
	
		//店小二
		//accept()是线程阻塞的方法,客户端和服务端连接成功后才会生成一个Socket对象
		Socket socket = server.accept();
		
		System.out.println("欢迎光临,客人来了~~~");
		
		//2.接收来自客户端的消息
		BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream(),"GBK"));
		String readLine = br.readLine();
		System.out.println(readLine);
		
		//3.向客户端发送消息
		PrintStream ps = new PrintStream(socket.getOutputStream());
		ps.println("店小二:好的,您请坐!");
		
		//关闭资源
		br.close();
		ps.close();
		socket.close();
		server.close();
	}
}

1.TCP案例之 传输文件

import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;

public class Client {

	public static void main(String[] args) throws UnknownHostException, IOException {
		
		Socket socket = new Socket("127.0.0.002", 6666);
		
		//客户端读取源文件,通过Socket提供的输出流向服务端传输数据即可
		
		FileInputStream fis = new FileInputStream("测试视频.mp4");
		OutputStream os = socket.getOutputStream();
		
		byte[] b = new byte[1024];
		int len;
		while ((len = fis.read(b)) != -1) {
			os.write(b, 0, len);
		}
		fis.close();
		os.close();
		socket.close();
	}
}
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class Server {

	public static void main(String[] args) throws IOException {
		
		ServerSocket server = new ServerSocket(6666);
		Socket socket = server.accept();
		
		//通过Socket提供过的输入流接收来自客户端的数据,并写入到本地文件中
		InputStream is = socket.getInputStream();
		FileOutputStream fos = new FileOutputStream("copy.mp4");
		
		byte[] b = new byte[1024];
		int len;
		while ((len = is.read(b)) != -1) {
			fos.write(b, 0, len);
		}
		
		is.close();
		fos.close();
		socket.close();
		server.close();
	}
}

2.TCP协议 之 一对一聊天

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;

public class Client {

	public static void main(String[] args) throws UnknownHostException, IOException {
		
		Socket socket = new Socket("127.0.0.001", 5555);
		
		Scanner scan = new Scanner(System.in);
		
		PrintStream ps = new PrintStream(socket.getOutputStream());
		BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream(),"GBK"));
		
		while (true) {
			
			ps.println("小小:" + scan.next());
			
			String readLine = br.readLine();
			System.out.println(readLine);
		}
		
	}
}

3.TCP协议 之 优化一对一聊天

import java.io.IOException;
import java.io.PrintStream;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;

public class Client {

	public static void main(String[] args) throws UnknownHostException, IOException {
		
		Socket socket = new Socket("127.0.0.1",5010);
		
		new ReceiveThread(socket).start();
		
		Scanner scan = new Scanner(System.in);
		PrintStream ps = new PrintStream(socket.getOutputStream());
		
		while (true) {
			ps.println("刘备:" + scan.next());
		}
	}
}
import java.io.IOException;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;

public class Server {

	public static void main(String[] args) throws IOException {
		
		ServerSocket server = new ServerSocket(5010);
		
		Socket socket = server.accept();
		
		new ReceiveThread(socket).start();
		
		Scanner scan = new Scanner(System.in);
		PrintStream ps = new PrintStream(socket.getOutputStream());
		
		while (true) {
			ps.println("张飞:" + scan.next());
		}
	}
}
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;

public class ReceiveThread extends Thread{

	private Socket socket;

	public ReceiveThread(Socket socket) {
		this.socket = socket;
	}
	
	@Override
	public void run() {
		try {
			BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream(), "GBK"));
			while (true) {
				String readLine = br.readLine();
				System.out.println(readLine);
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}

4.TCP协议 之 群聊

import java.io.IOException;
import java.io.PrintStream;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;

public class Client {

	public static void main(String[] args) throws UnknownHostException, IOException {
		
		Socket socket = new Socket("127.0.0.1", 4563);
		
		new ReceiveThread(socket).start();
		
		Scanner scan = new Scanner(System.in);
		PrintStream ps = new PrintStream(socket.getOutputStream());
		while (true) {
			ps.println("关羽:" + scan.next());
		}
	}
}

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ConcurrentHashMap;

public class Server {

	public static final ConcurrentHashMap<String, Socket> map = new ConcurrentHashMap<>();
	
	public static void main(String[] args) throws IOException {
		
		ServerSocket server = new ServerSocket(4563);
		
		while (true) {
			
			Socket socket = server.accept();
			
			//获取客户端的IP地址
			String ip = socket.getInetAddress().toString();
			System.out.println(ip);
			
			//将IP地址和Socket对象存入Map中
			map.put(ip,socket);
			
			//此线程 -- 接收当前Socket的消息,并发送给其他Socket
			 new ServerThread(socket).start();
		}
	}
}

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;

public class ReceiveThread extends Thread{

	private  Socket socket;

	public ReceiveThread(Socket socket) {
		this.socket = socket;
	}
	
	@Override
	public void run() {

		try {
			BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream(),"GBK"));
			while (true) {
				String readLine = br.readLine();
				System.out.println(readLine);
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.io.UnsupportedEncodingException;
import java.net.Socket;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

public class ServerThread extends Thread{

	private Socket socket;

	public ServerThread(Socket socket) {
		this.socket = socket;
	}
	
	@Override
	public void run() {
		//接收当前Socket的消息,并发送给其他Socket
		try {
			BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream(),"GBK"));
			
			while (true) {
				String readLine = br.readLine();
				System.out.println(readLine);
				
				ConcurrentHashMap<String, Socket> map = Server.map;
				Set<Entry<String,Socket>> entrySet = map.entrySet();
				for (Entry<String, Socket> entry : entrySet) {
					String ip = entry.getKey();
					Socket value = entry.getValue();
					
					if (!socket.getInetAddress().toString().equals(ip)) {
						PrintStream ps = new PrintStream(value.getOutputStream());
						ps.println(readLine);
					}
				}
			}
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		
	}
}

四、UDP协议

1.简介

UDP(User Datagram Protocol)用户数据报包协议,UDP和TCP位于同一层-传输层,但它对于数据包的顺序错误或重发没有TCP可靠;UDP是一种面向无连接的通信协议。UDP向应用程序提供一种发送封装的原始IP数据报的方法,并且发送时无需建立连接,不保证可靠数据的传输

UDP — 发短信

TCP — 打电话

import java.net.DatagramSocket;
import java.net.SocketException;

public class Client01 {

	public static void main(String[] args) throws SocketException {
		
		DatagramSocket socket = new DatagramSocket(8808);
		
		new ReceiveThread(socket).start();
		
		new SendThread(socket, "127.0.0.1", 9099, "马超").start();
		
	}
}

import java.net.DatagramSocket;
import java.net.SocketException;

public class Client02 {

	public static void main(String[] args) throws SocketException {
		
		DatagramSocket socket = new DatagramSocket(9099);
		
		new ReceiveThread(socket).start();
		new SendThread(socket, "127.0.0.1", 8808, "吕布").start();
	}
}

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;

public class ReceiveThread extends Thread{

	private DatagramSocket socket;

	public ReceiveThread(DatagramSocket socket) {
		this.socket = socket;
	}
	
	@Override
	public void run() {

		while (true) {
		
			try {
				//数据容器
				byte[] buf = new byte[1024];
				//数据报包
				DatagramPacket dp = new DatagramPacket(buf, 0, buf.length);
				//接收数据报包
				socket.receive(dp);
				//打印
				System.out.println(new String(buf).trim());
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
}

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.UnknownHostException;
import java.util.Scanner;

public class SendThread extends Thread{

	private DatagramSocket socket;
    private String ip;
    private int port;
    private String name;
    
    public SendThread(DatagramSocket socket, String ip, int port, String name) {
		this.socket = socket;
		this.ip = ip;
		this.port = port;
		this.name = name;
	}

	@Override
    public void run() {
		
		Scanner scan = new Scanner(System.in);
		
		while (true) {
			
			try {
				//数据
				byte[] buf = (name + ":" + scan.next()).getBytes();
				//数据报包
				DatagramPacket dp = new DatagramPacket(buf, 0, buf.length);
				//发送数据报包
				socket.send(dp);
			} catch (UnknownHostException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
    }
}

2.TCP VS UDP

TCPUDP
是否连接面向连接无面向连接
传输可靠性可靠不可靠
应用场合传输大量数据少量数据
速度

五、Http协议

1.Http案例之获取来电归属地

import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;

import javax.net.ssl.HttpsURLConnection;

public class Test01 {

	public static void main(String[] args) throws IOException {
		
		//获取链接地址
		URL url = new URL("https://cx.shouji.360.cn/phonearea.php?number=15879090133");
		//获取连接对象
		HttpsURLConnection huc = (HttpsURLConnection) url.openConnection();
		
		//设置参数
		//设置请求方式
		huc.setRequestMethod("GET");
		//允许使用输入流
		huc.setDoInput(true);
		//允许使用输出流
		huc.setDoOutput(true);
		//设置连接超时时间
		huc.setConnectTimeout(5000);
		//设置读取超时时间
		huc.setReadTimeout(5200);
		
		//获取响应状态码
		int responseCode = huc.getResponseCode();
		
		if (responseCode == HttpsURLConnection.HTTP_OK) {//响应成功
			
			InputStreamReader isr = new InputStreamReader(huc.getInputStream(), "UTF-8");
			char[] c = new char[1024];
			int len;
			while ((len = isr.read(c)) != -1) {
				System.out.println(new String(c, 0, len));
			}
			isr.close();
		}else if(responseCode == HttpsURLConnection.HTTP_NOT_FOUND){
			System.out.println("报错了 --- 页面未找到");
		}
	}
}


2.Http案例之获取快递

import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;

import javax.net.ssl.HttpsURLConnection;

public class test02 {

	public static void main(String[] args) throws IOException {
		
		//获取地址
		URL url = new URL("https://www.kuaidi100.com/?type=zhongtong&postid=78624759493002");
		
		//获取连接对象
		HttpsURLConnection huc = (HttpsURLConnection) url.openConnection();
		
		//设置参数
		//设置请求方式
		huc.setRequestMethod("GET");
		//允许使用输入流
		huc.setDoInput(true);
		//允许使用输出流
		huc.setDoOutput(true);
		//设置连接超时时间
		huc.setConnectTimeout(5200);
		//设置读取超时时间
		huc.setReadTimeout(5000);
		
		//获取响应状态码
		int responseCode = huc.getResponseCode();
		
		if (responseCode == HttpsURLConnection.HTTP_OK) {//响应成功
			
			InputStreamReader isr = new InputStreamReader(huc.getInputStream(),"UTF-8");
			
			char[] c = new char[1024];
			int len;
			while ((len = isr.read(c)) != -1) {
				System.out.println(new String(c, 0, len));
			}
			isr.close();
		} else if(responseCode == HttpsURLConnection.HTTP_NOT_FOUND){
			System.out.println("报错了 --- 页面未找到");
		}
	}
}

3.Http案例之下载图片

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;

import javax.net.ssl.HttpsURLConnection;

public class Test03 {

	public static void main(String[] args) throws IOException {
		
		//获取连接地址
		URL url = new URL("https://ts1.cn.mm.bing.net/th/id/R-C.f27d775447d9f4ab7c71bbe5f8e38831?rik=4ISLL%2fsQWoSY8g&riu=http%3a%2f%2fimg95.699pic.com%2fphoto%2f40014%2f9369.jpg_wh860.jpg&ehk=S%2bDyu%2bhUKhk%2foLxQ6D7fO350Z%2fkmlDrRz5sM5J1QrCk%3d&risl=&pid=ImgRaw&r=0");
		
		//获取连接对象
		HttpsURLConnection huc = (HttpsURLConnection) url.openConnection();
		
		//设置参数
		//设置请求方式
		huc.setRequestMethod("GET");
		//允许使用输入流
		huc.setDoInput(true);
		//允许使用输出流
		huc.setDoOutput(true);
		//设置连接超时时间
		huc.setConnectTimeout(5200);
		//设置读取超时时间
		huc.setReadTimeout(5000);
		
		
		//获取响应状态码
		int responseCode = huc.getResponseCode();
		
		if (responseCode == HttpsURLConnection.HTTP_OK) {
			
			InputStream is = huc.getInputStream();
			FileOutputStream fos = new FileOutputStream("冲击的力量.jpg");
			
			byte[] b = new byte[1024];
			int len;
			while ((len = is.read(b)) != -1) {
				fos.write(b, 0, len);
			}
			is.close();
			fos.close();
		}else if (responseCode == HttpsURLConnection.HTTP_NOT_FOUND) {
			System.out.println("报错了 --- 页面未找到");
		}
		
	}
}

  • 8
    点赞
  • 56
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论
### 回答1: 要实现一个基于TCPUDP的多线程聊天室,可以采取以下步骤: 1. 首先,选择一个合适的端口号作为服务器的监听端口,并在服务器上创建一个套接字对象。服务器通过监听这个端口,等待客户端的连接请求。 2. 当有客户端连接上来后,服务器通过接受客户端的连接请求,建立与客户端的TCP连接。可以为每个连接的客户端都开辟一个新的线程,以便并发处理多个客户端的请求。 3. 客户端可以使用TCP连接来发送与接收消息。当客户端发送消息时,服务器将接收到的消息广播给所有连接到服务器的客户端,从而实现群聊的功能。 4. 除了TCP连接外,还可以使用UDP协议实现一对一的消息发送。在客户端和服务器上都创建一个UDP套接字对象。当客户端想要发送私密消息给其他特定客户端时,可以使用UDP连接来发送该消息。 5. 为了处理多个客户端的请求和消息,可以使用多线程来实现并发处理。每个连接的客户端都分配一个线程来处理其请求和消息。 6. 在服务器上,可以用一个线程专门来监听键盘输入,以接收服务器端的命令。例如,可以通过输入"exit"命令来关闭服务器。 综上所述,通过使用TCPUDP协议,以及多线程来处理连接和消息,可以实现一个基于多线程的聊天室。这个聊天室可以支持群聊和私密聊天,并且能够处理多个客户端的并发请求和消息。 ### 回答2: TCPUDP是两种不同的传输协议,用于实现聊天室可以选择使用其中一种或两者结合。 使用TCP实现聊天室可以确保数据的可靠性。TCP是面向连接的协议,通过三次握手建立连接,然后可以通过发送和接收数据来进行通信。在聊天室中,服务器可以使用多线程来处理多个客户端的连接请求。每当有新的客户端连接时,服务器创建一个新的线程来处理该连接,通过这些线程可以实现与多个客户端的通信。服务器将接收到的消息广播给所有在线的客户端,从而实现群聊功能。在TCP中,由于数据的可靠性,消息可能会有一定的延迟,但不会丢失。 而使用UDP实现聊天室则更适用于实时性要求较高的聊天应用。UDP是无连接的协议,发送端将数据报发送给目的地址,接收端从应用层接收数据报。对于聊天室,服务器和所有客户端可以使用不同的端口号,通过UDP发送和接收消息。在这种情况下,服务器仅需要一个线程来监听客户端发送的消息,并将消息广播给所有在线客户端。由于UDP是无连接的,消息可能丢失,因此在设计时,可以使用一些技术来提高数据的可靠性,例如使用ACK确认机制来确保消息的可靠传输。 无论是使用TCP还是UDP,多线程实现聊天室都具有一定的优势和限制。TCP能够提供可靠的传输,保证消息不会丢失,但可能会有一定的延迟。而UDP则可以提供更快的实时性,但消息可能会丢失。根据实际需求,可以选择适合的传输协议和多线程方案来实现聊天室。 ### 回答3: TCPUDP是互联网协议中两种不同的传输协议TCP是面向连接的,可靠的,有序的传输协议,适用于需要保证数据可靠性的应用场景,如文件传输和网页浏览。UDP是面向无连接的,不可靠的传输协议,适用于实时性要求较高的应用场景,如语音通话和视频直播。 而多线程是一种并发编程的方式,它可以让程序同时运行多个线程,实现并行处理,提高程序的执行效率。 实现聊天室可以结合使用TCP和多线程。利用TCP协议可以保证消息的可靠性和有序性,而多线程可以实现同时处理多个客户端请求。 具体实现步骤如下: 1. 服务器为每个客户端建立一个线程,监听客户端连接请求。 2. 客户端连接到服务器时,服务器启动一个新线程处理该客户端的请求。 3. 服务器接收客户端发送的消息并转发给其他在线的客户端。 4. 客户端接收到服务器发送的消息后,显示在聊天室界面上。 5. 客户端可以发送文本消息、图片、文件等,服务器接收并处理。 6. 客户端可以私聊,即选择某个在线的用户发送消息。 7. 当客户端断开连接时,服务器关闭相应的线程,保证资源的释放。 通过TCP协议保证了消息的可靠性和连接的稳定性,而多线程实现了并行处理,提高了聊天室的并发性能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

雨霖先森

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值