• C语言知识阶段性总结项目:电子词典


    项目需求

    1. 使用TCP实现客户端和服务端通信
    2. 使用sqlite存放用户信息
    3. 客户端需要有登录、注册、查询单词、账号查询记录功能
    4. 服务器需要实时显示在线用户

    解决方案

    1. 使用sqlite创建三个数据库,分别存放用户账号密码,单词表,用户查询记录
    2. 使用链表存放在线用户的信息,在子线程中循环遍历,达到实时显示在线用户的效果

    主要的功能代码

    头文件

    #ifndef MSQLITE_H
    #define MSQLITE_H
    #include "Client_list.h"
    
    
    //线程传参
    typedef struct msg
    {
    	ClistPtr C;
    	int cfd;
    	struct sockaddr_in caddr;
    } Msg_t;
     
    //用户信息结构体            
    typedef struct umsg             
    {    
    	char type;
    	char id[20];                 
    	char password[20];           
    } Umsg_t;                          
     
     //查询单词的结构体        
     typedef struct Word              
     {                         
         char word[20];        
         char mean[50];
    	 char time[20];
     } Word_t;   
    
    
    
    
    //打开电子词典库
    int Open_Dictdb(sqlite3* dictdb);
    
    //打开用户数据库
    int Open_Userdb(sqlite3* userdb);
    
    //打开历史记录库
    int Open_Histroy(sqlite3* histroy);
    
    //导入电子词典
    int Insert_Dict(sqlite3* dictdb);
    
    //判断用户登入注册
    int Connect_Event(sqlite3* userdb, sqlite3* histroy, Umsg_t usermsg, int cfd, ClistPtr C);
    
    //用户登入函数
    int User_Login(sqlite3* userdb, Umsg_t usermsg, int cfd, ClistPtr C);
    
    //用户注册函数
    int User_Register(sqlite3* userdb, Umsg_t usermsg, int cfd);
    
    //计算文件大小
    int Get_File_Line(char* file);
    
    //单词查找函数
    int Search_Word(Word_t word, int cfd, Umsg_t usermsg, sqlite3* dictdb, sqlite3* histroy);
    
    //查看历史记录
    int Show_History(sqlite3* histroy, Umsg_t usermsg, int cfd);
    
    
    #endif
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65

    函数实现

    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include "msqlite.h"
    
    
    
    
    #define LOG(s) printf("[%s] {%s:%d} %s \n", __DATE__, __FILE__, __LINE__, s);
    
    /*
    	函数功能:打开词典数据库
    	函数参数:词典数据库指针
    	返回值:成功返回0 失败返回-1
    */
    int Open_Dictdb(sqlite3* dictdb)
    {
    	int ret = -1;
    	//打开单词数据库
    
    	if(sqlite3_open("./dict.db", &dictdb) != SQLITE_OK)
    	{
    		fprintf(stderr, "{%s:%d} sqlite3_open failed\n", __FILE__, __LINE__);
    		return ret;
    	}
    
    	char sql[128] = "create table if not exists dict(word char, mean char);";
    	char* errmsg = NULL;
    	if(sqlite3_exec(dictdb, sql, NULL, NULL, &errmsg) != SQLITE_OK)
    	{
    		fprintf(stderr, "{%s:%d} sqlite3_exec:%s\n", __FILE__, __LINE__, errmsg);
    		return ret;
    	}
    
    
    
    	printf("[%s] Dictdb open success\n", __DATE__);	
    
    	ret = 0;
    	return ret;
    }
    
    /*
    	函数功能:打开用户数据库
    	函数参数:用户数据库指针
    	返回值:成功返回0 失败返回-1
    */
    int Open_Userdb(sqlite3* userdb)
    {
    	int ret = -1;
    
    	if(sqlite3_open("./user.db", &userdb) != SQLITE_OK)                                                
    	{                                                                                                  
    		fprintf(stderr, "{%s:%d} sqlite3_open failed\n", __FILE__, __LINE__);                                     
    		return 0;                                                                                   
    	}
    	char sql[128] = "create table if not exists user(id char PRIMARY KEY, password char);";
    	char* errmsg = NULL;
    	if(sqlite3_exec(userdb, sql, NULL, NULL, &errmsg) != SQLITE_OK)
    	{
    		fprintf(stderr, "{%s:%d} sqlite3_exec:%s\n", __FILE__, __LINE__, errmsg);
    		return ret;
    	}
    
    
    
    	ret = 0;
    	return ret;
    }
    
    /*
    	函数功能:打开历史记录数据库
    	函数参数:历史记录数据库指针
    	返回值:成功返回0 失败返回-1
    */
    int Open_Histroy(sqlite3* histroy)
    {
    	int ret = -1;
    
    	if(sqlite3_open("./histroy.db", &histroy) != SQLITE_OK)
    	{
    		fprintf(stderr, "{%s:%d} sqlite3_open failed\n", __FILE__, __LINE__);
    		return ret;
    	}
    
    	ret = 0;
    	return ret;
    }
    
    
    
    
    /*
    	函数功能:将电子词典文本导入电子词典数据库
    	函数参数:词典数据库指针
    	返回值:成功返回0 失败返回-1
    */
    int Insert_Dict(sqlite3* dictdb)
    {
    
    	if(sqlite3_open("./dict.db", &dictdb) != SQLITE_OK)
    	{
    		fprintf(stderr, "{%s:%d} sqlite3_open failed\n", __FILE__, __LINE__);
    		return -1;
    	}
    
    	char sql[128] = "create table if not exists dict(word char, mean char);";
    	char* errmsg = NULL;
    	if(sqlite3_exec(dictdb, sql, NULL, NULL, &errmsg) != SQLITE_OK)
    	{
    		fprintf(stderr, "{%s:%d} sqlite3_exec:%s\n", __FILE__, __LINE__, errmsg);
    		return -1;
    	}
    
    	FILE* fp_r;
    	char word[64] = "";
    	char mean[64] = "";
    	char buf[128] = "";
    	int count = 0;
    
    	if((fp_r = fopen("./dict.txt", "r")) == NULL)
    	{
    		LOG("fopen error");
    		return -1;
    	}
    
    	//获取文件行数
    	int size = Get_File_Line("./dict.txt");
    
    	printf("词典正在录入。。。\n");
    	while(1)
    	{
    		bzero(buf, sizeof(buf));
    		bzero(mean, sizeof(mean));
    		bzero(word, sizeof(word));
    
    		if(size == count++)
    			break;
    		if(fgets(buf, sizeof(buf), fp_r) == NULL)
    		{
    			LOG("fgets error");
    			return -1;
    		}
    		buf[strlen(buf)-1] = 0;
    
    		//词,义分离的判断逻辑
    		int flag = 0;
    		for(int i = 0; i < strlen(buf); i++)
    		{
    			if(buf[i] == ' ' && 0 == flag)
    			{
    				strncpy(word, buf, i+1);
    				word[strlen(word)-1] = 0;
    				flag = 1;
    			}
    
    			if(buf[i] != ' ' && 1 == flag)
    			{
    				strcpy(mean, &buf[i]);
    				break;
    			}
    
    		}
    
    		char sql[128] = "";
    		sprintf(sql, "insert into dict values (\"%s\", \"%s\");", word, mean);
    		char* errmsg = NULL;
    		if(sqlite3_exec(dictdb, sql, NULL, NULL, &errmsg) != SQLITE_OK)
    		{
    			fprintf(stderr, "{%s:%d} sqlite3_exec:%s\n",__FILE__, __LINE__, errmsg);
    			perror("sqlite3_exec");
    			return -1;
    		}
    
    	}
    
    	printf("词典录入完成\n");
    
    	return 0;
    }
    
    
    /*
    	函数功能:客户端连接事件
    	函数参数:用户库指针,历史记录库指针,用户信息结构体,与客户端通信的文件描述符,用户链表头节点指针
    	返回值:触发事件返回1 反之返回0
    */
    int Connect_Event(sqlite3* userdb, sqlite3* histroy, Umsg_t usermsg, int cfd, ClistPtr C)
    {
    
    	if(usermsg.type == 'L')
    	{
    		return User_Login(userdb, usermsg, cfd, C);
    	}
    	else if(usermsg.type == 'R')
    	{
    		return User_Register(userdb, usermsg, cfd);
    	}
    
    	return 0;
    }
    
    
    /*
    	函数功能:客户端登录事件
    	函数参数:用户库指针,用户信息结构体,与客户端通信文件描述符,用户信息链表头指针
    	返回值:成功返回1 失败返回-1
    */
    int User_Login(sqlite3* userdb, Umsg_t usermsg, int cfd, ClistPtr C)
    {
    	int ask = -1;//应答标志
    
    	if(sqlite3_open("./user.db", &userdb) != SQLITE_OK)                                                
    	{                                                                                                  
    		fprintf(stderr, "{%s:%d} sqlite3_open failed\n", __FILE__, __LINE__);                                     
    		return -1;                                                                                   
    	}
    	char sql[128] = "create table if not exists user(id char, password char);";
    	char* errmsg = NULL;
    	if(sqlite3_exec(userdb, sql, NULL, NULL, &errmsg) != SQLITE_OK)
    	{
    		fprintf(stderr, "{%s:%d} sqlite3_exec:%s\n", __FILE__, __LINE__, errmsg);
    		return -1;
    	}
    	char cmp[128] = "";
    	sprintf(cmp,"SELECT * FROM user WHERE id like \"%s\" AND password like \"%s\"",usermsg.id,usermsg.password);
    	char ** pres = NULL;
    	int row,column; 
    	if(sqlite3_get_table(userdb, cmp, &pres, &row, &column, &errmsg) != SQLITE_OK)
    	{
    		fprintf(stderr, "{%s:%d} sqlite3_get_table:%s\n", __FILE__, __LINE__, errmsg);
    		return -1;
    	}
    
    	ClistPtr p;
    	//判断用户状态
    	//重复登陆
    	if((p = List_Search_User(C, usermsg.id)))
    	{	
    		ask = 5;
    		if(send(cfd, &ask, sizeof(ask), 0) < 0)
    		{				
    			LOG("send");
    			return -1;
    		}
    		printf("%s用户重复登录\n",usermsg.id);
    		return -1;
    
    	}
    	//未登录
    	else if(row == 1)
    	{
    		ask = 1;
    		if(send(cfd, &ask, sizeof(ask), 0) < 0)
    		{
    			LOG("send");
    			return -1;
    		}
    		printf("%s用户登入成功\n",usermsg.id);
    		sqlite3_free_table(pres);
    		pres = NULL;
    		return 1;
    	}
    	//登录失败
    	else
    	{
    		if(send(cfd, &ask, sizeof(ask), 0) < 0)
    		{
    			LOG("send");
    			return -1;
    		}
    		return -1;
    	}
    
    	sqlite3_free_table(pres);
    	pres = NULL;
    
    	return -1;
    }
    
    /*
    	函数功能:客户端注册事件
    	函数参数:用户库指针,用户信息结构体,与客户端通信文件描述符
    	返回值:成功返回1 失败返回-1
    */
    int User_Register(sqlite3* userdb, Umsg_t usermsg, int cfd)
    {
    	if(sqlite3_open("./user.db", &userdb) != SQLITE_OK)                                                
    	{                                                                                                  
    		fprintf(stderr, "{%s:%d} sqlite3_open failed\n", __FILE__, __LINE__);                                     
    		return -1;                                                                                   
    	}
    	char sql[128] = "create table if not exists user(id char PRIMARY KEY, password char);";
    	char* errmsg = NULL;
    	if(sqlite3_exec(userdb, sql, NULL, NULL, &errmsg) != SQLITE_OK)
    	{
    		fprintf(stderr, "{%s:%d} sqlite3_exec\n", __FILE__, __LINE__);
    		perror("");
    		return -1;
    	}
    
    	int ask = -1;//应答标志
    	char msg[128] = "";
    	sprintf(msg, "insert into user values (\"%s\",\"%s\");", usermsg.id, usermsg.password);
    	if(sqlite3_exec(userdb, msg, NULL, NULL, &errmsg) != SQLITE_OK)
    	{	
    		fprintf(stderr, "{%s:%d} sqlite3_exec:", __FILE__, __LINE__);
    		perror("");
    		if(send(cfd, &ask, sizeof(ask), 0) < 0)
    		{
    			LOG("send");
    			return -1;
    		}
    		return -1;
    	}
    	/*
    	char cmp[128] = "";
    	sprintf(cmp,"SELECT * FROM user WHERE id like \"%s\" AND password like \"%s\";",usermsg.id,usermsg.password);
    	char ** pres = NULL;
    	int row,column; 
    	if(sqlite3_get_table(userdb, cmp, &pres, &row, &column, &errmsg) != SQLITE_OK)
    	{
    		fprintf(stderr, "{%s:%d} sqlite3_get_table:%s\n", __FILE__, __LINE__, errmsg);
    		return -1;
    	}
    	*/
    	ask = 1;
    	if(send(cfd, &ask, sizeof(ask), 0) < 0)
    	{
    		LOG("send");
    		return -1;
    	}
    	printf("%s用户注册成功\n",usermsg.id);
    
    	return 1;
    }
    
    
    
    /*
    	函数功能:计算文件行数
    	函数参数:文件路径
    	返回值:成功返回文件行数 失败返回-1
    */
    int Get_File_Line(char* file)
    {
    	int ret = -1;
    	int line = 0;
    	int ch;
    	FILE * path;
    	path = fopen(file, "r+");
    	if (NULL == path)
    	{
    		LOG("open file error");
    		return  ret; //文件大小不可能为负数
    	}
    	while((ch = fgetc(path)) != EOF)
    	{
    		if(ch == '\n')
    		{
    			line++;
    		}
    	}
    
    	return (ret = line);
    }
    
    
    /*
    	函数功能:服务器查询单词功能
    	函数参数:单词结构体,通信文件描述符,用户信息结构体,单词库,历史记录库
    	返回值:成功返回0 失败返回-1
    */
    int Search_Word(Word_t word, int cfd, Umsg_t usermsg, sqlite3* dictdb, sqlite3* histroy)
    {
    	int ret = -1;
    	if(sqlite3_open("./dict.db", &dictdb) != SQLITE_OK)
    	{
    		fprintf(stderr, "{%s:%d} sqlite3_open failed\n", __FILE__, __LINE__);
    		return ret;
    	}
    
    	char sql[128] = "create table if not exists dict(word char, mean char);";
    	char* errmsg = NULL;
    	if(sqlite3_exec(dictdb, sql, NULL, NULL, &errmsg) != SQLITE_OK)
    	{
    		fprintf(stderr, "{%s:%d} sqlite3_exec:%s\n", __FILE__, __LINE__, errmsg);
    		return ret;
    	}
    
    	if(sqlite3_open("./histroy.db", &histroy) != SQLITE_OK)
    	{
    		fprintf(stderr, "{%s:%d} sqlite3_open failed\n", __FILE__, __LINE__);
    		return ret;
    	}
    
    	bzero(sql, sizeof(sql));
    	sprintf(sql, "create table if not exists %s(word char, mean char, time char);", usermsg.id);
    	if(sqlite3_exec(histroy, sql, NULL, NULL, &errmsg) != SQLITE_OK)
    	{
    		fprintf(stderr, "{%s:%d} sqlite3_exec:\n", __FILE__, __LINE__);
    		perror("");
    		return ret;
    	}
    
    	//查询单词和解释是否在数据库中
    	char cmp[128] = "";
    
    	sprintf(cmp,"SELECT * FROM dict WHERE word like \"%s\" OR mean like \" %s \"",word.word,word.mean);
    
    	char ** pres = NULL;
    	int row,column;  
    	if(sqlite3_get_table(dictdb, cmp, &pres, &row, &column, &errmsg) != SQLITE_OK)
    	{
    		fprintf(stderr, "{%s:%d} sqlite3_get_table:%s\n", __FILE__, __LINE__, errmsg);
    		return ret;
    	}
    
    	if(row == 0)
    	{
    		strcpy(word.mean, "未查询到此单词,请重试");
    	}
    	else
    	{
    		bzero(&word,sizeof(word));
    		strcpy(word.word,pres[2]);
    		strcpy(word.mean,pres[3]);
    
    		time_t t;
    		struct tm *info = NULL;
    		char timenow[128] = "";
    		t = time(NULL);
    		info = localtime(&t);
    		sprintf(timenow, "[%d-%02d-%02d] %02d:%02d:%02d",\
    				info->tm_year+1900, \
    				info->tm_mon+1, \
    				info->tm_mday,\
    				info->tm_hour, \
    				info->tm_min, \
    				info->tm_sec);
    
    		//将单词存入历史记录表
    		char sql[128] = "";
    		bzero(sql,sizeof(sql));
    		sprintf(sql, "insert into %s values(\"%s\",\"%s\",\"%s\");", usermsg.id, pres[2], pres[3], timenow);
    		if(sqlite3_exec(histroy, sql, NULL, NULL, &errmsg) != SQLITE_OK)
    		{
    			fprintf(stderr, "{%s:%d} sqlite3_exec:%s\n", __FILE__, __LINE__, errmsg);
    			return ret;
    		}
    	}
    
    	//发送查询结果
    	if(send(cfd, &word, sizeof(word), 0) < 0)
    	{
    		LOG("send");
    		return ret;
    	}
    
    	ret = 0;
    
    	return ret;
    }
    
    
    /*
    	函数功能:服务器查询用户历史查询记录
    	函数参数:历史记录库,用户信息结构体,通信文件描述符
    	返回值:成功返回0 失败返回-1
    */
    int Show_History(sqlite3* histroy, Umsg_t usermsg, int cfd)
    
    {
    	char cmp[128] = "";
    	Word_t word;
    	if(sqlite3_open("./histroy.db", &histroy) != SQLITE_OK)
    	{
    		fprintf(stderr, "{%s:%d} sqlite3_open failed\n", __FILE__, __LINE__);
    		return -1;
    	}
    	sprintf(cmp,"SELECT * FROM %s;", usermsg.id);
    
    	char* errmsg = NULL;
    	char ** pres = NULL;
    	int row,column;
    	if(sqlite3_get_table(histroy, cmp, &pres, &row, &column, &errmsg) != SQLITE_OK)
    	{
    		fprintf(stderr, "{%s:%d} sqlite3_get_table:%s\n", __FILE__, __LINE__, errmsg);
    		return -1;
    	}
    
    	//遍历数据库中的指定表,分次发向客户端
    	if(row > 0)
    	{	//printf("__%s__ __ %d__ __%d__\n", __FILE__, __LINE__, row);
    		for(int i = 3; i <= row*column; i+=3)
    		{
    			strcpy(word.word, pres[i]);
    			strcpy(word.mean, pres[i+1]);
    			strcpy(word.time, pres[i+2]);
    
    			//printf("%s\t%s\t%s\n", pres[i], pres[i+1], pres[i+2]);
    
    			if(send(cfd, &word, sizeof(word), 0) < 0)
    			{
    				LOG("send");
    				return -1;
    			}
    		}
    		strcpy(word.mean, "over");
    		if(send(cfd, &word, sizeof(word), 0) < 0)
    		{
    			LOG("send");
    			return -1;
    		}
    		return 1;
    	}
    	else
    	{	
    		strcpy(word.mean, "暂无历史记录");
    		if(send(cfd, &word, sizeof(word), 0) < 0)
    		{
    			LOG("send");
    			return -1;
    		}
    	}
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264
    • 265
    • 266
    • 267
    • 268
    • 269
    • 270
    • 271
    • 272
    • 273
    • 274
    • 275
    • 276
    • 277
    • 278
    • 279
    • 280
    • 281
    • 282
    • 283
    • 284
    • 285
    • 286
    • 287
    • 288
    • 289
    • 290
    • 291
    • 292
    • 293
    • 294
    • 295
    • 296
    • 297
    • 298
    • 299
    • 300
    • 301
    • 302
    • 303
    • 304
    • 305
    • 306
    • 307
    • 308
    • 309
    • 310
    • 311
    • 312
    • 313
    • 314
    • 315
    • 316
    • 317
    • 318
    • 319
    • 320
    • 321
    • 322
    • 323
    • 324
    • 325
    • 326
    • 327
    • 328
    • 329
    • 330
    • 331
    • 332
    • 333
    • 334
    • 335
    • 336
    • 337
    • 338
    • 339
    • 340
    • 341
    • 342
    • 343
    • 344
    • 345
    • 346
    • 347
    • 348
    • 349
    • 350
    • 351
    • 352
    • 353
    • 354
    • 355
    • 356
    • 357
    • 358
    • 359
    • 360
    • 361
    • 362
    • 363
    • 364
    • 365
    • 366
    • 367
    • 368
    • 369
    • 370
    • 371
    • 372
    • 373
    • 374
    • 375
    • 376
    • 377
    • 378
    • 379
    • 380
    • 381
    • 382
    • 383
    • 384
    • 385
    • 386
    • 387
    • 388
    • 389
    • 390
    • 391
    • 392
    • 393
    • 394
    • 395
    • 396
    • 397
    • 398
    • 399
    • 400
    • 401
    • 402
    • 403
    • 404
    • 405
    • 406
    • 407
    • 408
    • 409
    • 410
    • 411
    • 412
    • 413
    • 414
    • 415
    • 416
    • 417
    • 418
    • 419
    • 420
    • 421
    • 422
    • 423
    • 424
    • 425
    • 426
    • 427
    • 428
    • 429
    • 430
    • 431
    • 432
    • 433
    • 434
    • 435
    • 436
    • 437
    • 438
    • 439
    • 440
    • 441
    • 442
    • 443
    • 444
    • 445
    • 446
    • 447
    • 448
    • 449
    • 450
    • 451
    • 452
    • 453
    • 454
    • 455
    • 456
    • 457
    • 458
    • 459
    • 460
    • 461
    • 462
    • 463
    • 464
    • 465
    • 466
    • 467
    • 468
    • 469
    • 470
    • 471
    • 472
    • 473
    • 474
    • 475
    • 476
    • 477
    • 478
    • 479
    • 480
    • 481
    • 482
    • 483
    • 484
    • 485
    • 486
    • 487
    • 488
    • 489
    • 490
    • 491
    • 492
    • 493
    • 494
    • 495
    • 496
    • 497
    • 498
    • 499
    • 500
    • 501
    • 502
    • 503
    • 504
    • 505
    • 506
    • 507
    • 508
    • 509
    • 510
    • 511
    • 512
    • 513
    • 514
    • 515
    • 516
    • 517
    • 518
    • 519
    • 520
    • 521
    • 522
    • 523
    • 524
    • 525
    • 526
    • 527
    • 528
    • 529
    • 530
    • 531

    链表头文件

    #ifndef _CLIENT_LIST_H_
    #define _CLIENT_LIST_H_
    
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    
    //存储用户信息的链表节点
    typedef struct node
    {
    	union
    	{
    		struct sockaddr_in caddr;
    		int len;
    	};
    	char id[20];
    	struct node* next;
    } Clist, *ClistPtr;
    
    //创建头结点
    ClistPtr List_Create();
    
    //链表判空
    int  List_Empty(ClistPtr C);
    
    //创建普通节点
    ClistPtr Node_Buy(struct sockaddr_in caddr, char* id);
    
    //头插
    void List_Insert_Head(ClistPtr C, struct sockaddr_in caddr, char* id);
    
    
    //删除节点
    void List_Delete(ClistPtr C, struct sockaddr_in caddr);
    
    
    //销毁链表
    void List_Free(ClistPtr *C);
    
    //查找用户
    ClistPtr List_Search_User(ClistPtr C, char* id);
    
    
    #endif
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63

    链表函数实现

    #include "Client_list.h"
    
    #define LOG(s) printf("[%s] {%s:%d} %s \n", __DATE__, __FILE__, __LINE__, s);
    
    
    /*
       函数功能:在堆区申请一个链表节点
       函数参数:void
       函数返回值:申请失败:NULL  申请成功:空间地址
    */
    ClistPtr List_Create()
    {
    	//在堆区申请一个头结点类型
    	ClistPtr C = (ClistPtr)malloc(sizeof(Clist));
    	if(NULL == C)
    	{
    		LOG("malloc memory file!");
    		return NULL;
    	}
    
    	//创建成功,对节点初始化
    	C->len = 0; 	//初始化链表长度为0
    	C->next = NULL; //链表上没有任何节点
    
    	puts("list create compelet!");
    	return C;
    }
    
    /*
       函数功能:判断链表是否为空
       函数参数:头结点地址
       函数返回值:传参异常:-1  为空:1
    */
    int  List_Empty(ClistPtr C)
    {
    	//判断逻辑
    	if(NULL == C)
    	{
    		LOG("malloc memory file!");
    		return -1;
    	}
    
    	//判断指针域的内容
    	return C->next == NULL && C->len == 0;
    }
    
    /*
       函数功能:创建普通节点
       函数参数:客户端地址信息结构体,用户ID
       函数返回值:申请失败:NULL   成功:节点地址
    */
    ClistPtr Node_Buy(struct sockaddr_in caddr, char* id)
    
    {
    	//在堆区申请节点
    	ClistPtr P = (ClistPtr)malloc(sizeof(Clist));
    	if(NULL == P)
    	{
    		LOG("malloc memory file!");
    		return NULL;
    	}
    
    	//节点申请成功,将数据封装进去
    	P->caddr = caddr;
    	strcpy(P->id, id);
    	P->next = NULL;
    
    	return P;
    }
    
    /*
       函数功能:链表头插
       函数参数:头结点地址,客户地址信息结构体,用户ID
       函数返回值:无
     */
    void List_Insert_Head(ClistPtr C, struct sockaddr_in caddr, char* id)
    
    {
    	//判断逻辑
    	if(NULL == C)
    	{
    		LOG("malloc memory file!");
    		return ;
    	}
    
    	//创建节点并封装数据
    	ClistPtr P = Node_Buy(caddr, id);
    	if(NULL == P)
    	{
    		LOG("malloc memory file!");
    		return ;
    	}
    	//插入逻辑
    	P->next = C->next;
    	C->next = P;
    
    	//表格变化
    	C->len++;
    }
    
    /*
       函数功能:节点删除
       函数参数:头结点地址,客户端地址信息结构体
       函数返回值:无
    */
    void List_Delete(ClistPtr C, struct sockaddr_in caddr)
    {
    	if(NULL == C || List_Empty(C))
    	{
    		LOG("memory error!");
    		return;
    	}
    
    	ClistPtr q = C;
    	ClistPtr p = NULL;
    
    	//查询要删除的节点
    	while(q->next != NULL)
    	{	
    		if(!memcmp(&q->next->caddr, &caddr, sizeof(caddr)))
    		{
    			break;
    		}
    		q = q->next;
    	}
    
    
    	//删除逻辑
    	p = q->next;
    	q->next = q->next->next;
    	p->next = NULL;
    	free(p);
    	p = NULL;
    
    	C->len--;
    }
    
    
    /*
       函数功能:链表销毁
       函数参数:头结点指针地址
       函数返回值:无
    */
    void List_Free(ClistPtr *C)
    {
    	//判断逻辑
    	if(NULL == C || NULL == *C)
    	{
    		LOG("memory error!");
    		return;
    	}
    
    	ClistPtr q = *C;
    
    	while(*C != NULL)
    	{
    		q = q->next;
    		free(*C);
    		*C = q;
    	}
    
    	puts("list free");
    }
    
    /*
       函数功能:查询用户节点
       函数参数:头结点地址,用户ID
       函数返回值:成功返回用户节点地址,失败返回NULL
    */
    ClistPtr List_Search_User(ClistPtr C, char* id)
    {
    	ClistPtr q = C->next;
    	for(int i=1; i<=C->len; i++)
    	{
    		if(strcmp(q->id,id))
    		{
    			q = q ->next;
    		}
    		else
    		{
    			return q;
    		}
    	}
    
    	return NULL;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186

    客户端功能头文件

    #ifndef __CLIENT_H__
    #define __CLIENT_H__
     
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include "server.h"
    
     
    //登入注册界面
    int Menu(int client);
     
    //向服务器发送用户登入申请
    int Login(int client);
     
    //向服务器发送用户注册申请
    int Register(int client);
    
    //查询单词功能
    int Search(int client);
    
    //查询历史记录功能
    int History(int client);
    
     
    #endif
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    客户端功能实现

    #include "client.h"
    #define LOG(s) printf("[%s] {%s:%d} %s \n", __DATE__, __FILE__, __LINE__, s);
    Umsg_t usermsg;
    
    
    //登录注册界面
    int Menu(int client)
    {
    	int ret;
    		while(1)
    		{	
    			system("clear");
    				printf("-----------1.登入------------\n");
    				printf("-----------2.注册------------\n");
    				printf("-----------3.退出------------\n");
    				
    				
    				char choose; //存储选择的序号
    			printf("请选择:");
    				scanf("%c",&choose);
    				while(getchar() != 10);
    					
    						switch(choose)
    						{
    						case '1':
    								 ret = Login(client);
    									 return ret;
    									 break;
    						case '2':
    								 ret = Register(client);
    									 return ret;
    									 break;
    						case '3':
    								 return 1;
    						default:
    								printf("输入错误,请重新输入\n");
    						}
    			printf("输入任意字符清屏>>>");
    				while(getchar() != 10);
    					
    		}	
    	return ret;
    }
    
    
    /*
    函数功能:客户端登录
    函数参数:客户端文件描述符
    返回值:登录成功返回0,失败返回-1
    */
    int Login(int client)
    {
    	while(1)
    	{
    		printf("------登录------\n");
    			//填入账号密码数据
    			usermsg.type = 'L';
    			printf("请输入账号>>>");
    			scanf("%s",usermsg.id);
    			while(getchar() != 10);
    				printf("请输入密码>>>");
    					scanf("%s",usermsg.password);
    					while(getchar() != 10);
    						
    							system("clear");
    							printf("登陆中。。。");
    							//发送给服务器
    							if(send(client, &usermsg , sizeof(usermsg), 0) < 0)
    							{
    								LOG("send");
    									return -1;
    							}
    		
    			//接受服务器发来的确认信息	
    			int flag;
    			ssize_t res;
    			res = recv(client, &flag, sizeof(flag), 0);
    			//printf("{%s:%d} flag = %d\n", __FILE__, __LINE__, flag);
    			if(res < 0)
    			{
    				LOG("recv");
    					return -1;
    			}
    			else if(0 == res)
    			{
    				return -1;
    			}
    		
    			system("clear");
    			
    			//判断服务器发来的确认信息 1为成功,-1为失败(数据错误)
    			if(flag == 5)
    			{
    				printf("重复登录\n");
    			}
    			else if(flag == 1)
    			{
    				printf("登入成功\n");
    					break;
    			}
    			else if(flag == -1)
    			{
    				printf("用户账号密码错误\n");
    			}
    		
    	}
    	return 0;
    }
    
    /*
    函数功能:客户端注册
    函数参数:客户端文件描述符
    返回值:注册成功返回0,失败返回-1
    */
    int Register(int client)
    {
    	printf("------注册------\n");
    		while(1)
    		{
    			//填入要注册账号密码数据
    			usermsg.type = 'R';
    				printf("请输入注册账号:");
    				scanf("%s",usermsg.id);
    				while(getchar() != 10);
    					printf("请输入注册密码:");
    						scanf("%s",usermsg.password);
    						while(getchar() != 10);
    							
    								//发送给服务器
    								if(send(client, &usermsg , sizeof(usermsg), 0) < 0)
    								{
    									LOG("send");
    										return -1;
    								}
    			
    				//接受服务器发来的确认信息	
    				int flag;
    				ssize_t res;
    				res = recv(client, &flag, sizeof(flag), 0);
    				if(res < 0)
    				{
    					LOG("recv");
    						return -1;
    				}
    				else if(0 == res)
    				{
    					printf("server is off-line\n");
    						return -1;
    				}
    			
    				//判断服务器发来的确认信息 1为成功,-1为失败(数据错误)
    				if(flag == 1)
    				{
    					printf("注册成功\n");
    						break;
    				}
    				else if(flag < 0)
    				{
    					printf("注册失败,重复注册\n");
    				}
    		}
    	return 0;
    }
    
    /*
    函数功能:客户端单词查询
    函数参数:客户端文件描述符
    返回值:查询成功返回0,失败返回-1
    */
    int Search(int client)
    {
    	//查询单词操作
    	char buf[128] = "";
    	ssize_t res = 0;
    	Word_t words;
    		usermsg.type = 'S';
    		//发送给服务器
    		if(send(client, &usermsg , sizeof(usermsg), 0) < 0)
    		{
    			LOG("send");
    				return -1;
    		}
    	system("clear");
    		
    		
    		while(1)
    		{		
    			//发送功能
    			bzero(&words,sizeof(words));
    			bzero(buf, sizeof(buf));
    	
    			printf("请输入要查询的单词>>>");
    				fgets(buf, sizeof(buf), stdin);
    			buf[strlen(buf)-1] = 0;
    			strcpy(words.word,buf); 
    				
    				if(send(client, &words, sizeof(words), 0) < 0)
    				{
    					LOG("send");
    					return -1;
    				}
    			system("clear");
    
    			//接收功能 
    			bzero(&words, sizeof(words));
    			res = recv(client, &words, sizeof(words), 0);
    				if(res < 0)
    				{
    					LOG("recv");
    					return -1;
    				}
    				else if(0 == res)
    				{
    					printf("服务器已掉线\n");
    					break;
    				}
    			
    				printf("%s\t%s\n", words.word, words.mean);
    		}
    	
    		return 0;
    }
    
    /*
    函数功能:客户端历史记录查询
    函数参数:客户端文件描述符
    返回值:查询成功返回0,失败返回-1
    */
    int History(int client)
    {
    	Word_t word;
    	usermsg.type = 'H';
    
    		//命令发送
    		if(send(client, &usermsg , sizeof(usermsg), 0) < 0)
    		{
    			LOG("send");
    				return -1;
    		}
    	system("clear");
    
    		//接收功能
    		while(1)
    		{
    			bzero(&word, sizeof(word));
    				int res = recv(client, &word, sizeof(word), 0);
    				if(res < 0)
    				{
    					LOG("recv");
    					return -1;
    				}
    				else if(0 == res)
    				{
    					printf("服务器已掉线\n");
    					return -1;
    				}
    			if(!strcmp(word.mean, "over"))break;
    				printf("%s\t%s\t\t%s\n", word.word, word.mean, word.time);
    		}
    	printf("输入任意字符清屏>>>");
    		while(getchar() != 10);
    			system("clear");
    				return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264
    • 265

    客户端main函数

    #include "client.h"
    #include 
    
    #define PORT 8888                                    
    #define IP  "192.168.114.73"  
    #define LOG(s) printf("[%s] {%s:%d} %s \n", __DATE__, __FILE__, __LINE__, s);
    int main(int argc, const char *argv[])
    {
    
    	//创建流式套接字
    	int cfd = socket(AF_INET, SOCK_STREAM, 0);
    	if(cfd < 0)
    	{
    		LOG("socket");
    		return -1;
    	}
    	printf("create socket success\n");
    
    
    
    	//填充要连接的服务器的地址信息结构体
    	struct sockaddr_in saddr;
    	saddr.sin_family 		= AF_INET;
    	saddr.sin_port 		= htons(PORT);
    	saddr.sin_addr.s_addr = inet_addr(IP);
    
    	//连接服务器 connect
    	if(connect(cfd, (struct sockaddr*)&saddr, sizeof(saddr)) < 0)
    	{
    		LOG("connect");
    		return -1;
    	}
    
    	int ret = 0;
    	while(1)
    	{
    		ret = Menu(cfd);
    
    		if(ret== 0)
    		{
    			printf("connect success\n");
    		}
    		else if(ret == -1)
    		{
    			printf("服务器掉线\n");
    			return -1;
    		}
    		else
    		{
    			return -1;
    		}
    
    		while(1)
    		{
    			system("clear");
    			printf("-----------1.查单词------------\n");
    			printf("-----------2.历史记录----------\n");
    
    
    			char choose; //存储选择的序号
    			printf("请选择:");
    			scanf("%c",&choose);
    			while(getchar() != 10);
    
    			switch(choose)
    			{
    			case '1':
    				Search(cfd);
    				break;
    			case '2':
    				History(cfd);
    				break;
    			default:
    				printf("输入错误,请重新输入\n");
    				break;
    			}
    			printf("输入任意字符清屏>>>");
    			while(getchar() != 10);
    
    		}	
    
    	}	
    
    	//关闭套接字
    	close(cfd);
    
    	return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89

    服务器功能函数

    #ifndef SERVER_H
    #define SERVER_H
     
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include "msqlite.h"
    #include "Client_list.h"
    
    #define LOG(s) printf("[%s] {%s:%d} %s \n", __DATE__, __FILE__, __LINE__, s);
     
                         
                               
     
     
    //循环打印已有客户端的线程
    void* loop_printf(void* arg);
    
    //遍历链表
    void list_show(ClistPtr C);
     
    
    #endif
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    服务器函数实现

    #include "server.h"
    
    
    //循环打印已有客户端的线程                                                                             
    void* loop_printf(void* arg)                                                                           
    {                                                                                                      
    	ClistPtr C = arg;                                                                                 
    
    	pthread_detach(pthread_self());                                                                    
    	while(1)                                                                                           
    	{                                                                                                  
    		system("clear");                                                                               
    		list_show(C);                                                                                  
    		sleep(3);                                                                                      
    	}                                                                                                  
    
    	pthread_exit(NULL);                                                                                
    }                                                                                                      
    
    //遍历链表,终端输出客户端信息
    void list_show(ClistPtr C)
    {
    	time_t t;
    	struct tm *info = NULL;
    	char timenow[128] = "";
    	t = time(NULL);
    	info = localtime(&t);
    	sprintf(timenow, "[%d-%02d-%02d] %02d:%02d:%02d",\
    			info->tm_year+1900, \
    			info->tm_mon+1, \
    			info->tm_mday,\
    			info->tm_hour, \
    			info->tm_min, \
    			info->tm_sec);
    
    	//判断逻辑
    	if( NULL == C || List_Empty(C) )
    	{
    		printf("时间: %s\t暂无用户\n", timenow);
    		return;
    	}
    
    	//遍历逻辑
    	printf("时间: %s\t在线用户个数%d:\n",timenow, C->len);
    	ClistPtr q = C->next;
    	while(q != NULL)
    	{
    		printf("IP: %s\t|\tPort: %d\t|\tId: %s\n", inet_ntoa(q->caddr.sin_addr), ntohs(q->caddr.sin_port), q->id);
    		q = q->next;
    	}
    	printf("\n");
    }
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54

    服务器主函数

    #include "server.h"
    
    #define PORT 8888 				//1024~49151
    #define IP 	"192.168.114.73" 	//本机IP,用ifconfig查看
    
    #define LOG(s) printf("[%s] {%s:%d} %s \n", __DATE__, __FILE__, __LINE__, s);
    
    //回调函数                                                                                         
    void* Rcv_Msg(void* arg)                                         
    {                                                                                                      
    	//分离分支线程                                                                                     
    	pthread_detach(pthread_self());                                                                    
    	sqlite3* userdb;
    	sqlite3* histroy;
    	sqlite3* dictdb;
    	int cfd = (*(Msg_t*)arg).cfd;                                                             
    	struct sockaddr_in caddr = (*(Msg_t*)arg).caddr;                                                                                                                                                        
    	ClistPtr C = (*(Msg_t*)arg).C;                                                               
    
    	Umsg_t usermsg;                                                                           
    
    
    	while(1)
    	{
    		ssize_t res;
    		bzero(&usermsg, sizeof(usermsg));
    		res = recv(cfd, &usermsg, sizeof(usermsg), 0);                                                                     
    		if(res < 0)                                                                                                 
    		{                                                                                                           
    			LOG("recv");                                                                                        
    			return NULL;                                                                                       
    		}                                                                                                           
    		else if(0 == res)                                                                                           
    		{                                                                                                           
    			printf("[%s] [%s / %d] client: %d 客户端离线\n", __DATE__, inet_ntoa(caddr.sin_addr), ntohs(caddr.sin_port), cfd);
    			close(cfd);
    			pthread_exit(NULL);
    			return NULL;
    		}                                                                                                           
    
    		if( ( Connect_Event(userdb, histroy, usermsg, cfd, C)) == 1)
    		{
    			break;	
    		}
    	}
    
    	List_Insert_Head(C , caddr, usermsg.id);
    
    	while(1)
    	{
    		ssize_t res;
    		bzero(&usermsg, sizeof(usermsg));
    		res = recv(cfd, &usermsg, sizeof(usermsg), 0);
    		if(res < 0)                                                                                                 
    		{                                                                                                           
    			LOG("recv");                                                                                        
    			return NULL;                                                                                       
    		}                                                                                                           
    		else if(0 == res)                                                                                           
    		{                                                                                                           
    			printf("[%s] [%s / %d] client: %d 客户端离线\n", __DATE__, inet_ntoa(caddr.sin_addr), ntohs(caddr.sin_port), cfd);
    			List_Delete(C, caddr);
    			close(cfd);
    			pthread_exit(NULL);
    			return NULL;
    		}
    
    		if(usermsg.type == 'H')
    		{
    			Show_History(histroy, usermsg, cfd);
    			continue;
    		}
    		else if(usermsg.type == 'S')
    		{
    			Word_t words;
    			char buf[128] = "";
    			while(1)
    			{
    				bzero(&words,sizeof(words));
    				bzero(buf, sizeof(buf));
    				//循环接收 
    				res = recv(cfd, &words, sizeof(words), 0);
    				if(res < 0)
    				{
    					LOG("recv");
    					break;
    				}
    				else if(0 == res)
    				{
    					printf("[%s : %d] newfd = %d 客户端掉线\n", inet_ntoa(caddr.sin_addr), ntohs(caddr.sin_port), cfd);
    					List_Delete(C, caddr);
    					close(cfd);
    					pthread_exit(NULL);
    					return NULL;
    				}
    
    				Search_Word(words, cfd, usermsg, dictdb, histroy);
    
    			}
    		}
    
    	}
    
    
    
    }
    
    
    int main(int argc, const char *argv[])
    {
    	//创建套接字
    	int sfd = socket(AF_INET, SOCK_STREAM, 0);
    	if(sfd < 0)
    	{
    		LOG("socket");
    		return -1;
    	}
    	printf("create socket success\n");
    
    	//允许端口快速重用
    	int reuse = 1;
    	if(setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0)
    	{
    		LOG("setsockopt");
    		return -1;
    	}
    
    	//填充地址信息结构体,真实的地址信息结构体与协议族相关
    	//AF_INET,所以详情请看man 7 ip
    	struct sockaddr_in saddr;
    	saddr.sin_family 		= AF_INET;
    	saddr.sin_port 		= htons(PORT); 	//网络字节序的端口号
    	saddr.sin_addr.s_addr = inet_addr(IP); 	//网络字节序的IP地址
    
    	//将地址信息结构体绑定到套接字上
    	if(bind(sfd, (struct sockaddr*)&saddr, sizeof(saddr)) < 0)
    	{
    		LOG("bind");
    		return -1;
    	}
    	printf("bind success\n");
    
    	//将套接字设置为被动监听状态,让内核去监听是否有客户端连接;
    	if(listen(sfd, 10) < 0)
    	{
    		LOG("listen");
    		return -1;
    	}
    	printf("listen success\n");
    	sqlite3* dictdb;
    	sqlite3* userdb;
    	sqlite3* histroy;
    	Open_Dictdb(dictdb);
    	//Insert_Dict(dictdb);
    	Open_Userdb(userdb);
    	Open_Histroy(histroy);
    
    
    
    	//创建存储客户端网络结构体链表
    	ClistPtr C = List_Create();
    	if(NULL == C)
    	{
    		return -1;
    	}
    	//定义存储客户端网络结构体
    	struct sockaddr_in caddr;
    	socklen_t addrlen = sizeof(caddr);
    
    	int newfd = 0;
    	pthread_t tid;
    	Msg_t msg;
    
    
    	//循环打印已有客户端的线程
    
    	if(pthread_create(&tid, NULL, loop_printf, (void*)C) != 0)
    	{
    		LOG("pthread_create");
    		return -1;
    	}
    
    	while(1)
    	{
    		//主线程主要负责连接
    		newfd = accept(sfd, (struct sockaddr*)&caddr, &addrlen);
    		if(newfd < 0)
    		{
    			LOG("accept");
    			return -1;
    		}
    
    		//网络字节序的IP-->点分十进制  网络字节序的port--->本机字节序
    		printf("[%s : %d] newfd = %d 客户端连入\n", inet_ntoa(caddr.sin_addr), ntohs(caddr.sin_port),newfd);
    
    		msg.cfd = newfd;
    		msg.caddr = caddr;
    		msg.C = C;
    
    
    		//一旦连接成功后,创建一个分支线程用户与客户端交互;
    		if(pthread_create(&tid, NULL, Rcv_Msg, (void*)&msg) != 0)
    		{
    			LOG("pthread_create");
    			return -1;
    		}
    	}
    
    	close(sfd);
    	List_Free(&C);
    	return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
  • 相关阅读:
    Git忽略文件.gitignore的使用
    Spring事务失效原因
    想看,但电脑没网怎么办,python教你保存整本成TXT~
    git提交代码实际操作
    大数据课程L2——网站流量项目的算法分析&&数据处理
    2022年全球市场船用钢板总体规模、主要生产商、主要地区、产品和应用细分研究报告
    2022年深圳杯建模A题思路: 破除“尖叫效应”与“回声室效应”,走出“信息茧房”
    TeeChart 的使用从入门到精通
    如何彻底卸载mysql
    Bootstrap与响应式图片设计相关的类
  • 原文地址:https://blog.csdn.net/m0_72847002/article/details/132944062