基于TCP协议简易聊天室(服务器端)

服务器端:

/*********************************************************

-  File name    :chat.c

*  ******************************************************/

 

#include "../../include/net.h"

 

int sayto_1(int sfd, Node *newnode)

{

    char buf[100];

 

    char *sql;

    char *errmsg;

 

    int nrow;

    int ncolumn;

    char **azresult;

 

    /* 接收name,检查是否在线 */

    memset(buf, 0, sizeof(buf));

    sprintf(buf,"select * from client_inform where name = '%s' or id = '%s';",newnode->toname, newnode->toname);

    sql = buf;

 

    if(SQLITE_OK != sqlite3_get_table(db, sql, &azresult, &nrow, &ncolumn, &errmsg))

    {

        perror("sqlite3_get_table error!\n");

        exit(0);

    }

 

    if(nrow == 0)        // 用户名不存在

    {

        newnode->ack = NOT_EXIT;

write(sfd, newnode, sizeof(Node));

return 0;

    }

    else if(nrow == 1)   // 用户名存在

    {

        Online *temp = head;

while(temp != NULL)

{

    if(temp->sfd == sfd)           // 遍历在线用户,找出发送用户状态

    {

        strcpy(newnode->name, temp->name);

        if(temp->speek_flag == 0)  // 当前用户被禁言

        {

            newnode->ack = No_say;

            write(sfd, newnode, sizeof(Node));

    return 0;

        }

    }

    temp = temp->next;

}

        

temp = head;                        // 当前用户没有被禁言

while(temp != NULL)

{

    if(strcmp(newnode->toname, temp->name) == 0)  // 遍历在线用户,找出toname sfd

    {

        newnode->ack = MSG_RECV_ONE;

                write(temp->sfd, newnode, sizeof(Node));

 

return 0;

    }

    temp = temp->next;

}

 

        /* 无其他在线用户 */

newnode->ack = No_online;

write(sfd, newnode, sizeof(Node));

    }

 

    return 0;

}

 

int sayall_1(int sfd, Node *newnode)

{

    Online *temp = head;

 

    while(temp != NULL)

    {

        if(temp->sfd == sfd)

{

    strcpy(newnode->name, temp->name);

    if(temp->speek_flag == 0)

    {

        newnode->ack = No_say;

write(sfd, newnode, sizeof(Node));

return 0;

    }

}

temp = temp->next;

    }

 

    temp = head;

 

    while(temp != NULL)

    {

        if(temp->sfd == sfd)

{

    temp = temp->next;

    continue;

}

        newnode->ack = MSG_RECV_ALL;

        write(temp->sfd, newnode, sizeof(Node));

temp = temp->next;

    }

 

    return 0;

}

 

int dis_1(int sfd, Node *newnode)

{

    Online *temp = head;

 

    while(temp != NULL)

    {

        if(temp->sfd == sfd)

{

    temp = temp->next;

    continue;

}

        newnode->ack = DIS_NAME;

memset(newnode->name, 0, sizeof(Node));

strcpy(newnode->name, temp->name);

        write(sfd, newnode, sizeof(Node));

 

temp = temp->next;

    }

 

    return 0;

}

 

int change_1(int sfd, Node *newnode)

{

    int nrow;

    int ncolumn;

    

    char buf[100];

 

    char *sql;

    char *errmsg;

    char **azresult;

 

    Online *temp = head;

 

    while(temp != NULL)

    {

        /* 根据sfd找出name */

        if(temp->sfd == sfd)      

{

    strcpy(newnode->name, temp->name);

    break;

}

temp = temp->next;

    }

 

    memset(buf, 0, sizeof(buf));

    sprintf(buf,"select * from client_inform where name = '%s' and password = '%s';", newnode->name, newnode->password);

    sql = buf;

 

    if(SQLITE_OK != sqlite3_get_table(db, sql, &azresult, &nrow, &ncolumn, &errmsg))

    {

        perror("sqlite3_get_table error!\n");

exit(0);

    }

 

    if(nrow == 0)

    {

        newnode->ack = PASSWD_ERR;

write(sfd, newnode, sizeof(Node));

    }

    else if(nrow == 1)

    {

        memset(buf, 0, sizeof(buf));

sprintf(buf,"UPDATE client_inform SET password = '%s' where password = '%s' and name = '%s';", newnode->msg, newnode->password, newnode->name);

sql = buf;

 

if(SQLITE_OK != sqlite3_get_table(db, sql, &azresult, &nrow, &ncolumn, &errmsg))

{

    perror("sqlite3_get_table error!\n");

    exit(0);

}

        newnode->ack = PASSWD_SUCCESS;

write(sfd, newnode, sizeof(Node));

    }

 

    return 0;

}

 

 

