难点:
使用socket库创建和管理套接字,实现客户端和服务器的网络通信。
客户端使用TCP协议与服务器建立连接,并发送请求和接收响应。
客服端使用多线程或者多进程分别处理键盘输入或者服务器的响应。
服务器使用io多路复用来处理多个客户端的并发请求。
使用数据库存储用户的账号密码,并设定key值。
使用数据库存储词典数据,服务器根据客户端请求查询对应的数据。
使用适当的数据结构来组织和存储词典数据,以便快速查询。
使用链表等数据结构管理每个用户的查找记录,以便用户查看。
实现用户友好的界面,并提供错误处理和异常情况。
-
客户端功能:
- 与服务器建立TCP连接。
- 账号注册及出错反馈。
- 用户登录成功或失败反馈
- 登录成功将提供用户界面,接收用户输入的单词。
- 将用户输入的请求发送给服务器。
- 接收并显示服务器返回的结果,包括词义、解释等。
- 提供查询历史记录等。
-
服务器功能:
- 采用io多路复用,监听指定的端口,等待一个或多个客户端连接。
- 接收客户端发送的请求。
- 使用数据库,建立单词表和用户信息表
- 根据请求查询相应的词义和解释。
- 将查询结果发送给客户端。
- 根据客户端输入的请求,反馈结果给客户。
源码
服务器
void Register(int acceptfd, sqlite3 *db);
void Login(int acceptfd, sqlite3 *db);
void Query(int acceptfd, sqlite3 *db);
void History(int acceptfd,sqlite3 *db);
int main(int argc, char const *argv[])
{
//输入容错
if (argc != 2)
{
printf("Usage : %s <port>\n", argv[0]);
return -1;
}
//创建sockfd套接字
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
{
perror("socket is err:");
return -1;
}
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");
int addrlen = sizeof(caddr);
//绑定套接字
if (bind(sockfd, (struct sockaddr *)&saddr, addrlen))
{
perror("bind err:");
return -1;
}
//启动监听
if (listen(sockfd, 5))
{
perror("listen err:");
return -1;
}
//打开数据库
sqlite3 *db = NULL; //防止野指针
char *errmsg = NULL; //一个库
if (sqlite3_open("./cidian.db", &db) != 0) //两个表 帐号密码表 历史记录表
{
fprintf(stderr, "sqlite3_err %s\n", sqlite3_errmsg(db));
return -1;
}
printf("open cidian sucess\n");
if (sqlite3_exec(db, "create table usr(name char primary key ,password char);", NULL, NULL, &errmsg) != SQLITE_OK)
{
fprintf(stderr, "sqlite3_exec:%s\n", errmsg);
}
if (sqlite3_exec(db, "create table history(name char,word char,time char);", NULL, NULL, &errmsg) != SQLITE_OK)
{
fprintf(stderr, "sqlite3_exec:%s\n", errmsg);
}
while (1)
{
//连接
int acceptfd = accept(sockfd, (struct sockaddr *)&caddr, &addrlen);
if (acceptfd < 0)
{
perror("accept err");
return -1;
}
printf("client IP is: %s,PORT is: %d\n", inet_ntoa(caddr.sin_addr), ntohs(caddr.sin_port));
//多进程
pid_t pid = fork();
if (pid < 0)
{
perror("fork err");
return -1;
}
else if (pid == 0)
{
close(sockfd);
while (1)
{
//循环接收
int ret = recv(acceptfd, &msg, sizeof(msg), 0);
if (ret < 0)
{
perror("recv is err");
return -1;
}
else if (ret == 0)
{
break;
}
else
{
switch (msg.type)
{
case 'R':
Register(acceptfd, db);
break;
case 'L':
Login(acceptfd, db);
break;
case 'Q':
Query(acceptfd,db);
break;
case 'H':
History(acceptfd, db);
break;
}
}
}
printf("client exit\n");
close(acceptfd);
exit(0);
}
else
{
close(acceptfd);
}
}
close(sockfd);
sqlite3_close(db);
return 0;
}
客户端
#include <stdio.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <string.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/wait.h>
typedef struct
{
int type;
char name[128];
char text[256];
} MSG;
struct sockaddr_in saddr;
MSG msg;
int n;
//char word[64];
void list1();
void list2();
void do_register(int sockfd);
void do_login(int sockfd);
void query_word(int sockfd);
void history_record(int sockfd);
int main(int argc, char const *argv[])
{
if (argc != 3)
{
printf("Useage:%s <ip> <port>\n", argv[0]);
return -1;
}
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
{
perror("sockfd is err");
return -1;
}
saddr.sin_family = AF_INET;
saddr.sin_port = htons(atoi(argv[2]));
saddr.sin_addr.s_addr = inet_addr(argv[1]);
if (connect(sockfd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0)
{
perror("connect is err");
return -1;
}
while (1)
{
list1();
printf("please choose number :");
scanf("%d", &n);
getchar();
switch (n)
{
case 1:
do_register(sockfd);
break;
case 2:
do_login(sockfd);
break;
case 3:
close(sockfd);
exit(0);
default:
printf("输入格式有误,请重输\n");
break;
}
if (msg.type == 1)
goto loop;
}
loop:
while (1)
{
list2();
printf("please choose num:");
scanf("%d", &n);
getchar();
switch (n)
{
case 1:
query_word(sockfd);
break;
case 2:
history_record(sockfd);
break;
case 3:
close(sockfd);
printf("nice to meetyou!! bye\n");
exit(0);
default:
printf("输入格式有误,请重新输入\n");
break;
}
}
return 0;
}