UDP网络聊天室(服务器)

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

File Name: server.h
Author: 浮生流年
Function List: main() 主函数
Created Time: 2017年12月12日 星期二 20时17分13秒
**************************************************************/

#ifndef _UDP_NET_SOCKET_
#define _UDP_NET_SOCKET_

#include <sys/types.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <sqlite3.h>

#define PORT            8888


struct userinfo
{
    int flag;//
    char buf[100];//
    char account[20];
    char password[20];
    char nickname[100];
    char moto[256];
    int likes;
    char vip[20];
    char qq_email[64];
    char administrator[20];//管理员
    char msg[1024];//存储对话消息
    char to_nickname[20];
    int online_number;
    char online_nickname[100][20];//存储在线人员名单
    char file_name[64];//文件名称 
    char file_content[4096];//文件内容
    char shut_up[20];//禁言标志位
    char tmp_name[20];
};

typedef struct userinfo Userinfo;

struct node
{
    struct sockaddr_in client_addr;
    char nickname[20];
    struct node *next;
};

typedef struct node Node;

void forgot(sqlite3 *ppdb, Userinfo *recvbuf, Node **head, struct sockaddr_in *tmp_addr, int *sockfd);

#endif
#include <stdio.h>

#include "server.h"




void server_save_info(sqlite3 *ppdb, Userinfo *recvbuf, Userinfo *sendbuf)
{
    int ret;
    char auff[1024];

    sprintf(auff, "insert into save_info values('%s', '%s', '%s', '%s', '%d', '%s', '%s', '%s', '%s')", recvbuf->account, recvbuf->password,
            recvbuf->nickname, recvbuf->moto, recvbuf->likes, recvbuf->vip, recvbuf->qq_email, recvbuf->administrator, recvbuf->shut_up);
    ret = sqlite3_exec(ppdb, auff, NULL, NULL, NULL);
    if (ret != SQLITE_OK)
    {
        perror("sqlite3_exec");
        strcpy(sendbuf->buf, "帐号已存在!");
    }
    else
    {
        strcpy(sendbuf->buf, "注册成功!");
    }
}


