网络编程【16】(在线词典)

295 阅读5分钟
  1. 在传结构体时要注意结构体的大小,以及服务器和客户端双方的互传的结构体是否一样
  2. 在操作数据库的时候注意要有打开数据库的这一条件
  3. 注意sqlite3_get_table函数的返回值,用这个判断表里是否查询成功时是根据nrow的返回值来判断的
  4. 编译时记得链接库
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>

#define N 128
#define ERRLOG(errmsg) do{\
    perror(errmsg);\
    printf("%s - %s - %d\n", __FILE__, __func__, __LINE__);\
    exit(1);\
}while(0)

typedef struct{
    int code;
    int acceptfd;
    char user_name[N];
    char user_password[N];
    char word[N];
    char timebuf[18];
    struct sockaddr_in clientaddr;
}MSG;

void user_register(MSG msg,int sockfd);
void user_login(MSG msg,int sockfd);
void query_word(MSG msg,int sockfd);

int main(int argc, char const *argv[])
{
    if(argc < 3)
    {
        fprintf(stderr, "Usage: %s <ip> <port>\n", argv[0]);
        exit(1);
    }

    int sockfd;
    char chose;
    struct sockaddr_in serveraddr;
    socklen_t addrlen = sizeof(serveraddr);

    //第一步:创建套接字
    if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
    {
        ERRLOG("socket error");
    }

    //第二步:填充服务器网络信息结构体
    serveraddr.sin_family = AF_INET;
    serveraddr.sin_addr.s_addr = inet_addr(argv[1]);
    serveraddr.sin_port = htons(atoi(argv[2]));

    //第三步:给服务器发送客户端的连接请求
    if(connect(sockfd, (struct sockaddr *)&serveraddr, addrlen) == -1)
    {
        ERRLOG("connect error");
    }

    MSG msg;
  
    //进行通信
    char buf[N] = {0};
    while(1)
    {
START:

        printf("***********************************\n");
        printf("**1:register    2:login    3:quit**\n");
        printf("***********************************\n");
        
        scanf("%d",&msg.code);
        getchar();
        if(msg.code == 3)break;
        switch(msg.code)
        {
            case 1://注册

                user_register(msg,sockfd);
                break;
            case 2://登录
                user_login(msg,sockfd);
                break;
        
            default:
                break;       
        }
    }
    return 0;
}

void user_register(MSG msg,int sockfd)
{
    printf("input your name:");
    fgets(msg.user_name, sizeof(msg), stdin);
    msg.user_name[strlen(msg.user_name) - 1] = '\0';
    
    printf("input your password:");
    fgets(msg.user_password, sizeof(msg), stdin);
    msg.user_password[strlen(msg.user_password) - 1] = '\0';
                    
    if(send(sockfd, &msg, sizeof(msg), 0) == -1)
    {
        ERRLOG("send error");
    }

    char buf[N];
    if(recv(sockfd, buf, N, 0) == -1)
    {
        ERRLOG("recv error");
    }
    printf("%s\n",buf);
}

void user_login(MSG msg,int sockfd)
{
    printf("input your name:");
    fgets(msg.user_name, sizeof(msg), stdin);
    msg.user_name[strlen(msg.user_name) - 1] = '\0';
    
    printf("input your password:");
    fgets(msg.user_password, sizeof(msg), stdin);
    msg.user_password[strlen(msg.user_password) - 1] = '\0';
                    
    if(send(sockfd, &msg, sizeof(msg), 0) == -1)
    {
        ERRLOG("send error");
    }

    char buf[N];
    if(recv(sockfd, buf, N, 0) == -1)
    {
        ERRLOG("recv error");
    }
    else
    {
        printf("%s\n",buf);
    }

    query_word(msg,sockfd);
}

