服务器端

struct.h

 

#ifndef _STRUCT_H_//服务器端头文件
#define _STRUCT_H_

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

#define PORT  9999

char myName[20];

sqlite3 * database;

struct Msg
{
    int  cmd;        // 消息类型
    char fromname[20];
    char password[10];
    char tag[50];
    char toname[20];
    char msg[1024];  // 消息内容    
};

struct online
{
    int sfd;
    int on_flag;
    int speek_flag;
    char name[20];
    struct online *next;
};

struct online *header;

#endif

 

server.c

 

#include "struct.h"

struct online *header = NULL;

// 初始化套接字,返回监听套接字
int init_socket()
{
    int listen_socket = socket(AF_INET, SOCK_STREAM, 0);
    if (listen_socket == -1)
    {
        perror ("socket");
        return -1;
    }
    
    struct sockaddr_in addr;
    memset(&addr, 0, sizeof(addr));
    addr.sin_family  = AF_INET;     // 设置地址族
    addr.sin_port    = htons(PORT); // 设置本地端口
    addr.sin_addr.s_addr = htonl(INADDR_ANY);   // 使用本地的任意IP地址
    
    int  ret = bind(listen_socket,  (struct sockaddr *)&addr, sizeof(addr));
    if (ret == -1)
    {
        perror ("bind");
        return -1;
    }
    
    ret = listen(listen_socket, 5);
    if (ret == -1)
    {
        perror ("listen");
        return -1;
    }
    
    printf ("等待客户端连接.......\n");
    return listen_socket;
}

// 处理客户端连接,返回与连接上的客户端通信的套接字
int  MyAccept(int listen_socket)
{
    struct sockaddr_in client_addr; // 用来保存客户端的ip和端口信息
    int len = sizeof(client_addr);
    int client_socket = accept(listen_socket,   (struct sockaddr *)&client_addr,  &len);
    if (client_socket == -1)
    {
        perror ("accept");
    }
    
    printf ("成功接收一个客户端: %s\n", inet_ntoa(client_addr.sin_addr));
    
    return client_socket;
}

//注册
int reg(int client_socket, struct Msg *msg)
{
    printf ("%s进行注册\n", msg->fromname);
    
    char *errmsg = NULL;
    char **resultp = NULL;
    int nrow, ncolumn;
    char buf[100];
    sprintf(buf,"select * from user where name = '%s';",msg->fromname);
    
    int ret = sqlite3_get_table(database, buf, &resultp, &nrow, &ncolumn, &errmsg);
    if (ret != SQLITE_OK)
    {
        printf ("数据库操作失败:%s\n", errmsg);
        return -1;
    }    
    
    //用户名已存在
    if( nrow != 0 )
    {
        printf("该用户名已存在!\n");
        msg->cmd = 1001;
        write (client_socket, msg, sizeof(struct Msg));
        return 0;
    }
    else
    {
        printf("用户名不存在,可以注册!\n");
        
        char tag[20] = "emmmmm.....";
        strcpy( msg->tag, tag );
        
        //向数据库中插入用户信息
        sprintf (buf, "insert into user values('%s', '%s', '%s')", msg->fromname, msg->password, msg->tag);
        ret = sqlite3_exec(database, buf, NULL, NULL, &errmsg);
        if (ret != SQLITE_OK)
        {
            printf ("数据库操作失败:%s\n", errmsg);
            msg->cmd = 1002;
            write (client_socket, msg, sizeof(struct Msg));
            return -1;
        }
        msg->cmd = 1003;
        printf("注册成功!\n");
        write (client_socket, msg, sizeof(struct Msg));
        
    }
    
    sqlite3_free_table(resultp);
}