int send_1(int sfd, Node *newnode)

{

    char buf[100];

 

    char *sql;

    char *errmsg;

 

    int nrow;

    int ncolumn;

    char **azresult;

 

    Online *temp = head;

 

    while(temp != NULL)

    {

        /* 根据sfd找出name */

        if(temp->sfd == sfd)      

{

    strcpy(newnode->name, temp->name);

    break;

}

temp = temp->next;

    }

 

    /* 接受name,检查是否在线 */

    memset(buf, 0, sizeof(buf));

    sprintf(buf, "select * from client_inform where name = '%s' or id = '%s';", newnode->toname, newnode->toname);

    sql = buf;

 

    if(SQLITE_OK != sqlite3_get_table(db, sql, &azresult, &nrow, &ncolumn, &errmsg))

    {

        perror("sqlite3_get_table send error!\n");

exit(0);

    }

 

    if(nrow == 0)

    {

        newnode->ack = NOT_EXIT;

write(sfd, newnode, sizeof(Node));

return 0;

    }

    else if(nrow == 1)

    {

        temp = head;

 

while(temp != NULL)

{

    if(strcmp(newnode->toname, temp->name) == 0)

    {

        newnode->ack = RECV_FILE;

write(temp->sfd, newnode, sizeof(Node));

 

return 0;

    }

    temp = temp->next;

}

 

/* 无其他用户在线 */

newnode->ack = No_online;

write(sfd, newnode, sizeof(Node));

    }

 

    return 0;

}

 

 

/*********************************************************

-  File name    :creat_table.c

*  ******************************************************/

 

#include "../../include/net.h"

 

int creat_table(sqlite3 *db)

{

    char *sql;

    char *errmsg;

 

    sql = "create table if not exists client_inform(id varchar(10) primary key, name varchar(10), password varchar(10));";

 

    if(SQLITE_OK != sqlite3_exec(db, sql, NULL, NULL, &errmsg))

    {

        perror("sqlite3_exec error!\n");

exit(0);

    }

 

    return 0;

}

 

//int insert_record(sqlite3 *db)

//{

  //  char ch;

    //char *sql;

   // char *errmsg;

 

    

//}

 

/*********************************************************

-  File name    :get.c

*  ******************************************************/

 

#include "../../include/net.h"

 

void get_id(Node *newnode)

{

    int i = 0;

    int j = 10000000;

    long int id;

 

    char buf[10] = {0};

 

    srand(time(NULL));

 

    id = (rand() & 100000000);

    //printf("id = %ld\n",id);

 

    while(id != 0)

    {

        buf[i++] = id / j + '0';

id = id % j;

j = j / 10;

    }

    buf[i] = '\0';

    strcpy(newnode->id,buf);

    //printf("newnode->id = %s\n",newnode->id);

}

 

Net.h:

 

/*********************************************************

-  File name    :net.h

*  ******************************************************/

 

#ifndef NET_H_

#define NET_H_

 

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <sys/types.h>

#include <sys/socket.h>

#include <arpa/inet.h>

#include <unistd.h>

#include <signal.h>

#include <time.h>

#include <sqlite3.h>

#include <pthread.h>

 

struct node

{

    int ack;

    char id[9];

    char name[20];

    char password[10];

    char toname[20];

    char msg[1024];

    char file_name[100];

    char file_msg[1024];

};

 

typedef struct node Node;

 

struct online

{

    int sfd;

    int on_flag;

    int speek_flag;

    char name[20];

 

    struct online *next;

};

 

typedef struct online Online;

 

extern Online *head;

extern sqlite3 *db;

 

enum

{

    reg = 0,

    log,

    sayto,

    sayall,

    dis,

    change,

    send_file,

