UNIX Day12

1 基于TCP协议的客户机与服务器
2 基于UDP协议的客户机与服务器
1 基于TCP协议的客户机与服务器
1.1 问题
一个完整TCP通信过程需要依次经历三个阶段:

首先,客户机必须建立与服务器的连接,所谓虚电路。

然后,凭借已建立好的连接,通信双方相互交换数据。

最后,客户机与服务器双双终止连接,结束通信过程。

1.2 步骤
实现此案例需要按照如下步骤进行。

步骤一:服务器

代码如下所示:

#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
int main()
{
int listenfd = socket (AF_INET, SOCK_STREAM, 0);
if (listenfd == -1)
{
perror (“socket”);
exit (EXIT_FAILURE);
}
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons (8888);
addr.sin_addr.s_addr = INADDR_ANY;
if (bind (listenfd, (struct sockaddr*)&addr, sizeof (addr)) == -1)
{
perror (“bind”);
exit (EXIT_FAILURE);
}
if (listen (listenfd, 1024) == -1)
{
perror (“listen”);
exit (EXIT_FAILURE);
}
struct sockaddr_in addrcli = {};
socklen_t addrlen = sizeof (addrcli);
int connfd = accept (listenfd, (struct sockaddr*)&addrcli, &addrlen);
if (connfd == -1)
{
perror (“accept”);
exit (EXIT_FAILURE);
}
printf (“服务器已接受来自%s:%hu客户机的连接请求\n”, inet_ntoa (addrcli.sin_addr),ntohs (addrcli.sin_port));
char buf[1024];
ssize_t rcvd = recv (connfd, buf, sizeof (buf), 0);
if (rcvd == -1)
{
perror (“recv”);
exit (EXIT_FAILURE);
}
if (rcvd == 0)
{
printf (“客户机已关闭连接\n”);
exit (EXIT_FAILURE);
}
buf[rcvd] = ‘\0’;
printf (“客户端说:%s\n”, buf);
printf (“服务器说:”);
gets (buf);
ssize_t sent = send (connfd, buf, strlen (buf) * sizeof (buf[0]), 0);
if (sent == -1)
{
perror (“send”);
exit (EXIT_FAILURE);
}
if (close (listenfd) == -1)
{
perror (“close”);
exit (EXIT_FAILURE);
}
if (close (connfd) == -1)
{
perror (“close”);
exit (EXIT_FAILURE);
}
return 0;
}
上述代码中,以下代码:

int listenfd = socket (AF_INET, SOCK_STREAM, 0);
if (listenfd == -1)
{
perror (“socket”);
exit (EXIT_FAILURE);
}
使用函数socket创建套接字。

上述代码中,以下代码:

struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons (8888);
addr.sin_addr.s_addr = INADDR_ANY;
准备地址结构,使用sockaddr_in结构体类型。

上述代码中,以下代码:

if (bind (listenfd, (struct sockaddr*)&addr, sizeof (addr)) == -1)
{
perror (“bind”);
exit (EXIT_FAILURE);
}
使用函数bind将套接字对象和自己的地址结构绑定在一起。

上述代码中,以下代码:

if (listen (listenfd, 1024) == -1)
{
perror (“listen”);
exit (EXIT_FAILURE);
}
使用函数listen在指定套接字上启动对连接请求的侦听。该函数有两个参数,说明如下:

第一个参数为套接字描述符。

第二个参数为连接请求的最大值。

上述代码中,以下代码:

struct sockaddr_in addrcli = {};
socklen_t addrlen = sizeof (addrcli);
int connfd = accept (listenfd, (struct sockaddr*)&addrcli, &addrlen);
if (connfd == -1)
{
perror (“accept”);
exit (EXIT_FAILURE);
}
printf (“服务器已接受来自%s:%hu客户机的连接请求\n”, inet_ntoa (addrcli.sin_addr),ntohs (addrcli.sin_port));
使用函数accept在指定套接字上等待并接受连接请求。该函数有三个参数,说明如下:

第一个参数为套接字描述符。

第二个参数为输出连接请求发起者地址结构。

第三个参数为输入/输出,连接请求发起者地址结构长度(以字节为单位)。

上述代码中,以下代码:

char buf[1024];
ssize_t rcvd = recv (connfd, buf, sizeof (buf), 0);
if (rcvd == -1)
{
perror (“recv”);
exit (EXIT_FAILURE);
}
if (rcvd == 0)
{
printf (“客户机已关闭连接\n”);
exit (EXIT_FAILURE);
}
buf[rcvd] = ‘\0’;
printf (“客户端说:%s\n”, buf);
使用函数recv通过指定套接字接收数据,该函数有四个参数,说明如下:

第一个参数为套接字描述符。

第二个参数为应用程序接收缓冲区。

第三个参数为期望接收的字节数。

第四个参数为接收标志,一般取0,还可取以下值:

MSG_DONTWAIT - 以非阻塞方式接受数据。

MSG_OOB - 接收带外数据。

MSG_PEEK - 只查看可接收的数据,函数返回后数据依然留在接收缓冲区中。

MSG_WAITALL - 等待所有数据,即不接收到len字节的数据,函数就不返回。

上述代码中,以下代码:

printf ("服务器说:");
gets (buf);
ssize_t sent = send (connfd, buf, strlen (buf) * sizeof (buf[0]), 0);

if (sent == -1)
{
perror (“send”);
exit (EXIT_FAILURE);
}
使用函数send通过指定套接字发送数据,该函数有四个参数,说明如下:

第一个参数为套接字描述符。

第二个参数为应用程序发送缓冲区。

第三个参数为期望发送的字节数。

第四个参数为接收标志,一般取0,还可取以下值:

MSG_DONTWAIT - 以非阻塞方式发送数据。

MSG_OOB - 发送带外数据。

MSG_DONTROUTE - 不查路由表,直接在本地网络中寻找目的主机

上述代码中,以下代码:

if (close (listenfd) == -1)
{
perror (“close”);
exit (EXIT_FAILURE);
}
if (close (connfd) == -1)
{
perror (“close”);
exit (EXIT_FAILURE);
}
使用函数close关闭处于打开状态的套接字描述符,该函数的参数为处于打开状态的套接字描述符。

步骤二:客户端

代码如下所示:

#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
int main()
{
int listenfd = socket (AF_INET, SOCK_STREAM, 0);
if (listenfd == -1)
{
perror (“socket”);
exit (EXIT_FAILURE);
}
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons (8888);
addr.sin_addr.s_addr = inet_addr(“127.0.0.1”);
if (connect (listenfd, (struct sockaddr*)&addr, sizeof (addr)) == -1)
{
perror (“connect”);
exit (EXIT_FAILURE);
}
char buf[1024] = “你好,服务器”;
printf (“客户端说:%s\n”, buf);
ssize_t sent = send (listenfd, buf, strlen (buf) * sizeof (buf[0]), 0);
if (sent == -1)
{
perror (“send”);
exit (EXIT_FAILURE);
}
ssize_t rcvd = recv (listenfd, buf, sizeof (buf), 0);
if (rcvd == -1)
{
perror (“recv”);
exit (EXIT_FAILURE);
}
buf[rcvd] = ‘\0’;
printf (“服务器说:%s\n”, buf);
if (close (listenfd) == -1)
{
perror (“close”);
exit (EXIT_FAILURE);
}
return 0;
}
上述代码中,以下代码:

int listenfd = socket (AF_INET, SOCK_STREAM, 0);
if (listenfd == -1)
{
perror (“socket”);
exit (EXIT_FAILURE);
}
使用函数socket创建套接字。

上述代码中,以下代码:

struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons (8888);
addr.sin_addr.s_addr = inet_addr(“127.0.0.1”);
准备地址结构,使用sockaddr_in结构体类型。

上述代码中,以下代码:

if (connect (listenfd, (struct sockaddr*)&addr, sizeof (addr)) == -1)
{
perror (“connect”);
exit (EXIT_FAILURE);
}
使用函数connect将套接字对象和对方的地址结构连接在一起。

上述代码中,以下代码:

char buf[1024] = “你好,服务器”;
printf (“客户端说:%s\n”, buf);
ssize_t sent = send (listenfd, buf, strlen (buf) * sizeof (buf[0]), 0);
if (sent == -1)
{
perror (“send”);
exit (EXIT_FAILURE);
}
使用函数send通过指定套接字发送数据。

上述代码中,以下代码:

ssize_t rcvd = recv (listenfd, buf, sizeof (buf), 0);

if (rcvd == -1)
{
perror (“recv”);
exit (EXIT_FAILURE);
}
buf[rcvd] = ‘\0’;
printf (“服务器说:%s\n”, buf);
使用函数recv通过指定套接字接收数据。

上述代码中,以下代码:

if (close (listenfd) == -1)
{
perror (“close”);
exit (EXIT_FAILURE);
}
使用函数close关闭处于打开状态的套接字描述符,该函数的参数为处于打开状态的套接字描述符。

1.3 完整代码
本案例的完整代码如下所示:

服务器,代码如下所示:

#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
int main()
{
int listenfd = socket (AF_INET, SOCK_STREAM, 0);
if (listenfd == -1)
{
perror (“socket”);
exit (EXIT_FAILURE);
}
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons (8888);
addr.sin_addr.s_addr = INADDR_ANY;
if (bind (listenfd, (struct sockaddr*)&addr, sizeof (addr)) == -1)
{
perror (“bind”);
exit (EXIT_FAILURE);
}
if (listen (listenfd, 1024) == -1)
{
perror (“listen”);
exit (EXIT_FAILURE);
}
struct sockaddr_in addrcli = {};
socklen_t addrlen = sizeof (addrcli);
int connfd = accept (listenfd, (struct sockaddr*)&addrcli, &addrlen);
if (connfd == -1)
{
perror (“accept”);
exit (EXIT_FAILURE);
}
printf (“服务器已接受来自%s:%hu客户机的连接请求\n”, inet_ntoa (addrcli.sin_addr),ntohs (addrcli.sin_port));
char buf[1024];
ssize_t rcvd = recv (connfd, buf, sizeof (buf), 0);
if (rcvd == -1)
{
perror (“recv”);
exit (EXIT_FAILURE);
}
if (rcvd == 0)
{
printf (“客户机已关闭连接\n”);
exit (EXIT_FAILURE);
}
buf[rcvd] = ‘\0’;
printf (“客户端说:%s\n”, buf);
printf (“服务器说:”);
gets (buf);
ssize_t sent = send (connfd, buf, strlen (buf) * sizeof (buf[0]), 0);
if (sent == -1)
{
perror (“send”);
exit (EXIT_FAILURE);
}
if (close (listenfd) == -1)
{
perror (“close”);
exit (EXIT_FAILURE);
}
if (close (connfd) == -1)
{
perror (“close”);
exit (EXIT_FAILURE);
}
return 0;
}
客户端,代码如下所示:

#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
int main()
{
int listenfd = socket (AF_INET, SOCK_STREAM, 0);
if (listenfd == -1)
{
perror (“socket”);
exit (EXIT_FAILURE);
}
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons (8888);
addr.sin_addr.s_addr = inet_addr(“127.0.0.1”);
if (connect (listenfd, (struct sockaddr*)&addr, sizeof (addr)) == -1)
{
perror (“connect”);
exit (EXIT_FAILURE);
}
char buf[1024] = “你好,服务器”;
printf (“客户端说:%s\n”, buf);
ssize_t sent = send (listenfd, buf, strlen (buf) * sizeof (buf[0]), 0);
if (sent == -1)
{
perror (“send”);
exit (EXIT_FAILURE);
}
ssize_t rcvd = recv (listenfd, buf, sizeof (buf), 0);
if (rcvd == -1)
{
perror (“recv”);
exit (EXIT_FAILURE);
}
buf[rcvd] = ‘\0’;
printf (“服务器说:%s\n”, buf);
if (close (listenfd) == -1)
{
perror (“close”);
exit (EXIT_FAILURE);
}
return 0;
}
2 基于UDP协议的客户机与服务器
2.1 问题
UDP不提供客户机与服务器的连接。UDP的客户机与服务器不必存在长期关系。一个UDP的客户机在通过一个套接字向一个UDP服务器发送了一个数据报之后,马上可以通过同一个套接字向另一个UDP服务器发送另一个数据报。同样,一个UDP服务器也可以通过同一个套接字接收来自不同客户机的数据报

UDP不保证数据传输的可靠性和有序性。UDP的协议栈底层不提供诸如确认、超时重传、RTT估算以及序列号等机制。因此UDP数据报在网络传输的过程中,可能丢失,也可能重复,甚至重新排序。应用程序必须自己处理这些情况

2.2 步骤
实现此案例需要按照如下步骤进行。

步骤一:服务器

代码如下所示:

#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
int main()
{
int listenfd = socket (AF_INET, SOCK_DGRAM, 0);
if (listenfd == -1)
{
perror (“socket”);
exit (EXIT_FAILURE);
}
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons (8888);
addr.sin_addr.s_addr = INADDR_ANY;
if (bind (listenfd, (struct sockaddr*)&addr, sizeof (addr)) == -1)
{
perror (“bind”);
exit (EXIT_FAILURE);
}
char buf[1024];
struct sockaddr_in addrcli = {};
socklen_t addrlen = sizeof (addrcli);
ssize_t rcvd = recvfrom (listenfd, buf, sizeof (buf), 0, (struct sockaddr*)&addrcli, &addrlen);
if (rcvd == -1)
{
perror (“recvfrom”);
exit (EXIT_FAILURE);
}
buf[rcvd] = ‘\0’;
printf (“客户端说:%s\n”, buf);
printf (“服务器说:”);
gets (buf);
ssize_t sent = sendto (listenfd, buf, strlen (buf) * sizeof (buf[0]), 0, (struct sockaddr*)&addrcli, sizeof (addrcli));
if (sent == -1)
{
perror (“send”);
exit (EXIT_FAILURE);
}
if (close (listenfd) == -1)
{
perror (“close”);
exit (EXIT_FAILURE);
}
return 0;
}
上述代码中,以下代码:

int listenfd = socket (AF_INET, SOCK_DGRAM, 0);
if (listenfd == -1)
{
perror (“socket”);
exit (EXIT_FAILURE);
}
使用函数socket创建套接字。

上述代码中,以下代码:

struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons (8888);
addr.sin_addr.s_addr = INADDR_ANY;
准备地址结构,使用sockaddr_in结构体类型。

上述代码中,以下代码:

if (bind (listenfd, (struct sockaddr*)&addr, sizeof (addr)) == -1)
{
perror (“bind”);
exit (EXIT_FAILURE);
}
使用函数bind将套接字对象和自己的地址结构绑定在一起。

上述代码中,以下代码:

char buf[1024];
struct sockaddr_in addrcli = {};
socklen_t addrlen = sizeof (addrcli);
ssize_t rcvd = recvfrom (listenfd, buf, sizeof (buf), 0, (struct sockaddr*)&addrcli, &addrlen);
if (rcvd == -1)
{
perror (“recvfrom”);
exit (EXIT_FAILURE);
}
buf[rcvd] = ‘\0’;
printf (“客户端说:%s\n”, buf);
使用函数recvfrom从指定的地址结构接收数据,该函数有六个参数,说明如下:

第一个参数为套接字描述符。

第二个参数为应用程序接收缓冲区。

第三个参数为期望接收的字节数。

第四个参数为接收标志,一般取0,还可取以下值:

MSG_DONTWAIT - 以非阻塞方式接受数据。

MSG_OOB - 接收带外数据。

MSG_PEEK - 只查看可接收的数据,函数返回后数据依然留在接收缓冲区中。

MSG_WAITALL - 等待所有数据,即不接收到len字节的数据,函数就不返回。

第五个参数为输出数据报发送者的地址结构,可置NULL。

第六个参数为输入src_addr参数所指向内存块的字节数,输出数据报发送者地址结构的字节数,可置NULL。

上述代码中,以下代码:

printf ("服务器说:");
gets (buf);
ssize_t sent = sendto (listenfd, buf, strlen (buf) * sizeof (buf[0]), 0, (struct sockaddr*)&addrcli, sizeof (addrcli));

if (sent == -1)
{
perror (“send”);
exit (EXIT_FAILURE);
}
使用函数sendto从指定的地址结构发送数据,该函数有六个参数,说明如下:

第一个参数为套接字描述符。

第二个参数为应用程序发送缓冲区。

第三个参数为期望发送的字节数。

第四个参数为发送标志,一般取0,还可取以下值:

MSG_DONTWAIT - 以非阻塞方式接受数据。

MSG_OOB - 接收带外数据。

MSG_DONTROUTE - 不查路由表,直接在本地网络中寻找目的主机

第五个参数为数据报接收者的地址结构。

第六个参数为数据报接收者地址结构的字节数。

上述代码中,以下代码:

if (close (listenfd) == -1)
{
perror (“close”);
exit (EXIT_FAILURE);
}
使用函数close关闭处于打开状态的套接字描述符,该函数的参数为处于打开状态的套接字描述符。

步骤二:客户端

代码如下所示:

#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
int main()
{
int listenfd = socket (AF_INET, SOCK_DGRAM, 0);
if (listenfd == -1)
{
perror (“socket”);
exit (EXIT_FAILURE);
}
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons (8888);
addr.sin_addr.s_addr = inet_addr(“127.0.0.1”);
char buf[1024] = “你好,服务器”;
printf (“客户端说:%s\n”, buf);
ssize_t sent = sendto (listenfd, buf, strlen (buf) * sizeof (buf[0]), 0, (struct sockaddr*)&addr, sizeof (addr));
if (sent == -1)
{
perror (“send”);
exit (EXIT_FAILURE);
}
struct sockaddr_in addrser = {};
socklen_t addrlen = sizeof (addrser);
ssize_t rcvd = recvfrom (listenfd, buf, sizeof (buf), 0, (struct sockaddr*)&addrser, &addrlen);
if (rcvd == -1)
{
perror (“recvfrom”);
exit (EXIT_FAILURE);
}
buf[rcvd] = ‘\0’;
printf (“服务器说:%s\n”, buf);
if (close (listenfd) == -1)
{
perror (“close”);
exit (EXIT_FAILURE);
}
return 0;
}
上述代码中,以下代码:

int listenfd = socket (AF_INET, SOCK_DGRAM, 0);
if (listenfd == -1)
{
perror (“socket”);
exit (EXIT_FAILURE);
}
使用函数socket创建套接字。

上述代码中,以下代码:

struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons (8888);
addr.sin_addr.s_addr = inet_addr(“127.0.0.1”);
准备地址结构,使用sockaddr_in结构体类型。

上述代码中,以下代码:

char buf[1024] = “你好,服务器”;
printf (“客户端说:%s\n”, buf);
ssize_t sent = sendto (listenfd, buf, strlen (buf) * sizeof (buf[0]), 0, (struct sockaddr*)&addr, sizeof (addr));
if (sent == -1)
{
perror (“send”);
exit (EXIT_FAILURE);
}
使用函数sendto从指定的地址结构发送数据。

上述代码中,以下代码:

struct sockaddr_in addrser = {};
socklen_t addrlen = sizeof (addrser);
ssize_t rcvd = recvfrom (listenfd, buf, sizeof (buf), 0, (struct sockaddr*)&addrser, &addrlen);
if (rcvd == -1)
{
perror (“recvfrom”);
exit (EXIT_FAILURE);
}
buf[rcvd] = ‘\0’;
printf (“服务器说:%s\n”, buf);
使用函数recvfrom从指定的地址结构接收数据。

上述代码中,以下代码:

if (close (listenfd) == -1)
{
perror (“close”);
exit (EXIT_FAILURE);
}
使用函数close关闭处于打开状态的套接字描述符,该函数的参数为处于打开状态的套接字描述符。

2.3 完整代码
本案例的完整代码如下所示:

服务器,代码如下所示:

#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
int main()
{
int listenfd = socket (AF_INET, SOCK_DGRAM, 0);
if (listenfd == -1)
{
perror (“socket”);
exit (EXIT_FAILURE);
}
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons (8888);
addr.sin_addr.s_addr = INADDR_ANY;
if (bind (listenfd, (struct sockaddr*)&addr, sizeof (addr)) == -1)
{
perror (“bind”);
exit (EXIT_FAILURE);
}
char buf[1024];
struct sockaddr_in addrcli = {};
socklen_t addrlen = sizeof (addrcli);
ssize_t rcvd = recvfrom (listenfd, buf, sizeof (buf), 0, (struct sockaddr*)&addrcli, &addrlen);
if (rcvd == -1)
{
perror (“recvfrom”);
exit (EXIT_FAILURE);
}
buf[rcvd] = ‘\0’;
printf (“客户端说:%s\n”, buf);
printf (“服务器说:”);
gets (buf);
ssize_t sent = sendto (listenfd, buf, strlen (buf) * sizeof (buf[0]), 0, (struct sockaddr*)&addrcli, sizeof (addrcli));
if (sent == -1)
{
perror (“send”);
exit (EXIT_FAILURE);
}
if (close (listenfd) == -1)
{
perror (“close”);
exit (EXIT_FAILURE);
}
return 0;
}
客户端,代码如下所示:

#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
int main()
{
int listenfd = socket (AF_INET, SOCK_DGRAM, 0);
if (listenfd == -1)
{
perror (“socket”);
exit (EXIT_FAILURE);
}
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons (8888);
addr.sin_addr.s_addr = inet_addr(“127.0.0.1”);
char buf[1024] = “你好,服务器”;
printf (“客户端说:%s\n”, buf);
ssize_t sent = sendto (listenfd, buf, strlen (buf) * sizeof (buf[0]), 0, (struct sockaddr*)&addr, sizeof (addr));
if (sent == -1)
{
perror (“send”);
exit (EXIT_FAILURE);
}
struct sockaddr_in addrser = {};
socklen_t addrlen = sizeof (addrser);
ssize_t rcvd = recvfrom (listenfd, buf, sizeof (buf), 0, (struct sockaddr*)&addrser, &addrlen);
if (rcvd == -1)
{
perror (“recvfrom”);
exit (EXIT_FAILURE);
}
buf[rcvd] = ‘\0’;
printf (“服务器说:%s\n”, buf);
if (close (listenfd) == -1)
{
perror (“close”);
exit (EXIT_FAILURE);
}
return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值