//登录
int login(int client_socket, struct Msg *msg)
{
    printf ("%s进行登录\n", msg->fromname);
    
    char *errmsg = NULL;
    char **resultp = NULL;
    int nrow, ncolumn;
    char buf[100];
    sprintf(buf,"select * from user where name = '%s';",msg->fromname);
    
    int ret = sqlite3_get_table(database, buf, &resultp, &nrow, &ncolumn, &errmsg);
    if (ret != SQLITE_OK)
    {
        printf ("数据库操作失败:%s\n", errmsg);
        return -1;
    }    

    if ( nrow == 0 )
    {
        printf ("该用户名不存在!\n");
        msg->cmd = 2001;
        write (client_socket, msg, sizeof(struct Msg));
    }
    else
    {
        //密码正确
        if ( strcmp ( msg->password, resultp[4] ) == 0 )
        {    
            //检查用户是否在线
            struct online *temp = header;
            while (temp != NULL)
            {
                //用户已在线
                if (strcmp (temp->name, msg->fromname) == 0)
                {
                    if (temp->on_flag == 1)
                    {
                        msg->cmd = 2002;
                        printf ("用户已在线\n");
                        write (client_socket, msg, sizeof(struct Msg));
                        return 0;
                    }
                }
                temp = temp->next;
            }
            //用户不在线,保存用户信息
            struct online *node = (struct online *)malloc(sizeof(struct online));
            node->sfd = client_socket;
            node->on_flag     = 1;
            node->speek_flag  = 1;
            strcpy (node->name, msg->fromname);
            strcpy (msg->tag, resultp[5]);
            
            //将用户信息头插在在线链表中
            node->next = header;
            header = node;
            
            msg->cmd = 2003;
            printf ("登录成功!\n");
            write (client_socket, msg, sizeof(struct Msg));
            return 0;
        }
        printf ("密码输入错误!\n");
        msg->cmd = 2004;
        write (client_socket, msg, sizeof(struct Msg));
    }
    
    sqlite3_free_table (resultp);
    return 0;
}

// 私聊
void priva(int client_socket, struct Msg *msg)
{
    printf ("%s要给%s发一条消息\n", msg->fromname, msg->toname);
    
    //遍历在线用户链表
    struct online *temp = header;
    while (temp != NULL)
    {
        //找到要发送的对象
        if (strcmp (temp->name, msg->toname) == 0)
        {
            msg->cmd = 3001;
            write (temp->sfd, msg, sizeof(struct Msg));
            printf ("找到要发送的对象,消息发送成功!\n");
            
            msg->cmd = 3002;
            write (client_socket, msg, sizeof(struct Msg));
            return ;
            
        }
        temp = temp->next;
    }
    printf ("没有找到要发送的对象!\n");
    msg->cmd = 3003;
    write (client_socket, msg, sizeof(struct Msg));    
}

// 群发
void group(int client_socket, struct Msg *msg)
{
    printf ("%s发一次群消息\n", msg->fromname);
    
    //遍历在线用户链表
    struct online *temp = header;
    while (temp != NULL)
    {
        msg->cmd = 4001;
        write (temp->sfd, msg, sizeof(struct Msg));

        temp = temp->next;
    }
    msg->cmd = 4002;
    printf ("群发消息成功!\n");
    write (client_socket, msg, sizeof(struct Msg));
}

//查看在线用户
void check(int client_socket, struct Msg *msg)
{
    printf ("%s查看在线用户\n", msg->fromname);
    
    char buf[300] = {0};
    int len;
    //遍历在线用户链表
    struct online *temp = header;
    while (temp != NULL)
    {
        strcat ( buf, temp->name );
        len = sizeof(buf);
        buf[len] = ' ';

        temp = temp->next;
    }
    strcpy ( msg->msg, buf );
    printf ("在线用户有:%s\n",buf);
    msg->cmd = 5001;
    printf ("查看在线用户成功!\n");
    write (client_socket, msg, sizeof(struct Msg));
}

//修改密码
int changepwd(int client_socket, struct Msg *msg)
{
    printf ("%s修改密码\n", msg->fromname);
    
    char *errmsg = NULL;
    char **resultp = NULL;
    int nrow, ncolumn;
    char buf[100];
    sprintf(buf,"select * from user where name = '%s';",msg->fromname);
    
    int ret = sqlite3_get_table(database, buf, &resultp, &nrow, &ncolumn, &errmsg);
    if (ret != SQLITE_OK)
    {
        printf ("数据库操作失败:%s\n", errmsg);
        return -1;
    }    

    //密码正确
    if ( strcmp ( msg->password, resultp[4] ) == 0 )
    {
        char buf[100];
        sprintf (buf, "update user set password = '%s' where name = '%s'", msg->msg, msg->fromname);
        ret = sqlite3_exec(database, buf, NULL, NULL, &errmsg);
        if (ret != SQLITE_OK)
        {
            printf ("数据库操作失败:%s\n", errmsg);
            msg->cmd = 6001;
            write (client_socket, msg, sizeof(struct Msg));
            return -1;
        }
        msg->cmd = 6002;
        printf("修改密码成功!\n");
        write (client_socket, msg, sizeof(struct Msg));
    }
    else
    {
        msg->cmd = 6003;
        printf("密码错误!\n");
        write (client_socket, msg, sizeof(struct Msg));
    }
}