void server_login(sqlite3 *ppdb, Userinfo *recvbuf, Userinfo *sendbuf, Node **head, struct sockaddr_in *tmp_addr)
{
    bzero(sendbuf, sizeof(*sendbuf));
    char **dbresult = NULL;
    char *errmsg = NULL;//用来存储错误信息字符串
    int nrow;//查询出多少记录(总行数)
    int ncolumn;//查询出来的记录有多少字段,(总列数)
    int ret, i;
    char cuff[1024];

    sprintf(cuff, "select account, password, nickname, moto, likes, vip , administrator from save_info where account = '%s' and password = '%s'", recvbuf->account, recvbuf->password);
    ret = sqlite3_get_table(ppdb, cuff, &dbresult, &nrow, &ncolumn, &errmsg);//执行成功返回SQLITE_OK,否则返回其他值
    if (ret != SQLITE_OK)
    {
        perror("sqlite3_get_table_server_login");
        return;
    }

    if (1 == nrow)
    {
        Node *tmp = (*head)->next;
        while (tmp != (*head))
        {
            if (!strcmp(tmp->nickname, dbresult[9]))
            {
                strcpy(sendbuf->buf, "该帐号已在其他地方登录!");
                return;
            }
            tmp = tmp->next;
        }

        strcpy(sendbuf->buf, "登录成功!");
        strcpy(sendbuf->nickname, dbresult[9]);
        strcpy(sendbuf->moto, dbresult[10]);
        sendbuf->likes = (*dbresult[11]) - 48;
        strcpy(sendbuf->vip, dbresult[12]);
        strcpy(sendbuf->administrator, dbresult[13]);

        Node *p = (Node *)malloc(sizeof(Node));//链表用来记录帐号是否已登录,登录的帐号接入链表
        if (NULL == p)
        {
            printf("Malloc Failure !\n");
            return;
        }
        p->client_addr.sin_family = tmp_addr->sin_family;
        p->client_addr.sin_port = tmp_addr->sin_port;
        p->client_addr.sin_addr.s_addr = tmp_addr->sin_addr.s_addr;

        strcpy(p->nickname, dbresult[9]);

        p->next = (*head)->next;
        (*head)->next = p;//循环链表;  记忆:head始终在最有边,新来的结点在最左边,head->next 始终指向p
    }
    else
    {
        strcpy(sendbuf->buf, "帐号或密码错误");
    }
}
void forgot_password(sqlite3 *ppdb, Userinfo *recvbuf, Node **head, struct sockaddr_in *tmp_addr, int *sockfd)
{
    Userinfo sendbuf = {0};
    bzero(&sendbuf, sizeof(sendbuf));
    char **dbresult = NULL;
    char *errmsg = NULL;//用来存储错误信息字符串
    int nrow;//查询出多少记录(总行数)
    int ncolumn;//查询出来的记录有多少字段,(总列数)
    int ret, i;
    char cuff[1024];

    sprintf(cuff, "select account, password from save_info where qq_email = '%s'", recvbuf->qq_email);
    ret = sqlite3_get_table(ppdb, cuff, &dbresult, &nrow, &ncolumn, &errmsg);//执行成功返回SQLITE_OK,否则返回其他值
    if (ret != SQLITE_OK)
    {
        perror("sqlite3_get_table_server_login");
        return;
    }

    if (1 == nrow)
    {
        strcpy(sendbuf.buf, "忘记密码");
        strcpy(sendbuf.account, dbresult[2]);
        strcpy(sendbuf.password, dbresult[3]);
        ret = sendto(*sockfd, &sendbuf, sizeof(sendbuf), 0, (struct sockaddr *)tmp_addr, sizeof(*tmp_addr));
        if (ret < 0)
        {
            perror("sendto_forgot_password");
            return;
        }
    }
    else
    {
        strcpy(sendbuf.buf, "该帐号未注册");
        ret = sendto(*sockfd, &sendbuf, sizeof(sendbuf), 0, (struct sockaddr *)tmp_addr, sizeof(*tmp_addr));
        if (ret < 0)
        {
            perror("sendto_forgot_password");
            return;
        }
    }
}
void transmit_to(sqlite3 *ppdb, Userinfo *sendbuf, Userinfo *recvbuf)//存储接收方用户信息to_nickname
{


    char **dbresult = NULL;
    char *errmsg = NULL;//用来存储错误信息字符串
    int nrow;//查询出多少记录(总行数)
    int ncolumn;//查询出来的记录有多少字段,(总列数)
    int ret, i;
    char cuff[1024];

    sprintf(cuff, "select shut_up, password, nickname, moto, likes, vip , administrator from save_info where nickname = '%s'", recvbuf->to_nickname);
    ret = sqlite3_get_table(ppdb, cuff, &dbresult, &nrow, &ncolumn, &errmsg);//执行成功返回SQLITE_OK,否则返回其他值
    if (ret != SQLITE_OK)
    {
        perror("sqlite3_get_table_server_login");
        return;
    }

    if (1 == nrow)
    {

        strcpy(sendbuf->shut_up, dbresult[7]);
        strcpy(sendbuf->nickname, dbresult[9]);//
        strcpy(sendbuf->moto, dbresult[10]);
        sendbuf->likes = (*dbresult[11]) - 48;
        strcpy(sendbuf->vip, dbresult[12]);
        strcpy(sendbuf->administrator, dbresult[13]);
    }
}
void transmit(sqlite3 *ppdb, Userinfo *sendbuf, Userinfo *recvbuf)//存储发送方用户信息
{


    char **dbresult = NULL;
    char *errmsg = NULL;//用来存储错误信息字符串
    int nrow;//查询出多少记录(总行数)
    int ncolumn;//查询出来的记录有多少字段,(总列数)
    int ret, i;
    char cuff[1024];

    sprintf(cuff, "select shut_up, password, nickname, moto, likes, vip , administrator from save_info where nickname = '%s'", recvbuf->nickname);
    ret = sqlite3_get_table(ppdb, cuff, &dbresult, &nrow, &ncolumn, &errmsg);//执行成功返回SQLITE_OK,否则返回其他值
    if (ret != SQLITE_OK)
    {
        perror("sqlite3_get_table_server_login");
        return;
    }

    if (1 == nrow)
    {

        strcpy(sendbuf->shut_up, dbresult[7]);
        strcpy(sendbuf->nickname, dbresult[9]);//
        strcpy(sendbuf->moto, dbresult[10]);
        sendbuf->likes = (*dbresult[11]) - 48;
        strcpy(sendbuf->vip, dbresult[12]);
        strcpy(sendbuf->administrator, dbresult[13]);
    }
}
void transmit_back(sqlite3 *ppdb, Userinfo *recvbuf, struct sockaddr_in *tmp_addr, int *sockfd)
    //存储发送方用户信息并直接返回发送方,用于处理客户端误操作或重复操作
{
    Userinfo sendbuf = {0};
    bzero(&sendbuf, sizeof(sendbuf));
    char **dbresult = NULL;
    char *errmsg = NULL;//用来存储错误信息字符串
    int nrow;//查询出多少记录(总行数)
    int ncolumn;//查询出来的记录有多少字段,(总列数)
    int ret, i;
    char cuff[1024];

    sprintf(cuff, "select shut_up, password, nickname, moto, likes, vip , administrator from save_info where nickname = '%s'", recvbuf->nickname);
    ret = sqlite3_get_table(ppdb, cuff, &dbresult, &nrow, &ncolumn, &errmsg);//执行成功返回SQLITE_OK,否则返回其他值
    if (ret != SQLITE_OK)
    {
        perror("sqlite3_get_table_server_login");
        return;
    }

    if (1 == nrow)
    {

        strcpy(sendbuf.shut_up, dbresult[7]);
        strcpy(sendbuf.nickname, dbresult[9]);//
        strcpy(sendbuf.moto, dbresult[10]);
        sendbuf.likes = (*dbresult[11]) - 48;
        strcpy(sendbuf.vip, dbresult[12]);
        strcpy(sendbuf.administrator, dbresult[13]);
    }
    ret = sendto(*sockfd, &sendbuf, sizeof(sendbuf), 0, (struct sockaddr *)tmp_addr, sizeof(*tmp_addr));
    if (ret < 0)
    {
        perror("sendto_transmit_back");
        return;
    }
}
void private_chat(sqlite3 *ppdb, Userinfo *recvbuf, Node **head, struct sockaddr_in *tmp_addr, int *sockfd)
{
    int ret;
    Userinfo sendbuf;
    bzero(&sendbuf, sizeof(sendbuf));
    Node *tmp = (*head)->next;
    Node *p = (*head)->next;
    while (p != *head)
    {
        p = p->next;
    }


    while (tmp != *head)
    {
        if (strcmp(tmp->nickname, recvbuf->to_nickname) == 0)//判断接收消息的用户是否已登录
        {
            strcpy(sendbuf.nickname, tmp->nickname);//把对方的名字发过去方便用于保存聊天记录
            strcpy(sendbuf.msg, recvbuf->msg);
            strcpy(sendbuf.tmp_name, recvbuf->nickname);
            strcpy(sendbuf.buf, "1私聊");//发送给指定用户

            transmit_to(ppdb, &sendbuf, recvbuf);//*********************************************************************
            ret = sendto(*sockfd, &sendbuf, sizeof(sendbuf), 0, (struct sockaddr *)&tmp->client_addr, sizeof(tmp->client_addr));
            if (ret < 0)
            { 
                perror("sendto_private_char_to_nickname");
                return;
            }
            bzero(&sendbuf, sizeof(sendbuf));
            strcpy(sendbuf.buf, "2正在转发私聊信息");
            transmit(ppdb, &sendbuf, recvbuf);//******************************************************************
            ret = sendto(*sockfd, &sendbuf, sizeof(sendbuf), 0, (struct sockaddr *)tmp_addr, sizeof(*tmp_addr));//发送给自己告知已发送消息
            bzero(&sendbuf, sizeof(sendbuf));
            if (ret < 0)
            {
                perror("sendto_private_char_nickname_success");
                return;
            }
            return;
        }
        tmp = tmp->next;
    }
    strcpy(sendbuf.buf, "3对方暂未登录");
    transmit(ppdb, &sendbuf, recvbuf);//*********************************************************************
    ret = sendto(*sockfd, &sendbuf, sizeof(sendbuf), 0, (struct sockaddr *)tmp_addr, sizeof(*tmp_addr));
    bzero(&sendbuf, sizeof(sendbuf));//ke yi bu yao
    if (ret < 0)
    {
        perror("sendto_private_char_nickname_not_login");
        return;
    }

}
void group_chat(sqlite3 *ppdb, Userinfo *recvbuf, Node **head, struct sockaddr_in *tmp_addr, int *sockfd)//群聊
{
    int ret, flag = 0;
    Userinfo sendbuf = {0};
    bzero(&sendbuf, sizeof(sendbuf));

    Node *tmp = (*head)->next;
    while (tmp != *head)
    {
        if (tmp->client_addr.sin_port != tmp_addr->sin_port)
        {
            flag = 1;
            strcpy(sendbuf.tmp_name, recvbuf->nickname);

            strcpy(sendbuf.msg, recvbuf->msg);

            strcpy(sendbuf.buf, "5发起群聊");
            ret = sendto(*sockfd, &sendbuf, sizeof(sendbuf), 0, (struct sockaddr *)&tmp->client_addr, sizeof(tmp->client_addr));
            bzero(&sendbuf, sizeof(sendbuf));
            if (ret < 0)
            {
                perror("sendto_group_chat");
                return;
            }
        }
        tmp = tmp->next;
    }
    if (1 == flag)
    {
        strcpy(sendbuf.buf, "2群聊成功");
        transmit(ppdb, &sendbuf, recvbuf);//*********************************************************************
        ret = sendto(*sockfd, &sendbuf, sizeof(sendbuf), 0, (struct sockaddr *)tmp_addr, sizeof(*tmp_addr));
        if (ret < 0)
        {
            perror("sendto_group_chat_success");
            return;
        }
    }
    else 
    {
        strcpy(sendbuf.buf, "6群聊失败");
        transmit(ppdb, &sendbuf, recvbuf);//*********************************************************************
        ret = sendto(*sockfd, &sendbuf, sizeof(sendbuf), 0, (struct sockaddr *)tmp_addr, sizeof(*tmp_addr));
        if (ret < 0)
        {
            perror("sendto_group_chat_faliure");
            return;
        }
    }
}
void file_transfer(sqlite3 *ppdb, Userinfo *recvbuf, Node **head, struct sockaddr_in *tmp_addr, int *sockfd)//注意这个head传参
{
    int ret, flag = 0;
    Userinfo sendbuf = {0};
    bzero(&sendbuf, sizeof(sendbuf));

    Node *tmp = (*head)->next;
    while (tmp != (*head))
    {
        if (!strcmp(tmp->nickname, recvbuf->to_nickname))
        {
            flag = 1;
            strcpy(sendbuf.tmp_name, recvbuf->nickname);
            strcpy(sendbuf.file_name, recvbuf->file_name);//拷贝文件名
            strcpy(sendbuf.file_content, recvbuf->file_content);//拷贝文件内容
            strcpy(sendbuf.buf, "7传输文件");
            transmit_to(ppdb, &sendbuf, recvbuf);//*********************************************************************
            ret = sendto(*sockfd, &sendbuf, sizeof(sendbuf), 0, (struct sockaddr *)&tmp->client_addr, sizeof(tmp->client_addr));
            bzero(&sendbuf, sizeof(sendbuf));
            if (ret < 0)
            {
                perror("sendto_group_chat");
                return;
            }
        }
        tmp = tmp->next;
    }

    if (1 == flag)
    {
        strcpy(sendbuf.buf, "2文件传输成功");
        transmit(ppdb, &sendbuf, recvbuf);//*********************************************************************
        ret = sendto(*sockfd, &sendbuf, sizeof(sendbuf), 0, (struct sockaddr *)tmp_addr, sizeof(*tmp_addr));
        if (ret < 0)
        {
            perror("sendto_file_transfer_success");
            return;
        }
    }
    else 
    {
        strcpy(sendbuf.buf, "6文件传输失败");
        transmit(ppdb, &sendbuf, recvbuf);//*********************************************************************
        ret = sendto(*sockfd, &sendbuf, sizeof(sendbuf), 0, (struct sockaddr *)tmp_addr, sizeof(*tmp_addr));
        if (ret < 0)
        {
            perror("sendto_file_transfer_faliure");
            return;
        }
    }
}
void online_number(sqlite3 *ppdb, Userinfo *sendbuf, Userinfo *recvbuf, Node **head)//查看在线人数以及打印名单
{

    bzero(&sendbuf->online_nickname, sizeof(sendbuf->online_nickname));
    sendbuf->online_number = 0;
    Node *tmp = (*head)->next;
    printf("****************&&&&&&&&&&&&&&&&&&1\n");
    while (tmp != *head)
    {
        printf("****************&&&&&&&&&&&&&&&&&&&2\n");
    //  strcpy(sendbuf->online_nickname[sendbuf->online_number], tmp->nickname);//指针并没有malloc,等我有空malloc一下试试
    //  sendbuf->online_nickname[sendbuf->online_number] = tmp->nickname;
    //  sendbuf->online_nickname[sendbuf->online_number] = tmp->nickname;//这样的话只能传送地址,地址中的信息传递不了
        strcpy(sendbuf->online_nickname[sendbuf->online_number], tmp->nickname);//数组越界:之前定义数组char online_nickname[100][100]?    
        printf("***********************&&&&&&&&&&3\n");

        printf("tmp->nickname:%s\n", tmp->nickname);

        printf("online_nickname:%s\n", sendbuf->online_nickname[sendbuf->online_number]);

        sendbuf->online_number++;
        tmp = tmp->next;
    }
    strcpy(sendbuf->buf, "4在线人数");
    transmit(ppdb, sendbuf, recvbuf);//*********************************************************************
}
void give_like(sqlite3 *ppdb, Userinfo *recvbuf, Node **head, struct sockaddr_in *tmp_addr, int *sockfd)
{
    int ret, i;
    int nrow;
    int ncolumn;
    char cuff[1024];
    char *errmsg = NULL;
    char **dbresult = NULL;
    Userinfo sendbuf = {0};
    bzero(&sendbuf, sizeof(sendbuf));//应该多余吧

    sprintf(cuff, "select likes from save_info where nickname = '%s'", recvbuf->to_nickname);
    ret = sqlite3_get_table(ppdb, cuff, &dbresult, &nrow, &ncolumn, &errmsg);
    if (ret != SQLITE_OK)
    {
        printf("select failure : %d(%s)\n", ret, errmsg);
        return;
    }

    if (1 == nrow)//只要此用户注册过,就为其点赞
    {
        sprintf(cuff, "update save_info set likes = likes + %d where nickname = '%s'", 1, recvbuf->to_nickname);
        ret = sqlite3_exec(ppdb, cuff, NULL, NULL, &errmsg);
        if (ret != SQLITE_OK)
        {
            printf("update failure : %d(%s)\n", ret, errmsg);
            return;
        }

        Node *tmp = (*head)->next;
        while (tmp != (*head))//遍历登录用户
        {
            printf("$$$$$$$$$$##########$$$$$$$$$$$2\n");
            if (!strcmp(tmp->nickname, recvbuf->to_nickname))//若登录,则向其发送提醒消息
            {
                printf("$$$$$$$$$$$$$$$$$#################$$$$$$$$$$$$$3\n");
                strcpy(sendbuf.buf, "8已为该登录用户点赞");

                transmit_to(ppdb, &sendbuf, recvbuf);//*********************************************************************

                sendbuf.likes = *(dbresult[1]);
                strcpy(sendbuf.tmp_name, recvbuf->nickname);

                ret = sendto(*sockfd, &sendbuf, sizeof(sendbuf), 0, (struct sockaddr *)&tmp->client_addr, sizeof(tmp->client_addr));
                bzero(&sendbuf, sizeof(sendbuf));
                if (ret < 0)
                {
                    perror("sendto_give_like");
                    return;
                }
                break;
            }
            tmp = tmp->next;
        }
        strcpy(sendbuf.buf, "9点赞成功");
        transmit(ppdb, &sendbuf, recvbuf);//*********************************************************************
        ret = sendto(*sockfd, &sendbuf, sizeof(sendbuf), 0, (struct sockaddr *)tmp_addr, sizeof(*tmp_addr));
        if (ret < 0)
        {
            perror("sendto_give_like_success");
            return;
        }
    }
    else
    {
        strcpy(sendbuf.buf, "10点赞失败");
        transmit(ppdb, &sendbuf, recvbuf);//*********************************************************************
        ret = sendto(*sockfd, &sendbuf, sizeof(sendbuf), 0, (struct sockaddr *)tmp_addr, sizeof(*tmp_addr));
        if (ret < 0)
        {
            perror("sendto_give_like_failure");
            return;
        }
    }
}
void change_character_signature(sqlite3 *ppdb, Userinfo *recvbuf, struct sockaddr_in *tmp_addr, int *sockfd)//修改个性签名
{
    int ret;
    char moto[1024];
    char *errmsg = NULL;
    Userinfo sendbuf = {0};


    sprintf(moto, "update save_info set moto = '%s' where nickname = '%s'", recvbuf->moto, recvbuf->nickname);

    ret = sqlite3_exec(ppdb, moto, NULL, NULL, &errmsg);
    if (ret != SQLITE_OK)
    {
        printf("update failure : %d(%s)\n", ret, errmsg);
        return;
    }

    strcpy(sendbuf.moto, recvbuf->moto);
    strcpy(sendbuf.buf, "11个性签名修改成功");
        transmit(ppdb, &sendbuf, recvbuf);//*********************************************************************
    ret = sendto(*sockfd, &sendbuf, sizeof(sendbuf), 0, (struct sockaddr *)tmp_addr, sizeof(*tmp_addr));
    if (ret < 0)
    {
        perror("sendto_change_character_signature_");
        return;
    }
}
void register_member(sqlite3 *ppdb, Userinfo *recvbuf, struct sockaddr_in *tmp_addr, int *sockfd)//处理注册会员
{
    int ret;
    char member[1024];
    char *errmsg = NULL;
    Userinfo sendbuf = {0};

    sprintf(member, "update save_info set vip = '%s' where nickname = '%s'", recvbuf->vip, recvbuf->nickname);

    ret = sqlite3_exec(ppdb, member, NULL, NULL, &errmsg);
    if (ret < 0)
    {
        perror("sqlite3_exec_register_member");
        return;
    }

    transmit(ppdb, &sendbuf, recvbuf);//*********************************************************************
    strcpy(sendbuf.vip, "荣耀会员");
    strcpy(sendbuf.buf, "12注册会员成功");


    ret = sendto(*sockfd, &sendbuf, sizeof(sendbuf), 0, (struct sockaddr *)tmp_addr, sizeof(*tmp_addr));
    if (ret < 0)
    {
        perror("sendto_register_member");
        return;
    }
}
void shut_up_person(sqlite3 *ppdb, Userinfo *recvbuf, Node **head, struct sockaddr_in *tmp_addr, int *sockfd)//指定用户禁言(只针对群聊)
{
    int ret, i;
    int nrow;
    int ncolumn;
    char cuff[1024];
    char *errmsg = NULL;
    char **dbresult = NULL;
    Userinfo sendbuf = {0};
    bzero(&sendbuf, sizeof(sendbuf));//应该多余吧

    sprintf(cuff, "select shut_up from save_info where nickname = '%s'", recvbuf->to_nickname);
    ret = sqlite3_get_table(ppdb, cuff, &dbresult, &nrow, &ncolumn, &errmsg);
    if (ret != SQLITE_OK)
    {
        printf("select failure : %d(%s)\n", ret, errmsg);
        return;
    }

    if (1 == nrow)//只要此用户注册过,就可以禁言
    {
        sprintf(cuff, "update save_info set shut_up = '%s' where nickname = '%s'", recvbuf->shut_up, recvbuf->to_nickname);
        ret = sqlite3_exec(ppdb, cuff, NULL, NULL, &errmsg);
        if (ret != SQLITE_OK)
        {
            printf("update failure : %d(%s)\n", ret, errmsg);
            return;
        }

        Node *tmp = (*head)->next;
        while (tmp != (*head))//遍历登录用户
        {
            printf("$$$$$$$$$$##########$$$$$$$$$$$2\n");
            if (!strcmp(tmp->nickname, recvbuf->to_nickname))//若登录,则向其发送提醒消息
            {
                printf("$$$$$$$$$$$$$$$$$#################$$$$$$$$$$$$$3\n");
                strcpy(sendbuf.buf, "13已将该登录用户禁言");


                transmit_to(ppdb, &sendbuf, recvbuf);//*********************************************************************

                strcpy(sendbuf.tmp_name, recvbuf->nickname);

                ret = sendto(*sockfd, &sendbuf, sizeof(sendbuf), 0, (struct sockaddr *)&tmp->client_addr, sizeof(tmp->client_addr));
                bzero(&sendbuf, sizeof(sendbuf));
                if (ret < 0)
                {
                    perror("sendto_shut_up");
                    return;
                }
                break;
            }
            tmp = tmp->next;
        }
        strcpy(sendbuf.buf, "14禁言成功");
        transmit(ppdb, &sendbuf, recvbuf);//*********************************************************************
        ret = sendto(*sockfd, &sendbuf, sizeof(sendbuf), 0, (struct sockaddr *)tmp_addr, sizeof(*tmp_addr));
        if (ret < 0)
        {
            perror("sendto_shut_up__success");
            return;
        }
    }
    else
    {
        strcpy(sendbuf.buf, "15禁言失败");
        transmit(ppdb, &sendbuf, recvbuf);//*********************************************************************
        ret = sendto(*sockfd, &sendbuf, sizeof(sendbuf), 0, (struct sockaddr *)tmp_addr, sizeof(*tmp_addr));
        if (ret < 0)
        {
            perror("sendto_shut_up_failure");
            return;
        }
    }
}
void shut_up_all(sqlite3 *ppdb, Userinfo *recvbuf, Node **head, struct sockaddr_in *tmp_addr, int *sockfd)//全员禁言(只针对群聊)
    //新注册用户还能群聊,真尴尬!!!
{
    int ret, i, flag = 0;
    char sql[1024];
    Userinfo sendbuf = {0};


    sprintf(sql, "update save_info set shut_up = '%s' where nickname != '%s'", recvbuf->shut_up, recvbuf->nickname);
    ret = sqlite3_exec(ppdb, sql, NULL, NULL, NULL);
    if (ret < 0)
    {
        perror("sqlite3_exec_shut_up_all");
        return;
    }

    strcpy(sendbuf.buf, "16全员禁言成功");    
    transmit(ppdb, &sendbuf, recvbuf);//*********************************************************************


    ret = sendto(*sockfd, &sendbuf, sizeof(sendbuf), 0, (struct sockaddr *)tmp_addr, sizeof(*tmp_addr));
    if (ret < 0)
    {
        perror("sendto_shut_up_all_success");
        return;
    }


    Node *tmp = (*head)->next;//如果用户在线, 就发消息通知
    while (tmp != *head)
    {
        if (tmp->client_addr.sin_port != tmp_addr->sin_port)
        {
            flag = 1;
            strcpy(sendbuf.tmp_name, recvbuf->nickname);

            strcpy(sendbuf.buf, "17本群开始禁言");
            transmit_to(ppdb, &sendbuf, recvbuf);//*********************************************************************
            ret = sendto(*sockfd, &sendbuf, sizeof(sendbuf), 0, (struct sockaddr *)&tmp->client_addr, sizeof(tmp->client_addr));
            bzero(&sendbuf, sizeof(sendbuf));
            if (ret < 0)
            {
                perror("sendto_group_chat");
                return;
            }
        }
        tmp = tmp->next;
    }
}   
void remove_banned(sqlite3 *ppdb, Userinfo *recvbuf, Node **head, struct sockaddr_in *tmp_addr, int *sockfd)//指定用户解禁(只针对群聊)
{
    int ret, i;
    int nrow;
    int ncolumn;
    char cuff[1024];
    char *errmsg = NULL;
    char **dbresult = NULL;
    Userinfo sendbuf = {0};

    sprintf(cuff, "select shut_up from save_info where nickname = '%s'", recvbuf->to_nickname);
    ret = sqlite3_get_table(ppdb, cuff, &dbresult, &nrow, &ncolumn, &errmsg);
    if (ret != SQLITE_OK)
    {
        printf("select failure : %d(%s)\n", ret, errmsg);
        return;
    }

    if (1 == nrow)//只要此用户注册过,就可以解禁
    {
        sprintf(cuff, "update save_info set shut_up = '%s' where nickname = '%s'", recvbuf->shut_up, recvbuf->to_nickname);
        ret = sqlite3_exec(ppdb, cuff, NULL, NULL, &errmsg);
        if (ret != SQLITE_OK)
        {
            printf("update failure : %d(%s)\n", ret, errmsg);
            return;
        }

        Node *tmp = (*head)->next;
        while (tmp != (*head))//遍历登录用户
        {
            printf("$$$$$$$$$$##########$$$$$$$$$$$2\n");
            if (!strcmp(tmp->nickname, recvbuf->to_nickname))//若登录,则向其发送提醒消息
            {
                printf("$$$$$$$$$$$$$$$$$#################$$$$$$$$$$$$$3\n");
                strcpy(sendbuf.buf, "18已将该登录用户禁言");

                transmit_to(ppdb, &sendbuf, recvbuf);//*********************************************************************


                strcpy(sendbuf.tmp_name, recvbuf->nickname);

                ret = sendto(*sockfd, &sendbuf, sizeof(sendbuf), 0, (struct sockaddr *)&tmp->client_addr, sizeof(tmp->client_addr));
                bzero(&sendbuf, sizeof(sendbuf));
                if (ret < 0)
                {
                    perror("sendto_remove_banned");
                    return;
                }
                break;
            }
            tmp = tmp->next;
        }
        strcpy(sendbuf.buf, "19解禁成功");
        transmit(ppdb, &sendbuf, recvbuf);//*********************************************************************
        ret = sendto(*sockfd, &sendbuf, sizeof(sendbuf), 0, (struct sockaddr *)tmp_addr, sizeof(*tmp_addr));
        if (ret < 0)
        {
            perror("sendto_shut_up__success");
            return;
        }
    }
    else
    {
        strcpy(sendbuf.buf, "20解禁失败");
        transmit(ppdb, &sendbuf, recvbuf);//*********************************************************************
        ret = sendto(*sockfd, &sendbuf, sizeof(sendbuf), 0, (struct sockaddr *)tmp_addr, sizeof(*tmp_addr));
        if (ret < 0)
        {
            perror("sendto_shut_up_failure");
            return;
        }
    }
}
void remove_banned_all(sqlite3 *ppdb, Userinfo *recvbuf, Node **head, struct sockaddr_in *tmp_addr, int *sockfd)//全员解禁(只针对群聊)
{
    int ret, i, flag = 0;
    char sql[1024];
    Userinfo sendbuf = {0};


    sprintf(sql, "update save_info set shut_up = '%s' where nickname != '%s'", recvbuf->shut_up, recvbuf->nickname);
    ret = sqlite3_exec(ppdb, sql, NULL, NULL, NULL);
    if (ret < 0)
    {
        perror("sqlite3_exec_shut_up_all");
        return;
    }

    strcpy(sendbuf.buf, "21全员解禁成功");    
    transmit(ppdb, &sendbuf, recvbuf);//*********************************************************************


    ret = sendto(*sockfd, &sendbuf, sizeof(sendbuf), 0, (struct sockaddr *)tmp_addr, sizeof(*tmp_addr));
    if (ret < 0)
    {
        perror("sendto_shut_up_all_success");
        return;
    }


    Node *tmp = (*head)->next;//如果用户在线, 就发消息通知
    while (tmp != *head)
    {
        if (tmp->client_addr.sin_port != tmp_addr->sin_port)
        {
            flag = 1;
            strcpy(sendbuf.tmp_name, recvbuf->nickname);

            strcpy(sendbuf.buf, "22本群已被解禁");
            transmit_to(ppdb, &sendbuf, recvbuf);//*********************************************************************
            ret = sendto(*sockfd, &sendbuf, sizeof(sendbuf), 0, (struct sockaddr *)&tmp->client_addr, sizeof(tmp->client_addr));
            bzero(&sendbuf, sizeof(sendbuf));
            if (ret < 0)
            {
                perror("sendto_group_chat");
                return;
            }
        }
        tmp = tmp->next;
    }
}   
void kicking(sqlite3 *ppdb, Userinfo *recvbuf, Node **head, struct sockaddr_in *tmp_addr, int *sockfd)//踢人(强制下线)
{
    int ret, i;
    int nrow;
    int ncolumn;
    char cuff[1024];
    char *errmsg = NULL;
    char **dbresult = NULL;
    Userinfo sendbuf = {0};
    Userinfo RecvBuf = {0};

    sprintf(cuff, "select shut_up from save_info where nickname = '%s'", recvbuf->to_nickname);//
    ret = sqlite3_get_table(ppdb, cuff, &dbresult, &nrow, &ncolumn, &errmsg);
    if (ret != SQLITE_OK)
    {
        printf("select failure : %d(%s)\n", ret, errmsg);
        return;
    }

    if (1 == nrow)//注册过(判断此用户是否注册过)
    {
        Node *tmp = *head;
        while (tmp->next != *head)//判断该用户是否已登录
        {
            if (!strcmp(tmp->next->nickname, recvbuf->to_nickname))//若登录,则向其发送提醒消息
            {

                strcpy(sendbuf.buf, "23已将该登录用户强制下线");

                transmit_to(ppdb, &sendbuf, recvbuf);//*********************************************************************
                strcpy(sendbuf.tmp_name, recvbuf->nickname);

                ret = sendto(*sockfd, &sendbuf, sizeof(sendbuf), 0, (struct sockaddr *)&tmp->next->client_addr, sizeof(tmp->next->client_addr));
                Node *p = tmp->next;//释放节点必须要在发送数据后,否则节点地址及内容就消失了,无法传送到指定客户端
                tmp->next = p->next;
                free(p);

                bzero(&sendbuf, sizeof(sendbuf));
                if (ret < 0)
                {
                    perror("sendto_remove_banned");
                    return;
                }
                strcpy(sendbuf.buf, "24踢人成功");
                transmit(ppdb, &sendbuf, recvbuf);//*********************************************************************


                ret = sendto(*sockfd, &sendbuf, sizeof(sendbuf), 0, (struct sockaddr *)tmp_addr, sizeof(*tmp_addr));
                bzero(&sendbuf, sizeof(sendbuf));
                if (ret < 0)
                {
                    perror("sendto_shut_up__success");
                    return;
                }
                bzero(&sendbuf,sizeof(sendbuf));

                Node *temp = (*head)->next;
                while (temp != *head)
                {
                    if (strcmp(temp->nickname, recvbuf->nickname))
                    {
                        strcpy(sendbuf.tmp_name, recvbuf->to_nickname);

                        strcpy(sendbuf.buf, "29好友下线通知");
                        strcpy(RecvBuf.nickname, temp->nickname);
                        transmit(ppdb, &sendbuf, &RecvBuf);//*********************************************************************
                        ret = sendto(*sockfd, &sendbuf, sizeof(sendbuf), 0, (struct sockaddr *)&temp->client_addr, sizeof(temp->client_addr));
                        bzero(&sendbuf, sizeof(sendbuf));
                        bzero(&RecvBuf, sizeof(RecvBuf));
                        if (ret < 0)
                        {
                            perror("sendto_group_chat");
                            return;
                        }
                    }
                    temp = temp->next;
                }

                return;
            }
            tmp = tmp->next;
        }
        strcpy(sendbuf.buf, "25踢人失败");//注册但未登录
        transmit(ppdb, &sendbuf, recvbuf);//*********************************************************************
        ret = sendto(*sockfd, &sendbuf, sizeof(sendbuf), 0, (struct sockaddr *)tmp_addr, sizeof(*tmp_addr));
        bzero(&sendbuf, sizeof(sendbuf));
        if (ret < 0)
        {
            perror("sendto_shut_up__success");
            return;
        }
        return;
    }
    else//没注册过
    {
        strcpy(sendbuf.buf, "26踢人失败");
        transmit(ppdb, &sendbuf, recvbuf);//*********************************************************************
        ret = sendto(*sockfd, &sendbuf, sizeof(sendbuf), 0, (struct sockaddr *)tmp_addr, sizeof(*tmp_addr));
        if (ret < 0)
        {
            perror("sendto_shut_up_failure");
            return;
        }
    }
}
void offline(sqlite3 *ppdb, Userinfo *recvbuf, Node **head, struct sockaddr_in *tmp_addr, int *sockfd)//主动下线(不终止客户端)
{
    int ret;
    Userinfo sendbuf = {0};
    bzero(&sendbuf, sizeof(sendbuf));
    Userinfo RecvBuf = {0};

    Node *tmp = (*head)->next;
    while (tmp != *head)
    {
        if (strcmp(tmp->nickname, recvbuf->nickname))
        {
            strcpy(sendbuf.tmp_name, recvbuf->nickname);

            strcpy(sendbuf.buf, "29好友下线通知");
            strcpy(RecvBuf.nickname, tmp->nickname);
            transmit(ppdb, &sendbuf, &RecvBuf);//*********************************************************************
            ret = sendto(*sockfd, &sendbuf, sizeof(sendbuf), 0, (struct sockaddr *)&tmp->client_addr, sizeof(tmp->client_addr));
            bzero(&sendbuf, sizeof(sendbuf));
            bzero(&RecvBuf, sizeof(RecvBuf));
            if (ret < 0)
            {
                perror("sendto_group_chat");
                return;
            }
        }
        tmp = tmp->next;
    }

    Node *temp = *head;//这种方式较好
    while (temp->next != *head)
    {
        if (!strcmp(temp->next->nickname, recvbuf->nickname))
        {
            Node *p = temp->next;
            temp->next = p->next;
            free(p);
            break;
        }
        temp = temp->next;
    }
    strcpy(sendbuf.buf, "27下线成功");//
    ret = sendto(*sockfd, &sendbuf, sizeof(sendbuf), 0, (struct sockaddr *)tmp_addr, sizeof(*tmp_addr));
    if (ret < 0)
    {
        perror("sendto_offline");
        return;
    }
}
void terminate_client(sqlite3 *ppdb, Userinfo *recvbuf, Node **head, int *sockfd)//主动下线(终止客户端)
{
    int ret;
    Userinfo sendbuf = {0};
    bzero(&sendbuf, sizeof(sendbuf));
    Userinfo RecvBuf = {0};

    Node *tmp = (*head)->next;
    while (tmp != *head)
    {
        if (strcmp(tmp->nickname, recvbuf->nickname))
        {
            strcpy(sendbuf.tmp_name, recvbuf->nickname);

            strcpy(sendbuf.buf, "29好友下线通知");
            strcpy(RecvBuf.nickname, tmp->nickname);
            transmit(ppdb, &sendbuf, &RecvBuf);//*********************************************************************
            ret = sendto(*sockfd, &sendbuf, sizeof(sendbuf), 0, (struct sockaddr *)&tmp->client_addr, sizeof(tmp->client_addr));
            bzero(&sendbuf, sizeof(sendbuf));
            bzero(&RecvBuf, sizeof(RecvBuf));
            if (ret < 0)
            {
                perror("sendto_group_chat");
                return;
            }
        }
        tmp = tmp->next;
    }

    Node *temp = *head;//这种方式较好
    while (temp->next != *head)
    {
        if (!strcmp(temp->next->nickname, recvbuf->nickname))
        {
            Node *p = temp->next;
            temp->next = p->next;
            free(p);
            break;
        }
        temp = temp->next;
    }
}
void friends_online_notification(sqlite3* ppdb, Userinfo *recvbuf, Node **head, struct sockaddr_in *tmp_addr, int *sockfd)//好友上线通知
{
    int ret;
    Userinfo sendbuf = {0};
    bzero(&sendbuf, sizeof(sendbuf));

    Userinfo RecvBuf = {0};

    Node *tmp = (*head)->next;
    while (tmp != *head)
    {
        if (strcmp(tmp->nickname, recvbuf->nickname))//链表中所有人除了自己
        {
            strcpy(sendbuf.tmp_name, recvbuf->nickname);

            strcpy(sendbuf.buf, "28好友上线通知");
            strcpy(RecvBuf.nickname, tmp->nickname);
            transmit(ppdb, &sendbuf, &RecvBuf);//*********************************************************************
            ret = sendto(*sockfd, &sendbuf, sizeof(sendbuf), 0, (struct sockaddr *)&tmp->client_addr, sizeof(tmp->client_addr));
            bzero(&sendbuf, sizeof(sendbuf));
            bzero(&RecvBuf, sizeof(RecvBuf));
            if (ret < 0)
            {
                perror("sendto_group_chat");
                return;
            }
        }
        tmp = tmp->next;
    }
}
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <stdlib.h>
#include "server.h"