void query_word(MSG msg,int sockfd)
{
    if(recv(sockfd, &msg, N, 0) == -1)
    {
        ERRLOG("recv error");
    }
    switch(msg.code)
    {
        case 5://登录失败
            break;
        case 6://登录成功
            while(1)
            {
NEXT:
                printf("***********************************\n");
                printf("**1:query    2:history     3:quit**\n");
                printf("***********************************\n");
                printf("please choose :");
                scanf("%d",&msg.code);
                while(getchar()!='\n');

                if(msg.code == 3)break;
                switch(msg.code)
                {
                    case 1:
                    {
                        msg.code = 3;
                        printf("input word :");
                        fgets(msg.word, sizeof(msg), stdin);
                        msg.word[strlen(msg.word) - 1] = '\0';
                        if(send(sockfd, &msg, sizeof(msg), 0) == -1)
                        {
                            ERRLOG("send error");
                        }
                        char buf[500] = {0};
                        if(recv(sockfd, buf, 500, 0) == -1)
                        {
                            ERRLOG("recv error");
                        }
                        else
                        {
                            printf("%s\n",buf);
                        }
                    }
                        break;
                    case 2:
                    {
                        msg.code = 4;
                        if(send(sockfd, &msg, sizeof(msg), 0) == -1)
                        {
                            ERRLOG("send error");
                        }
                        
                        
                        char buf[N];
                        while(1)
                        {
                            
                            if(recv(sockfd, buf, N, 0) == -1)
                            {
                                ERRLOG("recv error");
                            }
                            
                            if(strcmp(buf,"next") == 0)goto NEXT;
                            printf("%s\n",buf);
                        }
                    } 
                        break;       
                    default:
                        break;                    
                }                            
            }
            break;
            default:
            break;                
    }
}
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>
#include <sqlite3.h>
#include <time.h>

#define DBFILE "dict.db"
#define TABLE1 "user"
#define TABLE2 "word"


#define N 128
#define ERRLOG(errmsg) do{\
    perror(errmsg);\
    printf("%s-%s-%d\n", __FILE__, __func__, __LINE__);\
    exit(1);\
}while(0)

typedef struct{
    int code;
    int acceptfd;
    char user_name[N];
    char user_password[N];
    char word[N];
    char timebuf[N];
    struct sockaddr_in clientaddr;
}MSG;

void creat_user_list(sqlite3 *db);
void creat_word_list(sqlite3 *db);
void user_register(MSG msg,sqlite3 *db,int sockfd);
void user_login(MSG msg, sqlite3 *db, int sockfd);
void do_get_table(sqlite3 *db);
void query_word(MSG msg,sqlite3 *db,int sockfd);
void history_word(MSG msg, sqlite3 *db, int sockfd);
MSG query_time(MSG msg);

void *pthread_fun(void *arg)
{
    MSG msg = *(MSG *)arg;
    int acceptfd = msg.acceptfd;
    struct sockaddr_in clientaddr = msg.clientaddr;

    //将子线程设置为分离态
    pthread_detach(pthread_self());

    //进行通信
    char buf[N] = {0};
    ssize_t bytes;
    sqlite3 *db1;
    sqlite3 *db2;

    while(1)
    {
       
        if(recv(acceptfd, &msg, sizeof(msg), 0) == -1)
        {
            ERRLOG("recv error");
        }
        switch(msg.code)
        {
            case 1:
                user_register(msg,db1,acceptfd);
                msg.code = 0;
                break;
            case 2:
                user_login(msg,db1,acceptfd);
                msg.code = 0;
                break; 
            case 3: 
                query_word(msg,db2,acceptfd);
                msg.code = 0;
                break;  
            case 4:
                history_word(msg,db2,acceptfd);
                msg.code = 0;
                break;
            default:
                break;
        }
    }
}

