在线词典是基于Linux 多进程并发服务器编程,由服务器端和客户端构成,客户端可以运行在多个不同的主机上连接服务器,服务器对员工信息的操作结果通过数据库sqlite来保存。当用户登录后,根据用户名判断用户是否已注册。如果未注册,则进行注册用户名和密码,如果已经存在该用户名,输入正确密码,则进行查询单词和查询历史记录操作。

服务器端

服务器端功能描述:

服务器端操作流程:

客户端

客户端功能描述:

客户端操作流程:

源代码

服务器端

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sqlite3.h>
#include <signal.h>
#include <time.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>#define  N  16
#define  R  1   //  user register
#define  L  2   //  user login
#define  Q  3   //  query word
#define  H  4   //  history record//定义数据库
#define DATABASE "my.db"typedef struct
{int type;char name[N];char data[256];   // password or word
} MSG;void do_client(int acceptfd, sqlite3 *db);
void do_register(int acceptfd, MSG *msg, sqlite3 *db);
void do_login(int acceptfd, MSG *msg, sqlite3 *db);
void do_query(int acceptfd, MSG *msg, sqlite3 *db);
int  do_searchword(int acceptfd, MSG *msg);
void getdata(char data[]);
void do_history(int acceptfd, MSG *msg, sqlite3 *db);
int history_callback(void *arg, int f_num, char **f_value, char **f_name);
int main(int argc, char *argv[])
{int sockfd, acceptfd;struct sockaddr_in server_addr;pid_t pid;sqlite3 *db;if (argc < 3){printf("Usage : %s <ip> <port>\n", argv[0]);exit(-1);}//打开数据库(如果数据库已经创建好了,调用函数后,之后利用指针操作数据库)//数据库里面有两个表,一个负责存放用户名和密码,用户名唯一,另一个负责存放历史记录if (sqlite3_open(DATABASE, &db) != SQLITE_OK){printf("error : %s\n", sqlite3_errmsg(db));exit(-1);}if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0){perror("fail to socket");exit(-1);}bzero(&server_addr, sizeof(server_addr));   server_addr.sin_family = AF_INET;server_addr.sin_addr.s_addr = inet_addr(argv[1]);server_addr.sin_port = htons(atoi(argv[2]));if (bind(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0){perror("fail to bind");exit(-1);}if (listen(sockfd, 5) < 0){perror("fail to listen");exit(-1);}signal(SIGCHLD, SIG_IGN);// 避免僵尸进程while(1){//不关心客户端的网络信息结构体if((acceptfd = accept(sockfd, NULL, NULL)) < 0){perror("fail to accept");exit(-1);}//父子进程实现并发if((pid = fork()) < 0){perror("fail to fork");exit(-1);}if(pid == 0)  //子进程负责接收数据并处理{close(sockfd);do_client(acceptfd, db);}else  //父进程负责连接{close(acceptfd);}}return 0;
}void do_client(int acceptfd, sqlite3 *db)
{MSG msg;//根据接收到的type判断对应执行的代码while (recv(acceptfd, &msg, sizeof(MSG), 0) > 0)  // receive request{printf("type : %d, name : %s, data : %s\n", msg.type, msg.name, msg.data);switch ( msg.type ){case R :do_register(acceptfd, &msg, db);break;case L :do_login(acceptfd, &msg, db);break;case Q :do_query(acceptfd, &msg, db);break;case H :do_history(acceptfd, &msg, db);break;}}//对方退出或者异常关闭printf("client quit\n");exit(0);return;
}//注册
void do_register(int acceptfd, MSG *msg, sqlite3 *db)
{char sqlstr[128] = {0};char *errmsg;sprintf(sqlstr, "insert into usr values('%s', '%s')", msg->name, msg->data);//调用函数在数据库里插入数据if(sqlite3_exec(db, sqlstr, NULL, NULL, &errmsg) != SQLITE_OK){//数据存在,插入失败sprintf(msg->data, "user %s already exist!!!", msg->name);} else {//插入成功strcpy(msg->data, "OK");}//将信息发送给客户端send(acceptfd, msg, sizeof(MSG), 0);return;
}//登录
void do_login(int acceptfd, MSG *msg, sqlite3 *db)
{char sqlstr[128] = {0};char *errmsg, **result;int nrow, ncolumn;sprintf(sqlstr, "select * from usr where name = '%s' and pass = '%s'", msg->name, msg->data);//调用sqlite3_get_table查询数据是否在数据库的表里面if(sqlite3_get_table(db, sqlstr, &result, &nrow, &ncolumn, &errmsg) != SQLITE_OK){printf("error : %s\n", errmsg);}//nrow为0表示数据不存在或者不匹配if(nrow == 0){strcpy(msg->data, "name or password is wrony!!!");}else  //数据匹配{strncpy(msg->data, "OK", 256);}//发送指令send(acceptfd, msg, sizeof(MSG), 0);return;
}//查询
void do_query(int acceptfd, MSG *msg, sqlite3 *db)
{char sqlstr[128], *errmsg;int found = 0;char date[128], word[128];strcpy(word, msg->data);//查询成功返回1found = do_searchword(acceptfd, msg);//如果找到单词的解释,需要将单词以及时间保存在历史记录的数据库表里if(found == 1){//时间getdata(date);      sprintf(sqlstr, "insert into record values('%s', '%s', '%s')", msg->name, date, word);//将用户名、时间以及单词保存在历史记录表里if(sqlite3_exec(db, sqlstr, NULL, NULL, &errmsg) != SQLITE_OK){printf("error : %s\n", errmsg);}} else {strcpy(msg->data, "not found");}send(acceptfd, msg, sizeof(MSG), 0);  return;
}//查找单词
int  do_searchword(int acceptfd, MSG *msg)
{FILE *fp;char temp[300];char *p;int len, result;//得到要查找单词的长度len = strlen(msg->data);//打开文档if((fp = fopen("dict.txt", "r")) == NULL){strcpy(msg->data, "dict can not open");send(acceptfd, msg, sizeof(MSG), 0);}//printf("query word is %s len = %d\n", msg->data, len);//fgets每次只可以读一行,规定文档里面最后一行有300个字节while(fgets(temp, 300, fp) != NULL){result = strncmp(msg->data, temp, len);//输入的单词必须保证一样,并且temp的下一个字符是空格if(result == 0 && temp[len] == ' '){//指针指向单词后面的位置p = temp + len;//从第一个有数据的位置开始读,排除单词与解释之间的空格while(*p == ' '){p++;}strcpy(msg->data, p);fclose(fp);return 1;}}//如果没找到fclose(fp);return 0;
}//获取时间
void getdata(char data[])
{time_t t;struct tm *tp;time(&t);tp = localtime(&t);//将数据保存在data里面sprintf(data, "%d-%d-%d %d:%d:%d", tp->tm_year + 1900, tp->tm_mon + 1, tp->tm_mday, tp->tm_hour, tp->tm_min, tp->tm_sec);return ;
}//查询历史记录
void do_history(int acceptfd, MSG *msg, sqlite3 *db)
{char sqlstr[128], *errmsg;sprintf(sqlstr, "select * from record where name = '%s'", msg->name);if (sqlite3_exec(db, sqlstr, history_callback, (void *)&acceptfd, &errmsg) != SQLITE_OK){printf("error : %s\n", errmsg);sqlite3_free(errmsg);}msg->data[0] = '\0';send(acceptfd, msg, sizeof(MSG), 0);return;
}int history_callback(void *arg, int f_num, char **f_value, char **f_name)
{int acceptfd;MSG msg;acceptfd = *(int *)arg;sprintf(msg.data, "%s : %s", f_value[1], f_value[2]);send(acceptfd, &msg, sizeof(msg), 0);return 0;
}
客户端
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sqlite3.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>#define  N  16
#define  R  1   //  注册
#define  L  2   //  登录
#define  Q  3   //  查询单词
#define  H  4   //  查询历史记录#define DATABASE "my.db"typedef struct
{int type;char name[N];char data[256];   // password or word or remark
} MSG;void do_register(int sockfd, MSG *msg);
int do_login(int sockfd, MSG *msg);
void do_query(int sockfd, MSG *msg);
void do_history(int sockfd, MSG *msg);int main(int argc, char *argv[])
{int sockfd ;int n;struct sockaddr_in server_addr;MSG msg;if (argc < 3){printf("Usage : %s <serv_ip> <serv_port>\n", argv[0]);exit(-1);}if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0){perror("fail to socket");exit(-1);}bzero(&server_addr, sizeof(server_addr));  server_addr.sin_family = AF_INET;server_addr.sin_addr.s_addr = inet_addr(argv[1]);server_addr.sin_port = htons(atoi(argv[2]));if (connect(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0){perror("fail to connect");exit(-1);}while(1){printf("************************************\n");printf("* 1: register   2: login   3: quit *\n");printf("************************************\n");printf("please choose : ");if(scanf("%d", &n) <= 0){perror("scanf");exit(-1);}switch(n){case 1:do_register(sockfd, &msg);break;case 2:if(do_login(sockfd, &msg) == 1){goto next;}break;case 3:close(sockfd);exit(0);}}
next:while(1){printf("************************************\n");printf("* 1: query   2: history   3: quit *\n");printf("************************************\n");printf("please choose : ");if(scanf("%d", &n) <= 0){perror("scanf");exit(-1);}switch(n){case 1:do_query(sockfd, &msg);break;case 2:do_history(sockfd, &msg);break;case 3:close(sockfd);exit(0);}}return 0;
}//注册
void do_register(int sockfd, MSG *msg)
{//输入指令以及用户名和密码,发送给服务器msg->type = R;printf("input your name:");scanf("%s", msg->name);    printf("input your password:");scanf("%s", msg->data);send(sockfd, msg, sizeof(MSG), 0); //接收数据,判断是否注册成功recv(sockfd, msg, sizeof(MSG), 0);printf("register : %s\n", msg->data);  return;
}//登录
int do_login(int sockfd, MSG *msg)
{//输入指令以及用户名和密码,发送给服务器msg->type = L;printf("input your name:");scanf("%s", msg->name);    printf("input your password:");scanf("%s", msg->data);send(sockfd, msg, sizeof(MSG), 0); //接收数据,判断是否登录成功recv(sockfd, msg, sizeof(MSG), 0);//如果登录成功,返回1if(strncmp(msg->data, "OK", 3) == 0){printf("login : OK\n");return 1;}//登录失败返回0printf("login : %s\n", msg->data);  return 0;
}//查询单词
void do_query(int sockfd, MSG *msg)
{//告知服务器查询单词msg->type = Q;puts("---------");while(1){printf("input word : ");scanf("%s", msg->data);//如果输入#,回退到上一层if(strcmp(msg->data, "#") == 0){break;}//发送指令和单词send(sockfd, msg, sizeof(MSG), 0); //接收数据recv(sockfd, msg, sizeof(MSG), 0);putchar(10);printf("********************************************************************************\n");printf("%s\n", msg->data);printf("********************************************************************************\n");putchar(10);}return;
}
//查询历史记录
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);}return;
}

