C语言数据库:基于tcp多进程的在线词典,有详细的步骤已经图解,欢迎大家来观看

1.功能演示

 

 

 

 2.功能说明

大方向一共四个功能:

注册

登录

查询单词

查询历史记录

3.流程图

3.功能实现

1.搭建程序框架

2.实现注册和登录功能

3.查单词

4.查历史记

4. 代码实现

服务器代码:

#include "myhead.h"

int main(int argc, char const *argv[])
{
    if (argc != 3){
        printf("Please enter in format");
        exit(-1);
    }

    int socketfd;
    int acceptfd;
    pid_t pid;
    sqlite3* db;

    if (SQLITE_OK != sqlite3_open(DATABASE, &db)){
        printf("error:%s\n", sqlite3_errmsg(db));
        exit(-1);
    }

    //创建套接字
    if (-1 == (socketfd = socket(AF_INET, SOCK_STREAM, 0))){
        ERROR("socket error");
    }

    //填充网络信息结构体
    struct sockaddr_in serveraddr;
    memset(&serveraddr, 0, sizeof(serveraddr));
    serveraddr.sin_family = AF_INET;
    serveraddr.sin_port = htons(atoi(argv[2]));
    serveraddr.sin_addr.s_addr = inet_addr(argv[1]);
    socklen_t serveraddr_len = sizeof(serveraddr);

    //将网络信息结构体与套接字进行绑定
    if (-1 == bind(socketfd, (struct sockaddr*)&serveraddr, serveraddr_len)){
        ERROR("Server_connect error");
    }

    //将套接字设置为被动监听状态
    if (-1 == listen(socketfd, 5)){
        ERROR("listen error");
    }

    if (SIG_ERR == signal(SIGCHLD, handler)){
        ERROR("Server_signal error");
    }

    while (1){
        if (-1 == (acceptfd = accept(socketfd, NULL, NULL))){
            ERROR("accept error");
        }

        if ((pid = fork()) == -1){
            ERROR("Server_fork error");
        }else if(pid == 0){
            Server_Process(acceptfd, db);
        }else {
            close(acceptfd);
        }
    }

    return 0;
}

服务器代码函数:

#include "myhead.h"

void handler(int sig)
{
    wait(NULL);
}

void Server_Process(int acceptfd,sqlite3 *db)
{
    msg_t msg;

    while (recv(acceptfd, &msg, sizeof(msg_t), 0) > 0){
        printf("code = %c\n", msg.operator_code);
        printf("type = %s\n", msg.data);

        switch(msg.operator_code) {
            case 'r':
                Server_Register(acceptfd, &msg, db);
                break;
            case 'l':
                Server_Login(acceptfd, &msg, db);
                break;
            case 'h':
                Server_History(acceptfd, &msg, db);
                break;
            case 'c':
                Server_Refer(acceptfd, &msg, db);
                break;
        }
    }
}

void Server_Register(int acceptfd,msg_t* msg, sqlite3* db)
{
    char buff[K] = {0};
    sprintf(buff, "insert into usr values('%s', '%s')", msg->name, msg->data);

    if (SQLITE_OK != sqlite3_exec(db, buff, NULL, NULL, NULL)){
        sprintf(msg->data, "user %s already exist!!!", msg->name);
    }else {
        strcpy(msg->data, "ok");
    }

    if (-1 == send(acceptfd, msg, sizeof(msg_t), 0)){
        ERROR("Server_Register send error");
    }

    return;
}