//修改个性签名
int changetag(int client_socket, struct Msg *msg)
{
    printf ("%s修改个性签名\n", msg->fromname);
    
    char *errmsg = NULL;
    char **resultp = NULL;
    int nrow, ncolumn;
    char buf[100];
    sprintf(buf,"select * from user where name = '%s';",msg->fromname);
    
    int ret = sqlite3_get_table(database, buf, &resultp, &nrow, &ncolumn, &errmsg);
    if (ret != SQLITE_OK)
    {
        printf ("数据库操作失败:%s\n", errmsg);
        return -1;
    }    

    sprintf (buf, "update user set tag = '%s' where name = '%s'", msg->tag, msg->fromname);
    ret = sqlite3_exec(database, buf, NULL, NULL, &errmsg);
    if (ret != SQLITE_OK)
    {
        printf ("数据库操作失败:%s\n", errmsg);
        msg->cmd = 7001;
        write (client_socket, msg, sizeof(struct Msg));
        return -1;
    }
    msg->cmd = 7002;
    printf ("修改个性签名成功!\n");
    write (client_socket, msg, sizeof(struct Msg));
}

int clientexit(int client_socket, struct Msg *msg)
{
    printf("%s要退出聊天室\n",msg->fromname);
    
    struct online *temp = header;
    struct online *prev = NULL;
    while (temp != NULL)
    {
        //找到在线用户节点
        //如果是第一个节点
        if (strcmp (temp->name, msg->fromname) == 0)
        {
            header = header->next;
            free(temp);
            temp = NULL;
            
            msg->cmd = 1301;
            printf ("删除在线用户节点成功!\n");
            write (client_socket, msg, sizeof(struct Msg));
            return 0;
        }
        else
        {
            prev = temp;
            temp = temp->next;
            if (strcmp (temp->name, msg->fromname) == 0)
            {
                prev->next = temp->next;
                free(temp);
                temp = NULL;
                
                msg->cmd = 1301;
                printf ("删除在线用户节点成功!\n");
                write (client_socket, msg, sizeof(struct Msg));
                return 0;
            }
        }
    }
    msg->cmd = 1302;
    printf ("没有找到该用户节点!\n");
    write (client_socket, msg, sizeof(struct Msg));
}

// 把 负责处理客户端通信的函数改成线程的工作函数
void* hanld_client(void* v)
{
    int client_socket = (int)v;
    struct Msg msg;
    while(1)
    {
        // 从客户端读一个结构体数据
        int ret = read(client_socket, &msg, sizeof(msg));
        if (ret == -1)
        {
            perror ("read");
            break;
        }
        
        // 代表客户端退出
        if (ret == 0)
        {
            printf ("客户端退出\n");
            break;
        }
        
        
        switch (msg.cmd)
        {
            case 1 :    // 注册
                reg(client_socket, &msg);
                break;
            case 2 :    // 登录
                login(client_socket, &msg);
                break;
            case 3 :    // 私聊
                priva(client_socket, &msg);
                break;
            case 4 :    // 群聊
                group(client_socket, &msg);
                break;
            case 5 :    // 查看在线用户
                check(client_socket, &msg);
                break;
            case 6:        // 修改密码
                changepwd(client_socket, &msg);
                break;
            case 7:        // 修改个性签名
                changetag(client_socket, &msg);
                break;
        /*    case 8:        // 找到要发送文件的对象
                finduser(client_socket, &msg);
                break;
            case 9:        // 发送文件
                sendfile(client_socket, &msg);
                break;*/
            case 13:    // 客户端退出
                clientexit(client_socket, &msg);
                break;
        }
        
    }
    close (client_socket);
}

int main()
{
    int listen_socket = init_socket();
    
    // 打开数据库
    int ret = sqlite3_open("user.db", &database);
    if (ret != SQLITE_OK)
    {
        printf ("打开数据库失败\n");
        return -1;
    }
    
    printf ("打开数据库成功\n");        
    
    char *errmsg = NULL;
    char *sql = "create table if not exists user ( name TEXT, password TEXT, tag TEXT, primary key(name) )";
    ret = sqlite3_exec(database, sql, NULL, NULL, &errmsg);
    if (ret != SQLITE_OK)
    {
        printf ("数据库操作失败:%s\n", errmsg);
        return -1;
    }
    
    while (1)
    {
        int client_socket = MyAccept(listen_socket);
        
        // 创建一个线程去处理客户端的请求,主线程依然负责监听
        pthread_t id;
        pthread_create(&id, NULL, hanld_client,  (void *)client_socket);
        
        pthread_detach(id); // 线程分离
    }
    close (listen_socket);

    sqlite3_close(database);
    
    return 0;
}
 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值