网络编程实战之在线电子词典
程序员文章站
2022-05-04 14:07:34
...
1.头文件
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>
#include <sqlite3.h>
#include <signal.h>
#include <time.h>
2.宏定义
#define R 1 // user - register
#define L 2 // user - login
#define Q 3 // user - query
#define H 4 // user - history
#define N 128
//char *errmsg=NULL;
typedef struct{
char type;
char name[N];
char data[512];
}MSG;//规定传输的格式
3.服务器主程序
服务器创建一个套接字即所谓的sockfd用于监听,绑定,以及创建用于通信的套接字——调用accept函数,当一个进程连接上就会返回一个通信套接字,另一个进程连上会返回一个看似一样但是不一样的通讯套接字,就像是sql语言中NULL永远会不同于其他字符,哪怕是另一个NULL依然有效。
我们将父进程的通用套接字关闭,只用于监听是否有客户端连接,子进程只用于接收,避免了同一时间只能连接一个用户的囧境。
int main(int argc, const char *argv[])
{
MSG msg;
sqlite3 *db;
int sockfd;
char *errmsg=NULL;
if(0!=sqlite3_open("test.db",&db))
{
fprintf(stderr,"sqlite_open failed:%s",sqlite3_errmsg(db));
return -1;
}
printf("sqlite_open ok;\n");
sqlite3_exec(db,"create table if not exits usr (name char,password char);",NULL,NULL,&errmsg);
sqlite3_exec(db,"create table if not exits record_test(name char,data char,word char);",NULL,NULL,&errmsg)!=0);
printf("the table create ok\n");
sockfd=socket(AF_INET,SOCK_STREAM,0);
struct sockaddr_in serveraddr;
struct sockaddr_in clientaddr;
//填充结构体
serveraddr.sin_family=AF_INET;
serveraddr.sin_port=htons(8898);
serveraddr.sin_addr.s_addr=inet_addr("127.0.0.1");
socklen_t addrlen=sizeof(serveraddr);
socklen_t clientlen=sizeof(clientaddr);
//绑定
if(bind(sockfd,(struct sockaddr *)&serveraddr,addrlen)<0)
{
perror("bind");
exit(1);
}
printf("bind\n");
//监听
if(0> listen(sockfd,5))
{
perror("listen");
exit(1);
}
printf("listen\n");
pid_t pid;
char buf[N]={0};
int acceptfd;
// 处理僵尸进程
signal(SIGCHLD,handler);
while(1)
{
acceptfd=accept(sockfd,(struct sockaddr *)&clientaddr,&clientlen);
pid=fork();
//fork函数创建进程
//1.创建失败 2.子进程 3.父进程:父进程用于监听和连接,子进程用于通信
if(pid<0)
{
perror("failed to fork");
exit(1);
}
else if(pid==0)
{
close(sockfd);
do_client(acceptfd,db);
}
else
close(acceptfd);
}
sqlite3_close(db);
return 0;
}
4.客户端信号的处理
int do_client(int acceptfd,sqlite3 *db)
{
MSG msg;
while(recv(acceptfd,&msg,sizeof(MSG),0)>0)
{
printf("type:%d\n",msg.type);
switch(msg.type)
{
case 'R':
process_register(acceptfd,&msg,db);
break;
case 'L':
process_login(acceptfd,&msg,db);
break;
case 'Q':
process_query(acceptfd,&msg,db);
break;
case 'H':
process_history(acceptfd,&msg,db);
break;
default:
printf("invalid data msg.\n");
}
}
printf("client exit\n");
close(acceptfd);
exit(0);
}
5.客户端的主函数(字符界面)
int main(int argc, const char *argv[])
{
int sockfd;
MSG msg;
MSG *msgp = NULL;
sockfd=socket(AF_INET,SOCK_STREAM,0);
if(sockfd<0)
{
perror("sockfd.");
exit(1);
}
struct sockaddr_in serveraddr;
bzero(&serveraddr,sizeof(serveraddr));//清零
serveraddr.sin_family=AF_INET;
serveraddr.sin_port=htons(8898);
serveraddr.sin_addr.s_addr=inet_addr("127.0.0.1");
socklen_t addrlen=sizeof(serveraddr);
connect(sockfd,(struct sockaddr *)&serveraddr,addrlen);
char buf[N]={0};
int n;
while(1)
{
printf("***********************\n");
printf("******1:register****\n");
printf("******2:login*******\n");
printf("******3.quit********\n");
printf("***********************\n");
printf("please choose\n");
fgets(buf,sizeof(buf),stdin);
printf("%s\n",buf);
switch(buf[0])
{
case '1':
do_register(sockfd,&msg);
break;
case '2':
if(do_login(sockfd,&msg)==1)
{
goto next;
}
break;
case '3':
close(sockfd);
exit(0);
break;
default:
printf("input again\n");
continue;
}
}
while(1)
{
next:
printf("************************************\n");
printf("**1:querry_word**2:history**3:quit**\n");
printf("************************************\n");
printf("please choose:\n");
fgets(buf,sizeof(buf),stdin);
switch(buf[0])
{
case '1':
do_query(sockfd,&msg);
break;
case '2':
do_history(sockfd,&msg);
break;
case '3':
close(sockfd);
exit(0);
default:printf("invalid data\n");
}
}
return 0;
}
6.注册功能实现
(1)客户端
int do_register(int sockfd,MSG *msg)
{
msg->type='R';
printf("your usrname:\n");
scanf("%s",msg->name);
printf("your password:\n");
scanf("%s",msg->data);
printf("%c,%s,%s\n",msg->type,msg->name,msg->data);
pid_t pid;
if(send(sockfd,msg,512,0)<0)
{
printf("failed to send\n");
return 1;
}
if(recv(sockfd,msg,sizeof(MSG),0)<0)
{
printf("failed to recv\n");
return 1;
}
printf("%s\n",msg->data);
return 0;
}
(2)服务器端
void process_register(int acceptfd,MSG *msg, sqlite3 * db)
{
char sql[64]={0};
char *errmsg=NULL;
sprintf(sql,"insert into usr values('%s','%s');",msg->name,msg->data);
printf("%s\n",sql);
if(0!= sqlite3_exec(db,sql,NULL,NULL,&errmsg))
{
printf("%s\n",errmsg);
strcpy(msg->data,"usrname already exit.");
}
else
{
printf("client register ok.\n");
strcpy(msg->data,"OK!");
}
if(send(acceptfd,msg,sizeof(MSG),0)<0)
{
perror("failed to send");
return;
}
return;
}
7.登录功能的实现
(1)客户端
int do_login(int sockfd,MSG *msg)
{
pid_t pid;
msg->type='L';
printf("input your name\n");
scanf("%s",msg->name);
getchar();
printf("input your password\n");
scanf("%s",msg->data);
getchar();
send(sockfd,msg,sizeof(MSG),0);
printf("%s\n",msg->data);
recv(sockfd,msg,sizeof(MSG),0);
printf("%s\n",msg->data);
if(strncmp(msg->data,"OK",3)==0)
{
printf("Login ok\n");
return 1;
}
else
{
printf("%s",msg->data);
return 0;
}
}
(2)服务器端
int process_login(int acceptfd,MSG *msg,sqlite3 *db)
{ char **resultp=NULL;
int nrow,ncolumn;
char *errmsg=NULL;
char sql[512]={0};
printf("a2\n");
sprintf(sql,"select * from usr where name = '%s' and password = '%s';",msg->name,msg->data);
if(0!= sqlite3_get_table(db,sql,&resultp,&nrow,&ncolumn,&errmsg))
{
printf("%s\n",errmsg);
return -1;
}else
{
printf("get_table ok!\n");
}
if(nrow==0)
{
strcpy(msg->data,"usr/pwd wrony");
send(acceptfd,msg,sizeof(MSG),0);
}else if(nrow==1)
{
strcpy(msg->data,"OK");
send(acceptfd,msg,sizeof(MSG),0);
return 1;
}
return 0;
}
8.查询功能
(1)客户端
void do_query(int sockfd,MSG *msg)
{
msg->type='Q';
puts("-----------------------------");
while(1)
{
printf("input word:");
fgets(msg->data,sizeof(msg->data),stdin);
msg->data[strlen(msg->data)-1]='\0';
if(strncmp(msg->data,"#",1)==0)
break;
if(send(sockfd,msg,sizeof(MSG),0)<0)
{
printf("failed to send\n");
return ;
}
printf("%c,%s",msg->type,msg->data);
printf("send ok.\n");
if(recv(sockfd,msg,1024,0)<0)
{
printf("failed to recv\n");
return ;
}
printf("%s\n",msg->data);
}
return ;
}
(2)服务器端
int do_searchword(int acceptfd,MSG *msg,char word[])
{
FILE *fp=NULL;
char buffer[1024]={0};
int len;
if((fp=fopen("./dict.txt","r"))==NULL)
{
perror("fail to fopen.\n");
strcpy(msg->data, "Failed to open dict.txt");
send(acceptfd,(MSG*)&msg, sizeof(MSG), 0);
return 1;
}
len=strlen(word);
printf("%s,len=%d\n",word,len);
int result;
char *p=NULL;
while(fgets(buffer,1024,fp)!=NULL)
{
result=strncmp(buffer,word,len);
if(result<0)
{
continue;
}
if(result>0||((result == 0)&&(buffer[len]!=' ')))
break;
p=buffer + len;
while(*p== ' ')
{
p++;
}
strcpy(msg->data,p);
printf("%s\n",msg->data);
fclose(fp);
return 1;
}
fclose(fp);
return 0;
}
int get_time(char *data)
{
struct tm *tm_p=NULL;
time_t dtime;
time(&dtime);
tm_p=localtime(&dtime);
sprintf(data,"%d-%d-%d %d:%d:%d\n",tm_p->tm_year + 1900,tm_p->tm_mon + 1,\
tm_p->tm_mday,tm_p->tm_hour,tm_p->tm_min,tm_p->tm_sec);
printf("get data:%s\n",data);
return 0;
}
void process_query(int acceptfd,MSG *msg,sqlite3 *db)
{
int found;
char word[64]={0};
char data[128]={0};
char sql[128]={0};
char *errmsg =NULL;
strcpy(word,msg->data);
found=do_searchword(acceptfd,msg,word);
if(found==1)
{
get_time(data);
sprintf(sql,"insert into record_test values('%s','%s','%s')",msg->name,data,word);
if(0!=sqlite3_exec(db,sql,NULL,NULL,&errmsg))
{
printf("%s\n",errmsg);
return ;
}
else
{
printf("insert record done.\n");
}
}
else
{
strcpy(msg->data,"NO found");
printf("aaaa\n");
}
if(send(acceptfd,msg,sizeof(MSG),0)<0)
{
perror("failed to send");
}
}
9 历史查询
(1)客户端
void do_history(int sockfd,MSG *msg)
{
msg->type='H';
send(sockfd,msg,sizeof(MSG),0);
while(1)
{
recv(sockfd,msg,sizeof(MSG),0);
if(msg->data[0]=='\0')
break;
printf("%s\n",msg->data);
}
}
(2)服务器端
int history_callback(void* arg,int f_num,char** f_value,char** f_name)
{
int accptfd;
MSG msg;
accptfd=*((int *)arg);
sprintf(msg.data,"%s ,%s",f_value[1],f_value[2]);
send(accptfd,&msg,sizeof(msg),0);
return 0;
}
void process_history(int acceptfd,MSG *msg,sqlite3 * db)
{
char sql[128]={0};
char *errmsg=NULL;
sprintf(sql,"select * from record where name ='%s';",msg->name);
if(0!=sqlite3_exec(db,sql,history_callback,(void *)&acceptfd,&errmsg))
{
printf("%s\n",errmsg);
}else
{
printf("record done.\n");
}
msg->data[0]='\0';
send(acceptfd,msg,sizeof(MSG),0);
}
10 僵尸进程处理函数
void handler(int signum)
{
if(SIGCHLD==signum)
waitpid(-1,NULL,WNOHANG);
}
本文纯属个人笔记,如有错误,还望不吝指点,如有雷同,你来打我呀
上一篇: python读取Dicom文件