    stop_say,

    let_say,

    t_man,

    quit = 10,

    SUCCESS,

    FAILE,

    sup,

    EXIT,

    NOT_EXIT,

    PASSWD_ERR,

    SUCCESS_LOG,

    REG_NOT_EXIT,

    REG_EXIT,

    SUCCESS_REG = 20,

    No_say,

    Ok_say,

    MSG_RECV_ONE,

    MSG_RECV_ALL,

    DIS_NAME,

    PASSWD_SUCCESS,

    RECV_FILE,

    STOP_SAY_OK,

    NOT_STOP_SAY,

    LET_SAY_OK = 30,

    No_online,

    T_OK,

    YOU_OUT,

    QUIT_OK

};

 

void read_msg(void *arg);

 

int change_1(int sfd, Node *newnode);

 

int dis_1(int sfd, Node *newnode);

 

void get_id(Node *newnode);

 

int let_say_1(int sfd, Node *newnode);

 

int log_1(int sfd, Node *newnode);

 

int reg_1(int sfd, Node *newnode);

 

int sayto_1(int sfd, Node *newnode);

 

int sayall_1(int sfd, Node *newnode);

 

int creat_table(sqlite3 *db);

 

int stop_say_1(int sfd, Node *newnode);

 

int tcp_init();

 

int t_man_1(int sfd, Node *newnode);

 

int quit_1(int sfd, Node *newnode);

 

int err_quit(int sfd);

 

int tcp_init();

 

int tcp_accept(int sfd);

 

#endif

 

/*********************************************************

-  File name    :log_reg.c

*  ******************************************************/

 

#include "../../include/net.h"

 

int log_1(int sfd, Node *newnode)

{

    char buf[100];

    char *sql;

    char *errmsg;

 

    Online *linenode = (Online *) malloc (sizeof(Online));

    

    /* 检查用户名是否存在 */

    /* 超级用户 */

    if((strcmp(newnode->id, "admin") == 0) && (strcmp(newnode->password, "admin") == 0))

    {

        newnode->ack = sup;               // 发送ack = sup

printf("sup\n");

write(sfd, newnode, sizeof(Node));

return 0;

    }

 

    int i;

    int nrow;

    int ncolumn;

    char **azresult = NULL;

 

    memset(buf, 0, sizeof(buf));

    sprintf(buf,"select * from client_inform where id = '%s' or name = '%s'",newnode->id, newnode->id);

    sql = buf;

 

    if(SQLITE_OK != sqlite3_get_table(db, sql, &azresult, &nrow, &ncolumn, &errmsg))

    {

        perror("select id error!\n");

exit(0);

    }

 

    if(nrow == 0)   //用户名不存在

    {

        newnode->ack = NOT_EXIT;

write(sfd, newnode, sizeof(Node));

return 0;

    }

    else if(nrow == 1)  //用户名存在

    {

        /* 检查密码是否正确 */

        memset(buf, 0, sizeof(buf));

sprintf(buf,"select * from client_inform where password = '%s' and (id = '%s' or name = '%s');", newnode->password, newnode->id, newnode->id);

sql = buf;

if(SQLITE_OK != sqlite3_get_table(db, sql, &azresult, &nrow, &ncolumn, &errmsg))

{

    perror("seletc password error!\n");

    exit(0);

}

 

if(nrow == 0)   //密码不正确

{

    newnode->ack = PASSWD_ERR;

printf("perr\n");

    write(sfd, newnode, sizeof(Node));

    return 0;

}

else if(nrow == 1)   //密码正确

{

    Online *temp = head;

    while(temp != NULL)

    {

        if(strcmp(temp->name,newnode->id) == 0)

{

    if(temp->on_flag == 1)

    {

        newnode->ack = EXIT;                //用户已在线

printf("exit\n");

write(sfd, newnode, sizeof(Node));

return 0;

    }

}

temp = temp->next;

    }

 

    /* 登录信息正确,且用户不在线,保存在线信息 */

    newnode->ack = SUCCESS_LOG;                      // 发送登录成功ack

    write(sfd, newnode, sizeof(Node));

 

            linenode->sfd = sfd;                             // 网络套接口

    linenode->on_flag = 1;                           // 用户在线

    linenode->speek_flag = 1;                        // 用户未被禁言

 

            /* 若用户ID登录,改为昵称在线 */

            memset(buf, 0, sizeof(buf));

            sprintf(buf,"select * from client_inform where id = '%s';",newnode->id);

            sql = buf;

 

            if(SQLITE_OK != sqlite3_get_table(db, sql, &azresult, &nrow, &ncolumn, &errmsg))

            {

                perror("select id error!\n");

        exit(0);

            }

 

            if(nrow == 0)            // 用户名登录

    {

        strcpy(linenode->name, newnode->id);

    }

    else if(nrow == 1)       // ID登录

    {

        for(i = 0; i < (nrow + 1) * ncolumn; i++)

{

    if(strcmp(azresult[i],newnode->id) == 0)

    {

        strcpy(linenode->name,azresult[i + 1]);    // 用户在线昵称

break;

    }

}

    }

 

            /* 头插 */

    linenode->next = head;

    head = linenode;

}

    }

 

    return 0;

}

 