#define PORT 8888
int main()
{
    int sockfd, length, ret, position;
    struct sockaddr_in server_addr;
//  struct sockaddr_in client_addr[100] = {0};//一次性记忆客户端,通过find_addr函数寻找,服务器停止后释放client_addr[100]中保存的内容
    struct sockaddr_in tmp_addr;
    char admin[512];

    Userinfo Sendbuf = {0};
    Userinfo Recvbuf = {0};
//  Userinfo recordbuf[100] = {0};
    sqlite3 *ppdb = NULL;

    char account[20] = "88888888";//初始化管理员信息
    char password[20] = "88888888";
    char nickname[100] = "浮生流年";
    char moto[256] = "山上山,水中水";
    int likes = 8888;
    char vip[20] = "至尊会员";
    char qq_email[64] = "1186461326";
    char administrator[20] = "管理员";
    char shut_up[20] = "未禁";

    Node *head = (Node *)malloc(sizeof(Node));
    if (NULL == head)
    {
        printf("Malloc Failure!\n");
        return;
    }
    head->next = head;

    ret = sqlite3_open("user.db", &ppdb);
    if (ret != SQLITE_OK)
    {
        perror("sqlite3_open");
        exit(1);
    }

    ret = sqlite3_exec(ppdb, "create table if not exists save_info(account text primary key, password text, nickname text, moto text, likes integer, vip text, qq_email text, administrator text, shut_up text);", NULL, NULL, NULL);
    if (ret != SQLITE_OK)
    {
        perror("sqlite3_exec_create_table");
        exit(1);
    }

    sprintf(admin, "insert into save_info values('%s', '%s', '%s', '%s', '%d', '%s', '%s', '%s', '%s')", account, password, nickname,
            moto, likes, vip, qq_email, administrator, shut_up);//服务器启动后自行生成一个管理员帐号
    ret = sqlite3_exec(ppdb, admin, NULL, NULL, NULL);
    if (ret != SQLITE_OK)
    {
        perror("sqlite3_exec_insert into");
        exit(1);
    }
    sockfd = socket(PF_INET, SOCK_DGRAM, 0);
    if (-1 == sockfd)
    {
        perror("socket");
        exit(1);

    }

    bzero(&server_addr, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = PORT;
    server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");

    ret = bind(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr));
    if (ret < 0)
    {
        perror("bind");
        exit(1);
    }
while (1)//此程序默认所有登录用户都在一个群里,暂无加群功能
    {
        length = sizeof(tmp_addr);
        ret = recvfrom(sockfd, &Recvbuf, sizeof(Recvbuf), 0, (struct sockaddr *)&tmp_addr, &length);
        if (ret < 0)
        {
            perror("recvfrom");
            exit(1);
        }

        switch (Recvbuf.flag)
        {
            case 1://注册
                server_save_info(ppdb, &Recvbuf, &Sendbuf);
                ret = sendto(sockfd, &Sendbuf, sizeof(Sendbuf), 0, (struct sockaddr *)&tmp_addr, sizeof(tmp_addr));
                if (ret < 0)
                {
                    perror("sendto_server_save_info");
                    break;
                }
                bzero(&Recvbuf, sizeof(Recvbuf));
                bzero(&Sendbuf, sizeof(Sendbuf));
                if (ret < 0)
                {
                        perror("sendto_server_register");
                    exit(1);
                }
                break;
            case 2://登录
                server_login(ppdb, &Recvbuf, &Sendbuf, &head, &tmp_addr);
                bzero(&Recvbuf, sizeof(Recvbuf));
                ret = sendto(sockfd, &Sendbuf, sizeof(Sendbuf), 0, (struct sockaddr *)&tmp_addr, sizeof(tmp_addr));
                if (ret < 0)
                {
                        perror("sendto_server_login");
                    exit(1);
                }
                bzero(&Sendbuf, sizeof(Sendbuf));
                break;
            case 3 ://忘记密码
                forgot_password(ppdb, &Recvbuf, &head, &tmp_addr, &sockfd);
                break;
            case 4://私聊
                private_chat(ppdb, &Recvbuf, &head, &tmp_addr, &sockfd);
                bzero(&Recvbuf, sizeof(Recvbuf));
                break;
            case 5://群聊
                group_chat(ppdb, &Recvbuf, &head, &tmp_addr, &sockfd);
                bzero(&Recvbuf, sizeof(Recvbuf));
                break;
            case 6://文件传输
                file_transfer(ppdb, &Recvbuf, &head, &tmp_addr, &sockfd);
                bzero(&Recvbuf, sizeof(Recvbuf));
                break;
            case 7://在线人数
                bzero(&Sendbuf, sizeof(Sendbuf));
                online_number(ppdb, &Sendbuf, &Recvbuf, &head);

        //      printf("%s\n", Sendbuf.online_nickname[0]);
                ret = sendto(sockfd, &Sendbuf, sizeof(Sendbuf), 0, (struct sockaddr *)&tmp_addr, sizeof(tmp_addr));
                if (ret < 0)
                {
                    perror("sendto_onine_number");
                    break;
                }
                break;
            case 8://查看聊天记录(融合了)
                break;
            case 9://快捷消息(融合了)
                break;
            case 10://点赞
                give_like(ppdb, &Recvbuf, &head, &tmp_addr, &sockfd);
                break;
            case 11://修改签名
                change_character_signature(ppdb, &Recvbuf, &tmp_addr, &sockfd);
                break;
            case 12://vip(充钱)
                register_member(ppdb, &Recvbuf, &tmp_addr, &sockfd);
                break;
            case 13://指定用户禁言(管理员权限)(只针对群聊,不影响私聊)
                shut_up_person(ppdb, &Recvbuf, &head, &tmp_addr, &sockfd);
                break;
            case 14://全员禁言(管理员权限)(注册过但没登录的也要禁言,确保用户上线后处于被动静默状态)(只针对群聊,不影响私聊)
                shut_up_all(ppdb, &Recvbuf, &head, &tmp_addr, &sockfd);
                break;
            case 15://指定用户解禁 (管理员权限)(只针对群聊,不影响私聊)
                remove_banned(ppdb, &Recvbuf, &head, &tmp_addr, &sockfd);
                break;
            case 16://全员解禁(管理员权限)(注册过但没登录的也要解禁,确保用户上线后处于言论自由状态)(只针对群聊,不影响私聊)
                remove_banned_all(ppdb, &Recvbuf, &head, &tmp_addr, &sockfd);
                break;
            case 17://踢人(管理员权限)(不终止客户端程序运行)
                kicking(ppdb, &Recvbuf, &head, &tmp_addr, &sockfd);
                break;
            case 18://退出(下线)不终止客户端
                offline(ppdb, &Recvbuf, &head, &tmp_addr, &sockfd);
                break;
            case 19://退出(下线)终止客户端
                terminate_client(ppdb, &Recvbuf, &head, &sockfd);   
                break;
            case 20:transmit_back(ppdb, &Recvbuf, &tmp_addr, &sockfd);//处理客户端因误操作或重复操作而导致信息丢失
                break;
            case 21://好友上线通知
                friends_online_notification(ppdb, &Recvbuf, &head, &tmp_addr, &sockfd);
                break;
        }
    }

    close(sockfd);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

浮生卍流年

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

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

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

打赏作者

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

抵扣说明:

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

余额充值