int main(int argc, char const *argv[])
{
    if(argc < 3)
    {
        fprintf(stderr, "Usage: %s <ip> <port>\n", argv[0]);
        exit(1);
    }

    int sockfd, acceptfd;
    struct sockaddr_in serveraddr;
    socklen_t addrlen = sizeof(struct sockaddr_in);
    struct sockaddr_in clientaddr;
    sqlite3 *db1;
    sqlite3 *db2;
    
    //创建套接字
    if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
    {
        ERRLOG("socket error");
    }

    //填充服务器网络信息结构体
    //htons:将主机字节序转化为网络字节序
    //atoi:将数字型字符串转化为整形数据
    //inet_addr:将点分十进制ip地址转化为32位整形数据
    serveraddr.sin_family = AF_INET;
    serveraddr.sin_addr.s_addr = inet_addr(argv[1]);
    serveraddr.sin_port = htons(atoi(argv[2]));

    //将套接字与服务器网络信息结构体绑定
    if(bind(sockfd, (struct sockaddr *)&serveraddr, addrlen) == -1)
    {
        ERRLOG("bind error");
    }

    //将套接字设置为被动监听状态
    if(listen(sockfd, 5) == -1)
    {
        ERRLOG("listen error");
    }

    //使用多线程实现TCP并发服务器
    pthread_t thread;
    MSG msg;

    //创建表
    creat_user_list(db1);
    creat_word_list(db2);

    while(1)
    {
        //阻塞等待客户端的连接
        if((acceptfd = accept(sockfd, (struct sockaddr *)&clientaddr, &addrlen)) == -1)
        {
            ERRLOG("accept error");
        }

        msg.acceptfd = acceptfd;
        msg.clientaddr = clientaddr;
        

        //只要有一个客户端与服务器连接,服务器就创建一个子线程与之通信
        if(pthread_create(&thread, NULL, pthread_fun, &msg) != 0)
        {
            ERRLOG("pthread_create error");
        }
    }

    return 0;
}

void creat_user_list(sqlite3 *db)
{
    
    if(sqlite3_open(DBFILE ,&db) != SQLITE_OK)
    {
        printf("error:%s\n",sqlite3_errmsg(db));
        exit(1);
    }

    char sql[128] = {0};
    char *errmsg;
    sprintf(sql, "create table %s(name text primary key, password text)", TABLE1);
    if(sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK)
    {
        printf("错误:%s\n", errmsg);
    }
    else 
    {
        printf("成功:用户表创建成功\n");
    }
}

void creat_word_list(sqlite3 *db)
{
    
    if(sqlite3_open(DBFILE ,&db) != SQLITE_OK)
    {
        printf("error:%s\n",sqlite3_errmsg(db));
        exit(1);
    }

    char sql[128] = {0};
    char *errmsg;
    sprintf(sql, "create table %s(name char, time char, word char)", TABLE2);
    if(sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK)
    {
        printf("错误:%s\n", errmsg);
    }

}

void user_register(MSG msg, sqlite3 *db, int sockfd)
{
    
    char sql[512] = {0};
    char *errmsg;

    if(sqlite3_open(DBFILE ,&db) != SQLITE_OK)
    {
        printf("error:%s\n",sqlite3_errmsg(db));
        exit(1);
    }
    sprintf(sql, "insert into %s values('%s', '%s')", TABLE1, msg.user_name,msg.user_password);
    if(sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK)
    {
        char buf[512];
        sprintf(buf,"register :user %s alredy exist!\n",msg.user_name);

        if(send(sockfd, buf, N, 0) == -1)
        {
            ERRLOG("send error");
        }
    }
    else 
    {
        char buf[12] = "register:OK";
        if(send(sockfd, buf, N, 0) == -1)
        {
            ERRLOG("send error");
        }
    }


}