void Server_Login(int acceptfd,msg_t* msg, sqlite3* db)
{
    char buff[K] = {0};
    int now;
    int column;
    char** result;
    
    sprintf(buff, "select * from usr where name='%s' and char='%s'", msg->name, msg->data);

    if (SQLITE_OK != sqlite3_get_table(db, buff, &result, &now, &column, NULL)){
        ERROR("Server_Login sqlite3_get_table error");
    }

    if (now == 1){
        strcpy(msg->data, "ok");
    }else {
        strcpy(msg->data, "login failure");   
    }

    if (-1 == send(acceptfd, msg, sizeof(msg_t), 0)){
        ERROR("Server_Login send error");
    }

    return;
}
int Server_Refer_searchword(int acceptfd,msg_t* msg)
{
    FILE* fp;
    char temp[F];
    int len;
    char *p;

    //保存单词长度
    len = strlen(msg->data);

    if (NULL == (fp = fopen("dict.txt", "r"))){
        strcpy(msg->data, "Server_Refer_searchword open error");

        if (-1 == send(acceptfd, msg, sizeof(msg_t), 0)){
            ERROR("Server_Refer_searchword send error");
        }
    }

    while (fgets(temp, sizeof(temp), fp) != NULL){
        
        if (!strncmp(msg->data, temp, len) && temp[len] == ' '){
             p = temp + len;

             while (*p == ' '){
                p++;
             }

                strcpy(msg->data, p);
                fclose(fp);
                return 1;
        }
    }
 
    strcpy(msg->data, "not found");
    fclose(fp);
    return 0;
}

void Server_Refer_getdata(char* data)
{
    time_t t;
    struct tm* tm;

    if (-1 ==(t = time(NULL))){
        ERROR("Server_Refer_getdata get time error");
    }

    if (NULL == (tm = localtime(&t))){
        ERROR("Server_Refer_getdata localtime error");
    }

    sprintf(data,"%d-%02d-%02d %02d:%02d:%02d\n", tm->tm_year+1900,\
    tm->tm_mon+1,tm->tm_mday,tm->tm_hour,tm->tm_min,tm->tm_sec);

    return;
}

void Server_Refer(int acceptfd,msg_t* msg, sqlite3* db)
{
    char buff[K] = {0};//用来插入历史记录
    char data[F] = {0};//用来记录时间
    char word[F] = {0};//用来提前保存一下单词
    int flag;

    strcpy(word, msg->data);

    flag = Server_Refer_searchword(acceptfd, msg);

    if (flag){
        Server_Refer_getdata(data);
        sprintf(buff, "insert into record values('%s', '%s', '%s')", msg->name, data, word);

        if (SQLITE_OK != sqlite3_exec(db, buff, NULL, NULL, NULL)){
            ERROR("Server_Refer sqlite3_exec error");
        }
    }

    printf("%s\n", msg->data);
    if (-1 == send(acceptfd, msg, sizeof(msg_t), 0)){
        ERROR("Server_Refer send error");
    }
}

int history_callback(void* arg, int f_num, char** f_value, char** f_name)
{
    msg_t msg;
    int acceptfd = *(int *)arg;
    sprintf(msg.data, "%s:%s", f_value[1],f_value[2]);

    if (-1 == send(acceptfd, &msg, sizeof(msg_t), 0)){
        ERROR("history_callback send error");
    }

    return 0;
}

void Server_History(int acceptfd,msg_t* msg, sqlite3* db)
{
    char buff[K];

    sprintf(buff, "select * from record where name ='%s'", msg->name);

    if (SQLITE_OK != sqlite3_exec(db, buff, history_callback, (void*)&acceptfd, NULL)){
        printf("Server_History errmsg >>%s\n", sqlite3_errmsg(db));
        exit(-1);
    }

    strcpy(msg->data, "over");

    if (-1 == send(acceptfd, msg, sizeof(msg_t), 0)){
        printf("Server_History\n");
    }
}

客户端代码:

#include "myhead.h"

int main(int argc, char const *argv[])
{
    if (argc != 3){
        printf("Please enter in format");
        exit(-1);
    }

    int socketfd;
    char choose;//用来做选择的
    msg_t msg;

    if (-1 == (socketfd = socket(AF_INET, SOCK_STREAM, 0))){
        ERROR("client_socket  error");
    }

    struct sockaddr_in cilentaddr;
    cilentaddr.sin_family = AF_INET;
    cilentaddr.sin_port = htons(atoi(argv[2]));
    cilentaddr.sin_addr.s_addr = inet_addr(argv[1]);
    socklen_t cilentaddr_len = sizeof(cilentaddr);

    if (-1 == connect(socketfd, (struct sockaddr*)&cilentaddr, cilentaddr_len)){
        ERROR("connect error");
    }

    while (1){
        printf("******************************\n");
        printf("  r注册        l登录      q退出\n");
        printf("*******************************\n");
        scanf("%c", &choose);

        switch (choose) {
            case 'r':
                Client_Register(socketfd, &msg);
                break;
            case 'l':
                if (Client_Login(socketfd, &msg)){
                    goto next;
                }
                break;
            case 'q':
                close(socketfd);
                exit(-1);
                break;
        }
    }

next:

    while (1){
        printf("***************************\n");
        printf("  c查阅      h历史     q退出\n");
        printf("***************************\n");
        scanf("%c", &choose);

        switch (choose) {
            case 'c':
                Client_Refer(socketfd, &msg);
                break;
            case 'h':
                Client_History(socketfd, &msg);
                break;
            case 'q':
                close(socketfd);
                exit(-1);
                break;
        }
    }
    return 0;
}