Makefile

CC=gcc
CFGLASS=-Wall -g -c -O2all:server clientserver:server.o$(CC) $< -o $@ -lsqlite3client:client.o$(CC) $< -o $@%.o:%.c$(CC) $(CFGLASS) $< -o $@.PHONY:cleanclean:$(RM) -rf *.o a.out server client

运行结果

操作步骤

(1)执行命令make,生成可执行文件server和client。

(2)执行命令./server 127.0.0.1 10001,运行服务器端。

(3)执行命令./client 127.0.0.1 10001,模拟客户1。

(4)执行命令./client 127.0.0.1 10001,模拟客户2。

(5)在客户端按下Ctrl+C,关闭客户连接。

服务器

客户端1

客户端2

下载

基于Linux在线英语词典

http://download.csdn.net/download/u010872301/10049628

Linux多进程编程之在线词典相关推荐

  1. Linux -- 多进程编程之 - 守护进程

    内容概要 一.守护进程概述 二.守护进程创建 2.1.创建子进程,父进程退出 2.2.在子进程中创建新会话 2.2.1.进程组和会话期 2.2.2.setsid()函数说明 2.3.改变当前工作目录 ...

  2. LINUX 多进程编程 C语言实例

    LINUX多进程编程 简单实例 1.ps与top命令 查看进程状态 2.系统调用ping,并执行 #include <stdio.h> #include <string.h> ...

  3. linux多进程编程(一)

    2019独角兽企业重金招聘Python工程师标准>>> 最近因为一个偶然的原因要在linux平台上做一个模拟实验,其中要涉及到多进程的编程,所以特此写一系列的博客来总结一下多进程的编 ...

  4. Linux多进程编程(2)

    简介 IPC(Inter Process Communication,进程间通信)的方式总共有三种,分别是信号量.共享内存和消息队列,本文介绍前两种. 在Linux中,进程之间操作公共数据时,需要进行 ...

  5. Linux多进程编程

    fork系统调用 #include <sys/types.h> #include <unistd.h>/* Clone the calling process, creatin ...

  6. Linux网络编程之六 --在线英英字典的实现

    综合项目:在线英英字典 服务器端 head.h: ​ server.c do_client.c Makefile 客户端 head.h client.c Makefile 关注微信公众号获取更多资讯

  7. Linux多进程编程之 孤儿进程僵尸进程+wait函数

    我们可否想过一个问题:使用fork()函数创建子进程,因为父进程和子进程的执行顺序是随机的 当父进程已经结束了,子进程还会继续存在并正常执行吗? 我们先看这个例子: guer1.c #include& ...

  8. linux多进程编程计算圆周率,中值积分定理计算PI值的多线程实现

    // Parallel.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include #include static long num_ ...

  9. Linux多进程编程(1)

    fork函数与exec系列函数系统调用 fork系统调用用于产生一个子进程,下面是基础用法: #include <sys/types.h> #include <unistd.h> ...

