功能:
- 客户端每次连接服务器时,都需要登陆或注册对应的账号和密码;
- 如果客户端没有账号,则应该注册账号和密码;
- 客户端登陆成功后, 应该具有检索单词,查看历史的功能;
4.可以根据自己情况自行添加其他功能;
.h文件
#ifndef _HEAD_H_
#define _HEAD_H_
enum un
{
regi,
login,
quit,
};
//链表节点结构体:
typedef struct node
{
struct sockaddr_in addr; //data memcmp
struct node *next;
} link_t;
//消息对应的结构体(同一个协议)
typedef struct msg_t
{
int choose;
char name[128]; //用户名
char password[128]; //消息正文
} MSG_t;
#endif
客户端
client.c
void show(void)
{
printf("***************************************\n");
printf("***************0:register**************\n");
printf("***************1:login*****************\n");
}
void show2(void)
{
printf("***************2:Quit*****************\n");
printf("***************3:History******************\n");
printf("***************4:Quire******************\n");
}
int creat_socket(void)
{
int sockec;
if ((sockec = socket(AF_INET, SOCK_STREAM, 0)) < 0) //TCP向下默认匹配ip协议
{
perror("socket err");
return -1;
}
return sockec;
}
int main(int argc, char const *argv[])
{
int n;
char buf[128] = {0};
char file[128] = {0};
char name[128] = {0};
char password[128] = {0};
int choose;
//创建套接字
int sockec, ret;
sockec = creat_socket();
printf("%d\n", sockec);
//指定服务器的信息
struct sockaddr_in saddr;
saddr.sin_family = AF_INET;
saddr.sin_port = htons(atoi(argv[1]));
saddr.sin_addr.s_addr = INADDR_ANY;
// saddr.sin_addr.s_addr = inet_addr("192.168.50.194");
//请求连接服务器
if (connect(sockec, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) //sockets只能用于连接
{
perror("connect err");
return -1;
}
else
printf("con succ\n");
//创建身份结构体
MSG_t msg;
while (1)
{
show();
printf("please choose\n");
scanf("%d", &choose);
msg.choose = choose;
printf("input name\n");
scanf("%s", name);
strcpy(msg.name, name);
printf("input password\n");
scanf("%s", password);
strcpy(msg.password, password);
send(sockec, &msg, sizeof(msg), 0); //发送信息
if (choose == 0)
{
memset(buf, 0, sizeof(buf));
ret = recv(sockec, buf, 256, 0); //默认阻塞
if (ret < 0)
{
perror("recv err");
return -1;
}
else if (ret == 0)
{
printf("dis connect\n");
break;
}
else
{
printf("%s\n", buf);
if (strncmp(buf, "register failure", sizeof(buf)) == 0)
printf("register failure\n");
else
{
printf("%s\n", buf);
}
}
}
else if (choose == 1)
{
memset(buf, 0, sizeof(buf));
ret = recv(sockec, buf, 256, 0); //默认阻塞
if (ret < 0)
{
perror("recv err");
return -1;
}
else if (ret == 0)
{
printf("dis connect\n");
break;
}
else
{
if (strncmp(buf, "login failure", sizeof(buf)) == 0)
printf("login failure\n");
else
{
//登录成功
printf("%s\n", buf);
while (1)
{
memset(buf, 0, sizeof(buf));
show2();
printf("please choose\n");
scanf("%d", &n);
if (n == 2)
{
strcpy(buf, "Quit");
send(sockec, buf, sizeof(buf), 0); //发送信息
}
else if (n == 3)
{
strcpy(buf, "History");
send(sockec, buf, sizeof(buf), 0); //发送信息
while (1)
{
memset(buf, 0, sizeof(buf));
ret = recv(sockec, buf, 256, 0); //默认阻塞
if (ret < 0)
{
perror("recv err");
return -1;
}
else if (ret == 0)
{
printf("dis connect\n");
break;
}
else
{
if (strcmp(buf, "over") == 0)
{
break;
}
printf("%s\n", buf);
}
}
}
else if (n == 4)
{
strcpy(buf, "Quire");
send(sockec, buf, sizeof(buf), 0); //发送信息
while (1)
{
memset(buf, 0, sizeof(buf));
printf("please input word(#:quit):\n");
scanf("%s", buf);
send(sockec, buf, sizeof(buf), 0); //发送信息
ret = recv(sockec, buf, 256, 0); //默认阻塞
if (ret < 0)
{
perror("recv err");
return -1;
}
else if (ret == 0)
{
printf("dis connect\n");
break;
}
else
{
if (strcmp(buf, "#") == 0)
{
printf("without this word\n");
continue;
}
printf("%s\n", buf);
}
}
}
}
}
}
}
}
close(sockec);
return 0;
}
服务端
char sql[128] = {0};
int callback(void *buf, int num, char **value, char **name);
void client_regi(int sockfd, MSG_t msg, struct sockaddr_in caddr);
int client_login(int sockfd, MSG_t msg, struct sockaddr_in caddr);
sqlite3 *db;
void handler(int sig)
{
waitpid(-1, NULL, WNOHANG);
}
int main(int argc, char const *argv[])
{
pid_t pid;
int acceptfd;
char buf[128] = {0};
int ret, ret1;
char times[128] = {0};
char *errmsg = NULL;
char **result = NULL;
int row, column;
//获取时间
time_t timep;
struct tm *p;
time(&timep);
p = gmtime(&timep);
// 1.创建流式套接字(socket)-----------------------------》有手机
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
{
perror("sock err");
return -1;
}
printf("sockfd:%d\n", sockfd);
// 2.指定网络信息-----------------------------------------------》有号码
struct sockaddr_in saddr, caddr;
saddr.sin_family = AF_INET;
saddr.sin_port = htons(atoi(argv[1]));
//saddr.sin_addr.s_addr = inet_addr("0.0.0.0");
saddr.sin_addr.s_addr = INADDR_ANY;
//INADDR_ANY:0.0.0.0
// 3.绑定套接字(bind)--------------------------------------》绑定手机
if (bind(sockfd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0)
{
perror("bind err");
return -1;
}
printf("bind ok\n");
// 4.监听套接字(listen)-------------------------------------》待机
//将主动套接字变成被动套接字
if (listen(sockfd, 6) < 0)
{
perror("listen err");
return -1;
}
printf("listen ok\n");
// 5.接收客户端请求(accept)
int len = sizeof(caddr);
MSG_t msg;
while (1)
{
acceptfd = accept(sockfd, (struct sockaddr *)&caddr, &len);
if (acceptfd < 0)
{
perror("accept err");
return -1;
}
printf("accept ok\n");
printf("ip:%s port:%d\n", inet_ntoa(caddr.sin_addr), ntohs(caddr.sin_port));
pid = fork();
if (pid < 0)
{
perror("fork err");
return -1;
}
else if (pid == 0)
{
//子进程
while (1)
{ // 6.发送、接收消息(send、recv)-----------------------》通话
ret = recv(acceptfd, &msg, sizeof(msg), 0);
if (ret < 0)
{
perror("recv errr");
break;
}
else if (ret == 0)
{
printf("client exit\n");
break;
}
else
{
//选择类型
printf("type:%d\n", msg.choose);
switch (msg.choose)
{
case regi:
client_regi(acceptfd, msg, caddr);
break;
case login:
ret1 = client_login(acceptfd, msg, caddr);
if (ret1 == 0)
{
ret = recv(acceptfd, buf, sizeof(buf), 0);
if (ret < 0)
{
perror("recv errr");
break;
}
else if (ret == 0)
{
printf("client exit\n");
break;
}
else
{
printf("%s\n", buf);
if (strcmp(buf, "Quire") == 0)
{
printf("start quire\n");
while (1)
{
ret = recv(acceptfd, buf, sizeof(buf), 0);
if (ret < 0)
{
perror("recv errr");
break;
}
else if (ret == 0)
{
printf("client exit\n");
break;
}
else
{
printf("%s\n", buf);
// if (strcmp(buf, "#") == 0)
// break;
sprintf(sql, "select * from words where wordname=\"%s\";", buf);
sqlite3_get_table(db, sql, &result, &row, &column, &errmsg);
printf("row:%d column:%d\n", row, column);
if (row == 0)
{
strcpy(buf, "#");
send(acceptfd, buf, sizeof(buf), 0);
continue;
}
else
{
sprintf(times, "%d-%d-%d %d:%d:%d ", (1900 + p->tm_year), (1 + p->tm_mon), p->tm_mday, p->tm_hour + 8, p->tm_min, p->tm_sec);
printf("%s\n", times);
sprintf(sql, "insert into sit values(\"%s\",\"%s\");", buf, times);
//插入数据
if (sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK)
{
fprintf(stderr, "create stu err %s\n", errmsg);
return -1;
}
}
int k = 0;
for (int i = 0; i <= row; i++)
{
for (int j = 0; j < column; j++)
printf("%s ", result[k++]);
putchar(10);
}
strcpy(buf, result[5]);
send(acceptfd, buf, sizeof(buf), 0);
}
}
}
else if (strcmp(buf, "History") == 0)
{
sqlite3_get_table(db, "select * from sit;", &result, &row, &column, &errmsg);
printf("row:%d column:%d\n", row, column);
int k = 0;
for (int i = 0; i <= row; i++)
{
memset(buf, 0, sizeof(buf));
for (int j = 0; j < 2; j++)
{
//printf("%s ", result[k++]);
strcat(buf, result[k++]);
}
printf("%d\n", k);
printf("%s\n", buf);
send(acceptfd, buf, sizeof(buf), 0);
// putchar(10);
}
strcpy(buf, "over");
send(acceptfd, buf, sizeof(buf), 0);
}
break;
}
}
else
{
printf("login failure\n");
}
break;
// case quit:
// client_quit(acceptfd, msg, caddr);
// break;
default:
break;
}
}
}
close(acceptfd);
exit(0);
}
else
{
close(acceptfd);
signal(SIGCHLD, handler);
}
}
//recv(acceptfd, buf, 128, 0);
// 7.关闭套接字(close)-------------------------------------》挂电话
close(sockfd);
return 0;
}
void client_regi(int sockfd, MSG_t msg, struct sockaddr_in caddr)
{
//char buf[128] = "register success";
char text[128] = {0};
sprintf(text, "%s register...", msg.name);
//将新登录的用户信息添加到数据库中并且通知其他在线用户
// 打开数据库
if (sqlite3_open("./yun.db", &db) != SQLITE_OK)
{
fprintf(stderr, "open yun err %s", sqlite3_errmsg(db));
//return -1;
}
//操作数据库
char *errmsg = NULL;
sprintf(sql, "select * from stu where name=\"%s\"", msg.name);
if (sqlite3_exec(db, sql, callback, "hello", &errmsg) != SQLITE_OK)
{
fprintf(stderr, "select stu err %s\n", errmsg);
//return -1;
}
else
{
sprintf(sql, "insert into stu values(\"%s\",\"%s\");", msg.name, msg.password);
if (sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK)
{
fprintf(stderr, "create stu err %s\n", errmsg);
//return -1;
}
else
{
printf("%s\n", text);
send(sockfd, text, sizeof(msg), 0);
}
}
return;
}
int client_login(int sockfd, MSG_t msg, struct sockaddr_in caddr)
{
int ret;
char text[128] = {0};
sprintf(text, "%s login...", msg.name);
//printf("%s\n", text);
//将新登录的用户信息添加到数据库中并且通知其他在线用户
//sqlite3 *db;
// 打开数据库
if (sqlite3_open("./yun.db", &db) != SQLITE_OK)
{
fprintf(stderr, "open yun err %s", sqlite3_errmsg(db));
return -1; //打开失败
}
//操作数据库
char *errmsg = NULL;
char **result = NULL;
int row, column;
sprintf(sql, "select * from stu where name=\"%s\";", msg.name);
sqlite3_get_table(db, sql, &result, &row, &column, &errmsg);
printf("row:%d column:%d\n", row, column);
if (row == 0)
{
memset(text, 0, sizeof(text));
strcpy(text, "login failure");
}
send(sockfd, text, sizeof(text), 0);
return 0;
}
int callback(void *buf, int num, char **value, char **name)
{
//buf
printf("%s\n", (char *)buf);
//num:列的数量
//value:值
//name:列名
for (int i = 0; i < num; i++)
printf("%s ", name[i]);
for (int i = 0; i < num; i++)
printf("%s ", value[i]);
putchar(10);
//一定要加,不然会认为回调出错了
return 0;
}
将单词导入数据库
//int callback(void *buf, int num, char **value, char **name);
int main(int argc, char const *argv[])
{
sqlite3 *db;
// 打开/创建数据库
if (sqlite3_open("./yun.db", &db) != SQLITE_OK)
{
fprintf(stderr, "open stu err %s", sqlite3_errmsg(db));
return -1;
}
//操作数据库
char *errmsg = NULL;
//创建words表
if (sqlite3_exec(db, "create table words(id int,wordname char,express char);", NULL, NULL, &errmsg) != SQLITE_OK)
{
fprintf(stderr, "create stu err %s\n", errmsg);
//return -1;
}
printf("words table success\n");
//创建stu表
if (sqlite3_exec(db, "create table stu(name char,password char);", NULL, NULL, &errmsg) != SQLITE_OK)
{
fprintf(stderr, "create stu err %s\n", errmsg);
//return -1;
}
printf("stu table success\n");
//创建his表
if (sqlite3_exec(db, "create table sit(word char,time char);", NULL, NULL, &errmsg) != SQLITE_OK)
{
fprintf(stderr, "create sit err %s\n", errmsg);
//return -1;
}
printf("his table success\n");
char buf[1000] = {0};
char word[200] = {0};
char sql[200] = {0};
char tail[1000] = {0};
char *n = NULL;
//打开文件
FILE *fp;
int j, i, id = 1;
fp = fopen("./dict.txt", "r");
if (fp == NULL)
{
perror("open err");
return -1;
}
printf("open ok\n");
while (1)
{
i = 0;
n = fgets(buf, sizeof(buf), fp);
if (n == NULL)
break;
while (1)
{
if (buf[i] == ' ')
break;
i++;
}
for (j = 0; j < i; j++)
{
word[j] = buf[j];
}
while (1)
{
if (buf[i] == ' ')
break;
i++;
}
strcpy(tail, buf + i);
tail[sizeof(tail) - 1] = '\0';
printf("%d ", id);
printf("%s %s\n", word, tail);
sprintf(sql, "insert into words values (%d,\"%s\",\"%s\");", id, word, tail);
if (sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK)
{
fprintf(stderr, "create stu err %s\n", errmsg);
return -1;
}
else
{
id++;
}
memset(buf, 0, sizeof(buf));
memset(tail, 0, sizeof(tail));
memset(word, 0, sizeof(word));
}
sqlite3_close(db);
return 0;
}