客户端代码函数:

#include "myhead.h"

void Client_Register(int socketfd, msg_t* msg)
{
    msg->operator_code = 'r';
    
    printf("input your name>>");
    scanf("%s", msg->name);
    
    printf("input your password>>");
    scanf("%s", msg->data);

    if (-1 == send(socketfd, msg, sizeof(msg_t), 0)){
        ERROR("Client_Register send error");
    }

    if (-1 == recv(socketfd, msg, sizeof(msg_t), 0)){
        ERROR("Client_Register recv error");
    }
    printf("log-on message>>%s\n", msg->data);
    return;
}

int Client_Login(int socketfd, msg_t* msg)
{
    msg->operator_code = 'l';
    printf("input your name>>");
    scanf("%s", msg->name);
    printf("input your password>>");
    scanf("%s", msg->data);

    if (-1 == send(socketfd, msg, sizeof(msg_t), 0)){
        ERROR("Client_Login send error");
    }

    if (-1 == recv(socketfd, msg, sizeof(msg_t), 0)){
        ERROR("Client_Login recv error");
    }

    if (!strncmp(msg->data, "ok", 3)){
        printf("login:ok\n");
        return 1;
    }else {
        printf("login:%s\n", msg->data);
        return 0;
    }

}
void Client_Refer(int socketfd, msg_t* msg)
{   
    msg->operator_code = 'c';

    while(1) {
        printf("Please enter the word you are looking for(is # is end)>>");
        scanf("%s", msg->data);

        if (!strncmp(msg->data, "#", 2)){
            break;
        }

        if (-1 == send(socketfd, msg, sizeof(msg_t), 0)){
            ERROR("Client_History send error");
        }

        if (-1 == recv(socketfd, msg, sizeof(msg_t), 0)){
            ERROR("Client_History recv error");
        }

        printf("The word meaning>>%s\n", msg->data);
    }

}
void Client_History(int socketfd, msg_t* msg)
{
    msg->operator_code = 'h';

    if (-1 == send(socketfd, msg, sizeof(msg_t), 0)){
        ERROR("Client_History send error");
    }

    while (1){
        if (-1 == recv(socketfd, msg, sizeof(msg_t), 0)){
            ERROR("Client_History recv error");
        }

        if (!strcmp(msg->data, "over")){
            break;
        }

        printf("history>>%s\n", msg->data);
    }

    return;
}

头文件:

#ifndef __MYHEAD_H__
#define __MYHEAD_H_
#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>
#include <sys/wait.h>

#define DATABASE "my.db" //定义数据库名

#define ERROR(msg) do{\
    printf("%s %s %d\n", __func__, __FILE__, __LINE__);\
    perror(msg);\
    exit(-1);}while(0);

#define N 16 //姓名长度
#define M 256 //数据长度以及错误信息
#define K 512 //用来插入数据库命令
#define F 128 //用来记录时间,以及提前保存一下单词

typedef struct MSG{
    char operator_code;//操作码
    char name[N];//姓名
    char data[M];//数据
}msg_t;

//服务器的函数声明
void handler(int sig);
void Server_Process(int acceptfd,sqlite3 *db);
void Server_Register(int acceptfd,msg_t* msg, sqlite3* db);
void Server_Login(int acceptfd,msg_t* msg, sqlite3* db);
void Server_History(int acceptfd,msg_t* msg, sqlite3* db);
void Server_Refer(int acceptfd,msg_t* msg, sqlite3* db);