int reg_1(int sfd, Node *newnode)

{

    char buf[100];

 

    char *sql;

    char *errmsg;

 

    /* 创建用户信息表 */

    sql = "create table if not exists client_inform(id varchar(10),name varchar(10),password varchar(10));";

 

    if(SQLITE_OK != sqlite3_exec(db, sql, NULL, NULL, &errmsg))

    {

        perror("sqlite3_exec error!\n");

exit(0);

    }

    

    /* 检查name是否存在 */

    int nrow;

    int ncolumn;

    char **azresult = NULL;

 

    memset(buf, 0, sizeof(buf));

    sprintf(buf,"select * from client_inform where name = '%s';",newnode->name);

    sql = buf;

 

    if(SQLITE_OK != sqlite3_get_table(db, sql, &azresult, &nrow, &ncolumn, &errmsg))

    {

        perror("sqlite3_get_table error!\n");

exit(0);

    }

    

    /*

    if(nrow == 0)       //用户名不存在

    {

        newnode->ack = REG_NOT_EXIT;

        write(sfd, newnode, sizeof(Node));  //发送用户名不存在

    }

    */

    if(nrow == 1) //用户名存在

    {

        newnode->ack = REG_EXIT;

write(sfd, newnode, sizeof(Node));  //发送用户名存在

return 0;

    }

 

    /* 用户名不存在,保存用户信息 */

    get_id(newnode);                        // 生成ID

 

    memset(buf, 0, sizeof(buf));

    sprintf(buf,"insert into client_inform values('%s','%s','%s');",newnode->id, newnode->name, newnode->password);

    sql = buf;

    

    if(SQLITE_OK != sqlite3_exec(db, sql, NULL, NULL, &errmsg))

    {

        perror("insert error!\n");

exit(0);

    }

 

    /* 发送注册成功信息 */

    newnode->ack = SUCCESS_REG;

    write(sfd, newnode, sizeof(Node));

 

    return 0;

}

 

/*********************************************************

-  File name    :main.c

*  ******************************************************/

 

#include "../../include/net.h"

 

sqlite3 *db = NULL;

 

Online *head = NULL;

 

int main(int argc, char **argv)

{

    int rc;

    int sfd;

    int cfd;

 

    pthread_t id;

 

    sfd = tcp_init();

 

    if(SQLITE_OK != (rc = sqlite3_open("user.db",&db)))

    {

        perror("sqlite3_open error!\n");

exit(0);

    }

 

    while(1)

    {

        cfd = tcp_accept(sfd);

 

        pthread_create(&id, NULL, (void *)read_msg, (void *)&cfd);

    }   

 

    close(sfd);

 

    return 0;

}

 

/*********************************************************

-  File name    :quit_1.c

*  ******************************************************/

 

#include "../../include/net.h"

 

int quit_1(int sfd, Node *newnode)

{

    Online *temp = head;

    Online *ptr;

 

    if(sfd == temp->sfd)

    {

        head = head->next;

newnode->ack = QUIT_OK;

write(sfd, newnode, sizeof(Node));

 

temp->on_flag = 0;

ptr = temp;

temp = temp->next;

 

return 0;

    }

 

    while(temp != NULL)

    {

        if(sfd == temp->sfd)

{

    newnode->ack = QUIT_OK;

    write(sfd, newnode, sizeof(Node));

 

    temp->on_flag = 0;

    

    ptr->next = temp->next;

 

    return 0;

}

ptr = temp;

temp = temp->next;

    }

 

    return 0;

}

 

 

