免费的行情网站ifind是,qq营销推广方法和手段,学工网站建设,广州网站的建设公司15_Dictionary
在线词典
搭建客户端-服务器架构
准备必要的资源
整理原始数据
整理英汉双语对照表#xff0c;将XLSX格式转换成CSV格式#xff0c;准备好vocabulary_list.csv文件备用 注意#xff1a;CSV格式的文件必须使用UTF-8的字符集#xff1b;
建立mydatabase.…15_Dictionary
在线词典
搭建客户端-服务器架构
准备必要的资源
整理原始数据
整理英汉双语对照表将XLSX格式转换成CSV格式准备好vocabulary_list.csv文件备用 注意CSV格式的文件必须使用UTF-8的字符集
建立mydatabase.db数据库并创建dictionary表
shell命令行终端输入sqlite3 mydatabase.db
create table dictionary (
English text not null,
Chinese text not null);sqlite3当中CSV格式的导入
.mode csv
.import vocabulary_list.csv dictionary查询数据
select * from dictionary where Englishmain;如果显示如下信息表示配置成功
main,a.主要的最重要的实现服务端代码
udp.h
包含必要的头文件定义必要的宏定义函数指针
#ifndef _UDP_H_
#define _UDP_H_#include stdio.h
#include stdlib.h
#include unistd.h
#include string.h
#include sys/socket.h
#include netinet/in.h
#include netinet/udp.h
#include errno.h
#include arpa/inet.h#define ErrExit(msg) printf([%s:%d]%s:%s, __FUNCTION__, __LINE__,msg, strerror(errno)), exit(EXIT_FAILURE)#endifudp.c
实现UDP通信预留udp_main接口
#include udp.hextern void udp_main(const int fd, const struct sockaddr_in *addr);int main(int argc, const char *argv[])
{/* 1.检查参数 */if(argc 3) {printf([%s][addr][port]\n, argv[0]);exit(EXIT_FAILURE);}/* 2.创建数据报套接字 */int fd socket(AF_INET, SOCK_DGRAM, 0);if(fd 0)ErrExit(socket);/* 3.设置通信结构体 */struct sockaddr_in addr;addr.sin_family AF_INET;addr.sin_port htons( atoi(argv[2]) );if( inet_aton(argv[1], addr.sin_addr) 0) {printf([%s:%d] Invalid address\n, __FUNCTION__, __LINE__);exit(EXIT_FAILURE);}/* 4.绑定通信结构体 */if( bind(fd, (struct sockaddr *)addr, sizeof(addr) ) )ErrExit(bind);/* 5.处理客户端数据 */udp_main(fd, addr);/* 6.关闭套接字 */close(fd);return 0;
}udp_main.c
预留的客户端数据处理接口
#include udp.h/* 其他必要的环境已封装好了只需要实现与客户端的交互即可* 这里的fd是服务端的socket* addr是服务端的地址*/
void udp_main(const int fd, const struct sockaddr_in *addr) {printf(udp main test.\n);
}实现词典查询功能
在文件udp_main.c实现词典查询功能
#include udp.h
#include ctype.h
#include sqlite3.h#define DATABASE_NAME mydatabase.dbint callback(void *, int, char **, char **);/* 其他必要的环境已封装好了只需要实现与客户端的交互即可* 这里的fd是服务端的socket* addr是服务端的地址*/
void udp_main(const int fd, const struct sockaddr_in *addr) {int ret 0, rc;struct sockaddr_in client_addr;socklen_t addrlen sizeof(client_addr);sqlite3 *db;char buf[BUFSIZ] {};char *sql_query, *errmsg;/* 1.打开数据库 */if( (rc sqlite3_open(DATABASE_NAME, db) ) ) {printf([%s:%d]无法打开数据库: %s\n, __FUNCTION__, __LINE__, sqlite3_errmsg(db) );exit(0);}/* 2.循环处理客户端数据 */while(1) {/* 2.1.接收客户端数据 */do {ret recvfrom(fd, buf, BUFSIZ, 0, (struct sockaddr *)client_addr, addrlen);}while(ret 0 errno EINTR);if(ret 0)ErrExit(recvfrom);printf([%s:%d]收到的数据: {%s}\n, __FUNCTION__, __LINE__, buf);/* 2.2.提取需要翻译的单词 */for(ret 0; isalpha(buf[ret]) || buf[ret] ; ret);buf[ret] \0;/* 2.3.用SQL语句进行查询 */sql_query sqlite3_mprintf(select * from dictionary where english like %s, buf);rc sqlite3_exec(db, sql_query, callback, buf, errmsg);if(rc ! SQLITE_OK) {sprintf(buf, 查询失败:%s\n, errmsg);printf([%s:%d]%s, __FUNCTION__, __LINE__, buf);sendto(fd, buf, strlen(buf) 1, 0, (struct sockaddr *)client_addr, addrlen);sqlite3_free(errmsg);continue;}sqlite3_free(sql_query);printf([%s:%d]查询结果: {%s}\n, __FUNCTION__, __LINE__, buf);sendto(fd, buf, strlen(buf) 1, 0, (struct sockaddr *)client_addr, addrlen);}sqlite3_close(db);/* 3.关闭数据库关闭fd并且退出程序 */close(fd);
}int callback(void *NotUsed, int argc, char **argv, char **ColName) {char *buf NotUsed;if(argc 2) {/* 把查询到的字符串复制给buf */strncpy(buf, argv[1], strlen(argv[1]) 1 );} elsebuf[0] \0; //如果失败就将字符串置空/* 将换行符替换为\0 */buf[strlen(argv[1])] \n;buf[strlen(argv[1])1] \0;return 0;
}实现用户操作和服务端交互过程
接下来我们把文件组织成如下形式执行tree命令可以看到
备注如果没安装可以使用sudo apt-get install tree命令进行安装
设置环境变量
编辑.bashrc文件 执行sudo vim ~/.bashrc打开家目录下的.bashrc在文件末尾加上如下两句
export DICTIONARY_SERVER_HOST127.0.0.1
export DICTIONARY_SERVER_PORT8888然后再执行source ~/.bashrc让.bashrc生效 最后执行env | grep DICTIONARY如果能看到我们刚设置的命令表示环境变量生效了
connect函数是否可以用在UDP通信当中
在UDP通信中使用connect()函数发出“虚拟连接请求”以便建立虚拟连接。通过调用connect()函数可以将UDP套接字绑定到目标IP地址和端口上从而为UDP数据报提供一个默认的发送目的地。这样在后续的send()函数调用中就不需要再指定IP地址和端口。 但是需要注意的是在UDP通信中由于不存在真正的连接因此connect()函数并不会像TCP中那样进行三次握手。它只是在内核中存储了该套接字的目标地址并在后续的send()或recv()函数调用中使用该目标地址。 下面是一个示例代码片段展示如何在UDP通信中使用connect()函数
#include stdio.h
#include stdlib.h
#include string.h
#include netinet/in.h
#include sys/socket.h#define BUF_SIZE 1024int main(int argc, char *argv[]) {if (argc ! 3) {printf(Usage: %s IP port\n, argv[0]);exit(1);}int sockfd socket(AF_INET, SOCK_DGRAM, 0);if (sockfd -1) {perror(socket);exit(1);}struct sockaddr_in dest_addr;memset(dest_addr, 0, sizeof(dest_addr));dest_addr.sin_family AF_INET;dest_addr.sin_addr.s_addr inet_addr(argv[1]);dest_addr.sin_port htons(atoi(argv[2]));if (connect(sockfd, (struct sockaddr *)dest_addr, sizeof(dest_addr)) -1) {perror(connect);exit(1);}char buf[BUF_SIZE];printf(Enter message: );fgets(buf, BUF_SIZE, stdin);if (send(sockfd, buf, strlen(buf), 0) -1) {perror(send);exit(1);}close(sockfd);return 0;
}编写客户端代码
这里我们对client下的文件进行编辑
udp.c
#include udp.hextern void udp_main(const int fd, const char *argv);int main(int argc, const char *argv[])
{/* 获取环境变量DICTIONARY_SERVER_PORT */char *port getenv(DICTIONARY_SERVER_PORT);if(port NULL) {printf(没有发现环境变量[DICTIONARY_SERVER_PORT]\n);exit(EXIT_FAILURE);}/* 获取环境变量DICTIONARY_SERVER_HOST */char *host getenv(DICTIONARY_SERVER_HOST);if(port NULL) {printf(没有发现环境变量[DICTIONARY_SERVER_HOST]\n);exit(EXIT_FAILURE);}/* 检查参数, 其中第二个参数是需要翻译的单词 */if(argc 2) {printf([%s][word]\n, argv[0]);exit(EXIT_FAILURE);}/* 打印环境变量的值 */printf(服务器的主机IP是%s, 端口号是%s\n, host, port);int fd socket(AF_INET, SOCK_DGRAM, 0);if(fd 0)ErrExit(socket);/* 设置通信结构体 */struct sockaddr_in addr;addr.sin_family AF_INET;addr.sin_port htons( atoi(port) );if( inet_aton( host, addr.sin_addr) 0) {printf([%s:%d] Invalid address\n, __FUNCTION__, __LINE__);exit(EXIT_FAILURE);}/* 发起连接请求,注意UDP连接没有三次握手, 不存在连接失败, 只是确定接受端而已 */if(connect(fd, (struct sockaddr *)addr, sizeof(addr) ) )ErrExit(connect);/* 执行客户端处理程序 */udp_main(fd, argv[1]);/* 关闭套接字 */close(fd);return 0;
}udp_main.c
#include udp.h/* 其他必要的环境已封装好了只需要实现与客户端的交互即可* 这里的fd是服务端的socket* addr是服务端的地址*/
extern void udp_main(const int fd, const char *argv) {char buf[BUFSIZ] {};send(fd, argv, strlen(argv) 1, 0);recv(fd, buf, BUFSIZ, 0);printf(buf%s\n, buf);
}编译
执行gcc *.c -o test -Wall -lsqlite3 -I ../head/, 得到test的可执行文件 然后分别运行两边的test文件
得到类似这样的结果表示代码没有问题可以得到想要的结果 至此就实现了基本功能接下来再实现其它附加的功能