//客户端的函数声明
void Client_Register(int socketfd, msg_t* msg);
int Client_Login(int socketfd, msg_t* msg);
void Client_Refer(int socketfd, msg_t* msg);
void Client_History(int socketfd, msg_t* msg);
#endif

  • 22
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
### 回答1: TCP多进程并发服务器多进程客户端是一种网络编程模型,用于实现高并发的网络通信。在这种模型中,服务器和客户端都使用多个进程来处理并发连接请求,从而提高系统的处理能力和响应速度。 TCP多进程并发服务器通常采用多线程或多进程的方式来处理客户端连接请求,每个线程或进程负责处理一个客户端连接。当有新的连接请求到达时,服务器会创建一个新的线程或进程来处理该连接,从而实现并发处理多个连接的能力。 多进程客户端也是类似的,它可以同时与多个服务器建立连接,并使用多个进程来处理这些连接。每个进程负责处理一个连接,当连接结束时,进程会被释放,从而释放系统资源。 总的来说,TCP多进程并发服务器多进程客户端是一种高效的网络编程模型,可以提高系统的处理能力和响应速度,适用于需要处理大量并发连接的网络应用场景。 ### 回答2: TCP多进程并发服务器是指服务器可以同时处理多个客户端的请求,服务器不会阻塞在单个请求上。每当一个客户端连接到服务器服务器会启动一个新的进程来处理该客户端的请求。这些进程是独立的,可以同时运行,每个进程只负责处理与其连接的客户端请求,从而实现了服务器的并行处理。 多进程客户端是指客户端同时启动多个子进程或线程进行数据请求,每个子进程或线程各自独立工作,可以同时向服务器发送请求,提高了客户端的处理能力和请求效率。 TCP多进程并发服务器多进程客户端都是为了提高请求处理的效率,特别是在高并发情况下。但是,两者的实现方式有所不同。多进程并发服务器更加复杂,需要合理分配进程资源,防止进程过多导致系统负载过高;而多进程客户端相对简单,只需要注意并发请求的并发数限制就可以了。 此外,在实际应用过程中还需要注意以下几点: 1.多进程并发服务器多进程客户端需要考虑进程的创建、销毁和通信机制。 2.在高并发情况下,需要考虑进程和线程的竞争和锁机制。 3.需要合理分配资源,避免进程资源浪费和系统负载过高。 4.需要优化网络传输和数据处理算法,提升效率。 总之,TCP多进程并发服务器多进程客户端都是应对高并发请求的有效手段,但是在实际应用中需要考虑多方面因素,避免出现不必要的问题。 ### 回答3: TCP多进程并发服务器多进程客户端是在网络编程中广泛使用的技术,主要是为了解决服务器和客户端在处理多个连接请求时的效率和并发性问题。下面简要介绍这两种技术的概念、实现和优缺点。 TCP多进程并发服务器是指在一个主进程中创建多个子进程,每个子进程负责处理一个客户端的连接请求。当有多个客户端同时连接到服务器时,每个客户端连接都会创建一个子进程来处理其请求。子进程之间是独立的,相互之间不会干扰,从而保证了服务器的并发处理能力和效率。同时,由于每个子进程只处理一个客户端连接请求,从而降低了进程间的通信开销,提高了响应速度。 TCP多进程客户端是指在一个主进程中创建多个进程,每个进程负责向服务器发起连接请求,进行数据交换。当多个客户端同时连接到服务器时,它们之间是独立的,相互之间不会干扰,从而保证了客户端的并发处理能力和效率。 对于TCP多进程并发服务器多进程客户端,其实现可以使用fork系统调用或者并发编程框架如Python的multiprocessing模块等实现。在编写程序时,需要注意进程间通信和数据传输的问题,如进程间的互斥、同步和共享资源问题等。 优点: 1. 服务器端和客户端都具有良好的并发处理能力,可以同时处理多个连接请求。 2. 多进程之间相互独立,不会相互干扰,保证了系统的稳定性和可靠性。 3. TCP协议本身具有可靠性和稳定性等优点,保证了数据传输的准确性和完整性。 缺点: 1. 多进程之间的切换和数据交换会增加系统的开销和负担,可能会影响系统性能。 2. 程序的编写复杂度较高,需要考虑进程间通信、同步和共享资源等问题。 3. 程序的调试和维护较为困难,需要考虑多个进程之间的相互影响。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值