int err_quit(int sfd)

{

    Online *temp = head;

    Online *ptr;

 

    if(sfd == temp->sfd)

    {

        head = head->next;

 

temp->on_flag = 0;

ptr = temp;

temp = temp->next;

 

return 0;

    }

 

    while(temp != NULL)

    {

        if(sfd == temp->sfd)

{

    temp->on_flag = 0;

    

    ptr->next = temp->next;

 

    return 0;

}

ptr = temp;

temp = temp->next;

    }

 

    return 0;

}

 

/*********************************************************

-  File name    :read_msg.c

*  ******************************************************/

 

#include "../../include/net.h"

 

char buf[1024];

 

void read_msg(void *arg)

{

    int sfd = *((int *)arg);

    

    int n_read;

 

    Node *newnode = (Node *) malloc (sizeof(Node));

 

    while(1)

    {

        memset(newnode, 0, sizeof(Node));

/* 接收cmd */

if((n_read = read(sfd, newnode, sizeof(Node))) == 0)

{

    if(head != NULL)

    {

        err_quit(sfd);

    }

    close(sfd);

    pthread_exit(NULL);

 

}

 

switch(newnode->ack)

{

    case log:

    {

        log_1(sfd,newnode);

        break;

    }

 

    case reg:

    {

        reg_1(sfd,newnode);

        break;

    }

    

    case sayto:

    {

        sayto_1(sfd, newnode);

break;

    }

 

    case sayall:

    {

        sayall_1(sfd, newnode);

break;

    }

 

    case dis:

    {

        dis_1(sfd, newnode);

break;

    }

 

    case change:

    {

        change_1(sfd, newnode);

break;

    }

 

    case send_file:

    {

        send_1(sfd, newnode);

break;

    }

 

    case stop_say:

    {

        stop_say_1(sfd, newnode);

break;

    }

 

    case let_say:

    {

        let_say_1(sfd, newnode);

break;

    }

 

    case t_man:

    {

        t_man_1(sfd, newnode);

break;

    }

 

    case quit:

    {

        quit_1(sfd, newnode);

break;

    }

}

 

 

    }

}

 

Scripts:

CC := gcc

CFLAGS := -Wall -O3

Libs = -lpthread -lsqlite3

Target := server