最新文章

  1. Ansible自动化运维笔记1(安装配置)
  2. jQuery实现enter键登录
  3. SSM框架-使用MyBatis Generator自动创建代码
  4. at java.net.urlclassloader.findclass_如何使用URLClassLoader加载* .class文件?
  5. Providers in SAP Spartacus
  6. php吞了throw错误,PHP 异常与错误处理
  7. pythonwhile循环怎么修改数据类型_python基础--数据类型循环
  8. ZedGraph使用经验
  9. PAT乙级 1094 谷歌的招聘(柳婼代码,测试点1、2、4、5分析)
  10. java多按钮筛选条件_Excel办公技巧:如何对表格数据进行自定义筛选?
  11. mysql设置行值唯一_mysql怎么设置行值唯一?
  12. 轻量级Modal模态框插件cta.js
  13. Unity Shader播放序列帧动画
  14. 北漂程序员,何以露宿街头?
  15. hbuilder怎么设置网页的大小_怎么免费将图片转成PDF?这个方法超简单
  16. 产品市场调研分析报告、竞品分析报告、产品体验报告的区别
  17. 用flashAS3.0做一个连线题
  18. unity3d 双人巡逻兵网络游戏
  19. 关于用数组实现输入字符串以单词为元素反转输出思路
  20. linux不能打开流的函数为,详解 4 种电脑提示“无法访问函数不正确”的解决方法...

热门文章

  1. LSH︱python实现局部敏感哈希——LSHash(二)
  2. springBoot整合Dubbo使用与采坑
  3. 机器学习中常见的最优化方法
  4. windows Mobile使用ActiveSync上网
  5. [软件人生]关于认知,能力的思考——中国城市里的无知现象片段
  6. sersync+rsync 数据同步配置
  7. (8). 使用JPA保存数据【从零开始学Spring Boot】
  8. C#实现WebService服务 项目完整总结
  9. jquery tmpl的使用
  10. 排名前50的开源Web爬虫用于数据挖掘