void user_login(MSG msg, sqlite3 *db, int sockfd)
{
    
    char sql[512] = {0};
    char **ret;
    char *errmsg;
    int nrow, ncolumn;

    if(sqlite3_open(DBFILE ,&db) != SQLITE_OK)
    {
        printf("error:%s\n",sqlite3_errmsg(db));
        exit(1);
    }
    

    sprintf(sql, "select * from %s where name='%s' and password='%s'", TABLE1,msg.user_name,msg.user_password);

    if(sqlite3_get_table(db, sql, &ret, &nrow, &ncolumn, &errmsg) != SQLITE_OK)
    {
        
    }
    if (nrow == 0)
    {
        msg.code = 5;
        char buf[N] = "name or password is wrony!";
        if(send(sockfd, buf, N, 0) == -1)
        {
            ERRLOG("send error");
        }  
        if(send(sockfd, &msg, N, 0) == -1)
        {
            ERRLOG("send error");
        }
    }
    else
    {
        msg.code = 6;
        char buf[N] = "login success!";
        
        if(send(sockfd, buf, N, 0) == -1)
        {
            ERRLOG("send error");
        }
        
        if(send(sockfd, &msg, N, 0) == -1)
        {
            ERRLOG("send error");
        } 
    }
    
}

void query_word(MSG msg, sqlite3 *db, int sockfd)
{
    FILE *fp;
    char *errmsg;
	char temp[300] = {0};
    char explainbuf[512] = {0};
    char sql[512] = {0};
	char *p;
	int len, result;
    len = strlen(msg.word);
    
    if((fp = fopen("dict.txt", "r")) == NULL)
	{
		strcpy(msg.word, "dict can not open");
		send(sockfd, &msg, sizeof(MSG), 0);
	}

    while(fgets(temp, 300, fp) != NULL)
	{
		//比较单词
		result = strncmp(msg.word, temp, len);
		
		if(result == 0 && temp[len] == ' ')
        {
			//p保存单词后面第一个空格的首地址
			p = temp + len;
			
			//移动p,让p保存解释的第一个字符的首地址
			while(*p == ' ')
			{
				p++;
			}

            sprintf(explainbuf,"%s:%s",msg.word,p);
            if(send(sockfd, explainbuf, sizeof(explainbuf), 0) == -1)
            {
                ERRLOG("send error");
            }
			
			fclose(fp);

            msg = query_time(msg);

            if(sqlite3_open(DBFILE, &db) != SQLITE_OK)
            {
                printf("error:%s\n", sqlite3_errmsg(db));
                exit(1);
            }
            sprintf(sql, "insert into %s values( '%s', '%s', '%s')", TABLE2, msg.user_name, msg.timebuf, msg.word);
            if(sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK)
            {
                printf("错误:%s\n", errmsg);
            }
        }
	}
}

void history_word(MSG msg, sqlite3 *db, int sockfd)
{
    char *errmsg;
    char **ret;
    char sql[512] = {0};
    
    int nrow, ncolumn;
    int flag = 1;

    if(sqlite3_open(DBFILE, &db) != SQLITE_OK)
    {
        printf("error:%s\n", sqlite3_errmsg(db));
        exit(1);
    }
    sprintf(sql, "select *from %s where name='%s'", TABLE2, msg.user_name);
    
        if(sqlite3_get_table(db, sql, &ret, &nrow, &ncolumn, &errmsg) == SQLITE_OK)
        {
            int i, n = 4;
            for(i = 0; i < nrow; i++)
            {
                char buf[512] = {0};
                sprintf(buf,"%s : %s",ret[n],ret[n+1]);
                n = n+3;
                if (send(sockfd, buf, N, 0) == -1)
                {
                    ERRLOG("send error");
                }
            }
            char buf1[5] = "next";
            if (send(sockfd, buf1, sizeof(msg), 0) == -1)
                {
                    ERRLOG("send error");
                }    
        }   
}

MSG query_time(MSG msg)
{

    time_t mytime;
    mytime = time(NULL);//time函数获取到秒数
    
    //调用localtime函数进行tm结构体封装
    struct tm * mytm = localtime(&mytime);
    if(NULL == mytm)
    {
        perror("localtime");
    }

    sprintf(msg.timebuf,"%d-%d-%d %d:%d:%d  ",
    mytm->tm_year+1900,mytm->tm_mon+1,mytm->tm_mday,
    mytm->tm_hour,mytm->tm_min,mytm->tm_sec);

    return msg;
}