Source := $(wildcard src/*.c)

Objs := $(patsubst %.c,%.o,$(Source))

Modules += chat creat_table get log_reg main quit_1 read_msg sup tcp_socket

AllObjs := $(addsuffix /src/*.o,$(Modules))

 

 

/*********************************************************

-  File name    :send_1.c

*  ******************************************************/

 

int send_1(int sfd, Node *newnode)

{

    char buf[100];

 

    char *sql;

    char *errmsg;

 

    int nrow;

    int ncolumn;

    char **azresult;

 

    /* 接受name,检查是否在线 */

    memset(buf, 0, sizeof(buf));

    sprintf(buf, "select * from client_inform where name = '%s' or id = '%s';", newnode->toname, newnode->toname);

    sql = buf;

 

    if(SQLITE_OK != sqlite3_get_table(db, sql, &azresult, &nrow, &ncolumn, &errmsg))

    {

        perror("sqlite3_get_table send error!\n");

exit(0);

    }

 

    if(nrow == 0)

    {

        newnode->ack = NOT_EXIT;

write(sfd, newnode, sizeof(Node));

return 0;

    }

    else if(nrow == 1)

    {

        Online *temp = head;

 

while(temp != NULL)

{

    if(strcmp(newnode->toname, temp->name) == 0)

    {

        newnode->ack = RECV_FILE;

write(temp->sfd, newnode, sizeof(Node));

 

return 0;

    }

    temp = temp->next;

}

 

/* 无其他用户在线 */

newnode->ack = No_online;

write(sfd, newnode, sizeof(Node));

    }

 

    return 0;

}

 

/*********************************************************

-  File name    :sup.c

*  ******************************************************/

 

#include "../../include/net.h"

 

int stop_say_1(int sfd, Node *newnode)

{

    Online *temp = head;

 

    while(temp != NULL)

    {

        if(strcmp(newnode->name, temp->name) == 0)

{

    temp->speek_flag = 0;

    newnode->ack = STOP_SAY_OK;

            write(sfd, newnode, sizeof(Node));

 

            /* 通知被禁言用户已被禁言 */

    newnode->ack = No_say;

    write(temp->sfd, newnode, sizeof(Node));

    break;

}

temp = temp->next;

    }

 

    return 0;

}

 

int let_say_1(int sfd, Node *newnode)

{

    Online *temp = head;

 

    while(temp != NULL)

    {

        if(strcmp(newnode->name, temp->name) == 0)

{

    if(temp->speek_flag == 0)          //该用户之前被禁言

    {

        temp->speek_flag = 1;

        newnode->ack = LET_SAY_OK;

                write(sfd, newnode, sizeof(Node));

 

/* 通知用户被解禁 */

newnode->ack = Ok_say;

write(temp->sfd, newnode, sizeof(Node));

        return 0;

    }

    else if(temp->speek_flag == 1)

    {

        newnode->ack = NOT_STOP_SAY;    //该用户没有被禁言

write(sfd, newnode, sizeof(Node));

 

//newnode->ack = Ok_say;

//write(temp->sfd, newnode, sizeof(Node));

return 0;

    }

}

temp = temp->next;

    }

 

    return 0;

}

 

int t_man_1(int sfd, Node *newnode)

{

    Online *temp = head;

    Online *ptr;

 

    if(strcmp(newnode->name, temp->name) == 0)

    {

        head = head->next;

newnode->ack = T_OK;

write(sfd, newnode, sizeof(Node));

 

newnode->ack = YOU_OUT;

write(temp->sfd, newnode, sizeof(Node));

 

temp->on_flag = 0;

ptr = temp;

temp = temp->next;

 

return 0;

    }

 

    while(temp != NULL)

    {

        if(strcmp(newnode->name, temp->name) == 0)

{

    newnode->ack = T_OK;

    write(sfd, newnode, sizeof(Node));

 

    newnode->ack = YOU_OUT;

    write(temp->sfd, newnode, sizeof(Node));

 

    temp->on_flag = 0;

    

    ptr->next = temp->next;

 

    return 0;

}

ptr = temp;

temp = temp->next;

    }

    

    newnode->ack = No_online;

    write(sfd, newnode, sizeof(Node));

 

    return 0;

}

 

 

/*********************************************************

-  File name    :tcp_socket.c

*  ******************************************************/

 

#include "../../include/net.h"

 

int tcp_init()

{

    int sfd;

 

    int opt = 1;

 

    if((sfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)

    {

        perror("socket error!\n");

exit(-1);

    }

 

    struct sockaddr_in severaddr;

    bzero(&severaddr, sizeof(severaddr));

    severaddr.sin_family = AF_INET;

    severaddr.sin_addr.s_addr = htonl(INADDR_ANY);

    severaddr.sin_port = htons(8888);

 

    setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));

 

    if(bind(sfd, (struct sockaddr *)&severaddr, sizeof(severaddr)) == -1)

    {

        perror("bind error!\n");

close(sfd);

exit(-1);

    }

 

    if(listen(sfd,1024) == -1)

    {

        perror("listen error!\n");

close(sfd);

exit(-1);

    }

 

    return sfd;

}

 

int tcp_accept(int sfd)

{

    struct sockaddr_in cliaddr;

    memset(&cliaddr, 0, sizeof(cliaddr));

 

    int connfd;

    unsigned int clilen = sizeof(cliaddr);

 

    if((connfd = accept(sfd, (struct sockaddr *)&cliaddr, &clilen)) == -1)

    {

        perror("accept error!\n");

close(sfd);

exit(-1);

    }

 

    printf("%s %d success connect\n",inet_ntoa(cliaddr.sin_addr),ntohs(cliaddr.sin_port));

 

    return connfd;

}

 

 

 

 

 

 

 

 

 


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

XuLujuncsdn

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

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

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

打赏作者

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

抵扣说明:

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

余额充值