基于TCP传输,数据库存储电子词典

客户端

.h文件

#ifndef __DICT_C_H__
#define __DICT_C_H__

#define ERR_MSG(msg){\
    fprintf(stderr,"line:%d\n",__LINE__);\
    perror(msg);\
}while(0);
//登录与注册
int do_load(int sig);
//菜单
int do_menu(int sfd);
//查找单词
int do_select(int sfd);
//查询历史记录
int do_history(int sfd);
//返回上级
int do_quit(int sfd);


#endif

.c文件

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include "dict_c.h"
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <sys/select.h>
#include <sys/time.h>

struct msg{
    char type;//任务标志位
    char name[30];//名字
    char password[30];//密码
    char word[30];//单词
    char chin[50];//存储翻译
    char time[30];//时间
}s;

#define IP "192.168.10.4"
#define PORT 6666

int do_load(int sig)
{
    int sfd = socket(AF_INET,SOCK_STREAM,0);//创建流式套接字
    if(sfd < 0)
    {
        ERR_MSG("socket");
        return -1;
    }

    struct sockaddr_in sin;//填写服务器地址信息结构体
    sin.sin_family = AF_INET;
    sin.sin_port = htons(PORT);
    sin.sin_addr.s_addr = inet_addr(IP);
    socklen_t addrlen = sizeof(sin);

    if(connect(sfd,(struct sockaddr*)&sin,addrlen) < 0)//连接到服务器
    {
        ERR_MSG("connect");
        return -1;
    }
    printf("connect success!\n");

    int con = 0;
    while(1)
    {
        bzero(s.name,sizeof(s.name));
        bzero(s.password,sizeof(s.password));

        printf("请输入用户名:\n");
        fgets(s.name,sizeof(s.name),stdin);
        s.name[strlen(s.name) -1] = 0;

        printf("请输入密码:\n");
        fgets(s.password,sizeof(s.password),stdin);
        s.password[strlen(s.password) -1] = 0;

        if(1 == sig)
            s.type = 'l';//登录标示
        else
            s.type = 'e';//注册标示

        if(send(sfd,&s,sizeof(s),0) < 0)
        {
            ERR_MSG("send");
            return -1;
        }
        printf("send success!\n");

        if(recv(sfd,&s,sizeof(s),0) < 0)
        {
            ERR_MSG("recv");
            return -1;
        }
        if('y' == s.type)//返回登录或注册成功标示'y'
        {
            do_menu(sfd);
            break;
        }
        else if('e' == s.type)//注册失败
            printf("注册失败\n");
        else//登录失败
            printf("%s\n",s.chin);//输出登录失败原因

        printf("继续请按1\n");
        scanf("%d",&con);
        while(getchar()!=10);
        if(con != 1)
          break;
    }
    close(sfd);
    return 0;
}

int do_menu(int sfd)
{
    int sig = 0;
    while(1)
    {
        system("clear");
        printf("********************\n");
        printf("***1.查找单词*******\n");
        printf("***2.查询历史记录***\n");
        printf("***3.返回上级*******\n");
        printf("********************\n");
        printf("请输入>>");
        scanf("%d",&sig);
        while(getchar()!=10);
        switch(sig)
        {
        case 1:
            do_select(sfd);
            break;
        case 2:
            do_history(sfd);
            break;
        case 3:
            do_quit(sfd);
            goto END;
        default:
            printf("输入错误,请重新输入\n");
        }
        printf("按任意字符清屏\n");
        while(getchar()!=10);    
    }
END:
    return 0;
}

int do_select(int sfd)
{
    fd_set readfds, tempfds;    
    FD_ZERO(&readfds);     //清空文件描述符集合
    FD_ZERO(&tempfds);

    FD_SET(0, &readfds);
    FD_SET(sfd, &readfds);
    int maxfd = sfd; 
    int s_res = 0;
    while(1)
    {
        tempfds = readfds;
        s_res = select(maxfd+1, &tempfds, NULL, NULL, NULL);
        if(s_res < 0)
        {
            ERR_MSG("select");
            return -1;
        }
        else if(0 == s_res)
        {
            printf("time out...\n");
            break;
        }


        if(FD_ISSET(0,&tempfds) != 0)
        {
             bzero(s.word,sizeof(s.word));
            scanf("%s",s.word);
            while(getchar()!=10);
            if(strcmp(s.word,".quit") == 0)//退出查找条件
                break;

            s.type = 'f';
            if(send(sfd,&s,sizeof(s),0) < 0)//发送查找信息
            {
                ERR_MSG("send");
                return -1;
            }
            printf("正在查询%s\n",s.word);
        }

        if(FD_ISSET(sfd,&tempfds) != 0)
        {
            if(recv(sfd,&s,sizeof(s),0) < 0)//接收查找结果
            {
                ERR_MSG("recv");
                return -1;
            }
            printf("查询结果:%s : %s\n",s.word,s.chin);//显示查找结果
        }
    }

    
}
//发送查询历史记录信息
int do_history(int sfd)
{
    s.type = 'h';
    if(send(sfd,&s,sizeof(s),0) < 0)//发送查询历史记录信息
    {
          ERR_MSG("send");
           return -1;
      }

    fd_set readfds, tempfds;    
    FD_ZERO(&readfds);     //清空文件描述符集合
    FD_ZERO(&tempfds);

    FD_SET(0, &readfds);
    FD_SET(sfd, &readfds);
    int maxfd = sfd; 
    int s_res = 0;
    char con[10] = "";
    printf("查询结束按.quit退出\n");
    while(1)
    {
        tempfds = readfds;
        s_res = select(maxfd+1, &tempfds, NULL, NULL, NULL);
        if(s_res < 0)
        {
            ERR_MSG("select");
            return -1;
        }
        else if(0 == s_res)
        {
            printf("time out...\n");
            break;
        }


        if(FD_ISSET(0,&tempfds) != 0)
        {
            scanf("%s",con);
            while(getchar()!=10);
            if(strcmp(con,".quit") == 0)//退出查找条件
            printf("退出查询\n");
                break;
        }

        if(FD_ISSET(sfd,&tempfds) != 0)
        {
            if(recv(sfd,&s,sizeof(s),0) < 0)//接收查找结果
            {
                ERR_MSG("recv");
                return -1;
            }
            if(s.type == 'h')
                printf("%s: %s %s %s\n",s.name,s.word,s.chin,s.time);//显示查找结果
            else
                printf("暂无查询记录\n");
        }
    }
    return 0;
}
//删除load表中登录状态
int do_quit(int sfd)
{
    s.type = 'q';
    if(send(sfd,&s,sizeof(s),0) < 0)//发送查询历史记录信息
    {
          ERR_MSG("send");
           return -1;
      }
    return 0;

}

main文件

//用户端:
//功能包括
//功能包括:一级目录->登录.注册,退出 (只有登录或者注册成功才能进入二级目录)
//         二级目录->查询单词,查看历史记录,返回上级
//
//         定义发送的协议包:发送的type='l'表示登录信息;发送的type='e'表示注册
//         发送的type= 'f'表示查询单词;发送的type='h'表示查看历史记录
//         发送的type= 'q'表示返回上级
//
//         接收:接收时根据type选择不同的输出
//
//子进程负责TCP传输用户端与服务端沟通沟通

#include <stdio.h>
#include <stdlib.h>
#include "dict_c.h"


int main(int argc, const char *argv[])
{
    int sig = 0;
    while(1)
    {
        system("clear");
        printf("********************\n");
        printf("*******1.登录*******\n");
        printf("*******2.注册*******\n");
        printf("*******3.退出*******\n");
        printf("********************\n");
        printf("请输入>>");
        scanf("%d",&sig);
        while(getchar()!=10);
        switch(sig)
        {
        case 1:
            do_load(sig);
            break;
        case 2:
            do_load(sig);
            break;
        case 3:
            goto END;
        default:
            printf("输入错误,请重新输入\n");
        }
        printf("按任意字符清屏\n");
        while(getchar()!=10);
    }
END:
    return 0;
}

Makefile文件

TARGET:=client

OBJS:=main_c.o dict_c.o

CC:=gcc

CFLAGS:= -o
CFLAGSs:= -c -o

$(TARGET):$(OBJS)
    $(CC) $^ $(CFLAGS) $@ -lsqlite3

%.o:%.c 
    $(CC) $< $(CFLAGSs) $@

.PHONY:free

free:
    rm *.o

服务端

main文件

//服务端
#include <stdio.h>
#include <sqlite3.h>
#include <stdlib.h>
#include <string.h>
#include "dict_s.h"

//主进程负责监听
//
//数据库包括单词表(单词与翻译),用户注册表(用户名(不可重复)与密码),
//查询历史记录表(用户名,单词,翻译,查询时间),登录用户表(用户名)
//
//子进程负责TCP服务器与用户端沟通
int main(int argc, const char *argv[])
{
    //打开数据库,并初始化数据库
   init_sqlite3();

    //载入单词表
    word_install();

    //搭建TCP服务器
    //并发多进程服务器
    mu_pro();
    return 0;

}

.c文件

#include <stdio.h>
#include <sqlite3.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/wait.h>
#include <unistd.h>
#include <time.h>
#include "dict_s.h"

#define IP "192.168.10.4"
#define PORT 6666

sqlite3 *sq = NULL;

//建立或打开数据库,将数据库中的内容初始化
void init_sqlite3()
{
    char *errmsg = NULL;
    if(sqlite3_open("my.dl",&sq) != SQLITE_OK)
    {
        fprintf(stderr,"err_msg[%d] : %s line:%d\n",\
                sqlite3_errcode(sq),sqlite3_errmsg(sq),__LINE__);
        return ;
    }
    printf("数据库访问成功\n");


    //创建单词表dict(载入单词),用户注册表reg(保留用户名,密码);历史记录表his(查询历史记录),用户登录表load(防止重登录)
    char buf[128] = "create table if not exists dict (word char,chin char);";
    if(sqlite3_exec(sq,buf,NULL,NULL,&errmsg) != SQLITE_OK )
    {
        fprintf(stderr,"err_msg[%d] : %s line:%d\n",\
                sqlite3_errcode(sq),sqlite3_errmsg(sq),__LINE__);
        return ;
    }
    char delete[64] = "delete from dict;";//删除可能之前载入的内容,防止重复载入
    if(sqlite3_exec(sq,delete,NULL,NULL,&errmsg) != SQLITE_OK )
    {
        fprintf(stderr,"err_msg[%d] : %s line:%d\n",\
                sqlite3_errcode(sq),sqlite3_errmsg(sq),__LINE__);
        return ;
    }

    bzero(buf,sizeof(buf));
    sprintf(buf,"create table if not exists reg (name char primary key,password char);");
    if(sqlite3_exec(sq,buf,NULL,NULL,&errmsg) != SQLITE_OK )
    {
        fprintf(stderr,"err_msg[%d] : %s line:%d\n",\
                sqlite3_errcode(sq),sqlite3_errmsg(sq),__LINE__);
        return ;
    }

    bzero(buf,sizeof(buf));
    sprintf(buf,"create table if not exists his (name char,word char,chin char,time char);");
    if(sqlite3_exec(sq,buf,NULL,NULL,&errmsg) != SQLITE_OK )
    {
        fprintf(stderr,"err_msg[%d] : %s line:%d\n",\
                sqlite3_errcode(sq),sqlite3_errmsg(sq),__LINE__);
        return ;
    }

    bzero(buf,sizeof(buf));
    sprintf(buf,"create table if not exists load (name char primary key);");
    if(sqlite3_exec(sq,buf,NULL,NULL,&errmsg) != SQLITE_OK )
    {
        fprintf(stderr,"err_msg[%d] : %s line:%d\n",\
                sqlite3_errcode(sq),sqlite3_errmsg(sq),__LINE__);
        return ;
    }
    sprintf(delete,"delete from load;");//有内容就清空
    if(sqlite3_exec(sq,delete,NULL,NULL,&errmsg) != SQLITE_OK )
    {
        fprintf(stderr,"err_msg[%d] : %s line:%d\n",\
                sqlite3_errcode(sq),sqlite3_errmsg(sq),__LINE__);
        return ;
    }
}


int word_install()
{
    FILE *fp = fopen("./dict.txt","r");
    if(NULL == fp)
    {
        ERR_MSG("open");
        return -1;
    }
    char *errmsg = NULL;
    char word[50] = "";
    char chin[50] = "";
    char sql[128] = "";
    int i = 0;
    while(1)
    {
        bzero(word,sizeof(word));
        bzero(chin,sizeof(chin));
        bzero(sql,sizeof(sql));
 
        if(fgets(sql,sizeof(sql),fp) == NULL)//读取一行内容
        {
            printf("读取结束\n");
            return 0;
         }
 
        for(i = 0;i < strlen(sql);i++)
        {
            if(sql[i] == ' '&& sql[i+1] == ' ')//防止可能的双单词现象
            {
                break;
            }
            word[i] = sql[i];//将第一个字符串给单词数组
        }
 
        for(;i < strlen(sql);i++)
        {
           if(sql[i] != ' ')
           {
               break;
           }
        }
        for(int j = 0;j < strlen(sql);j++)
        {
            if(sql[i] == 0)
            {
                break;
            }
            chin[j] = sql[i];
            i++;
        }
        chin[strlen(chin)-1] = 0;

        bzero(sql,sizeof(sql));
        sprintf(sql,"%s\"%s\"%s\"%s\"%s","insert into dict values (",word,",",chin,");");
     
        if(sqlite3_exec(sq,sql,NULL,NULL,&errmsg) != SQLITE_OK)
        {
            fprintf(stderr,"line:%d sqlite3_exec failed:%s\n",__LINE__,errmsg);
            return -1;
        }
    }
    return 0;
}

//父子进程,父进程负责检测是否有客户端连接
//子进程负责与客户端交互,子进程退出信号回收
//每一个客户端一个子进程,newfd不会被覆盖
 void handler(int sig)
 {
     while(waitpid(-1, NULL, WNOHANG) > 0);
 }
int mu_pro()
{
    sighandler_t s = signal(17,handler);
    if(SIG_ERR == s)
    {
        ERR_MSG("signal");
        return -1;
    }
    int sfd = socket(AF_INET,SOCK_STREAM,0);
    if(sfd < 0)
    {
        ERR_MSG("socket");
        return -1;
    }
    //填写地址信息结构体,绑定端口与IP
    struct sockaddr_in sin;
    sin.sin_family = AF_INET;
    sin.sin_port = htons(PORT);
    sin.sin_addr.s_addr = inet_addr(IP);

    if(bind(sfd,(struct sockaddr*)&sin,sizeof(sin)) < 0)
    {
        ERR_MSG("bind");
        return -1;
    }
    printf("bind success\n");
    //监听
    if(listen(sfd,128) < 0)
    {
        ERR_MSG("listen");
        return -1;
    }
    struct sockaddr_in cin;
    socklen_t addrlen = sizeof(cin);
    int newfd = 0;
    pid_t pid = 0;
    while(1)
    {
        newfd = accept(sfd,(struct sockaddr*)&cin,&addrlen);
        if(newfd < 0)
        {
            ERR_MSG("accept");
                return -1;
        }
        printf("accept success\n");

        pid = fork();
        if(0 == pid)
        {
            close(sfd);
            deal_cli_msg(newfd);
            close(newfd);
            exit(0);
        }
        else if(pid > 0)
            close(newfd);
        else
        {
            ERR_MSG("fork");
            return -1;
        }
    }
    close(sfd);
    return 0;
}

//子进程接收客户端的信息,并根据信息类型做出应答
//函数本身并不操作数据库,根据信息类型执行对应函数来操作数据库
int deal_cli_msg(int newfd)
{
    ssize_t res = 0;
    struct sockaddr_in cin;
    socklen_t addrlen = sizeof(cin);
    while(1)
     {
         //接收
         res = recv(newfd,&m, sizeof(m), 0);
         if(res < 0)
         {
             ERR_MSG("recv");
             return -1;
         }
         else if(0 == res)
         {
             fprintf(stderr, "[%s:%d] newfd = %d 客户端下线\n", inet_ntoa(cin.sin_addr), ntohs(cin.sin_port),newfd);
             //异常下线
             quit(newfd);
             break;
         }
         switch(m.type)
         {
         case 'l'://登录
             load(newfd);
             break;
         case 'e'://注册
             insert(newfd);
             break;
         case 'f'://查找单词
             find(newfd);
             break;
         case 'h'://查询历史记录
             history(newfd);
             break;
         case 'q'://退出登录
             quit(newfd);
             goto END;
         }
     }
END:    
    if(sqlite3_close(sq) != SQLITE_OK)//关闭数据库
    {
        fprintf(stderr,"line:%d sqlite3_close failed\n",__LINE__);
        return -1;
    }
    return 0;
}

//先去注册表比对用户名与密码,再去用户登录表确定用户是否重复登录
//符合返回type = 'y'表示登录成功,不符合就按原来的type发回去
int load(int newfd)
{
    char *errmsg = NULL;
    int flag = 0;
    //注册表中对比用户信息
    char sql[128] = "select * from reg where name=";
    sprintf(sql,"%s\"%s\"%s",sql,m.name,";");
    printf("sql = %s\n",sql);
    if(sqlite3_exec(sq, sql, select_callBack, &flag, &errmsg) != SQLITE_OK)
    {
        fprintf(stderr, "line:%d sqlite3_exec:%s\n", __LINE__, errmsg);
    }
    if(0 == flag)//回调函数未被调用,用户名,密码错误,登录失败
    {
       bzero(m.chin,sizeof(m.chin));
       sprintf(m.chin,"登录失败,请检查用户名,密码;或确定是否注册");
       printf("%s\n",m.chin);
       if(send(newfd,&m,sizeof(m),0) < 0)
       {
           ERR_MSG("send");
           return -1;
       }
       return -1;//登录失败,登录程序结束
    }
    //检查是否重复登录
    sprintf(sql,"insert into load values (");
    sprintf(sql,"%s\"%s\"%s",sql,m.name,");");
    printf("%s\n",sql);
    if(sqlite3_exec(sq, sql, select_callBack, &flag, &errmsg) != SQLITE_OK)
    {
       fprintf(stderr, "line:%d sqlite3_exec:%s\n", __LINE__, errmsg);
          bzero(m.chin,sizeof(m.chin));
       sprintf(m.chin,"请勿重复登录");
       if(send(newfd,&m,sizeof(m),0) < 0)
       {
           ERR_MSG("send");
           return -1;
       }
        return -1;
    }
    m.type = 'y';
    if(send(newfd,&m,sizeof(m),0) < 0)
    {
        ERR_MSG("send");
        return -1;
    }
}
//回调函数用于返回数据库的查询内容,查看用户密码,对比密码
int select_callBack(void *arg, int column, char **column_text, char **column_name)
{
    *(int*)arg = 1;

    printf("%s\n",column_text[1]);
    if(strcmp(column_text[1],m.password) != 0)//对比密码
    {
        *(int*)arg = 0;//用于返回登录失败信息
    }
    return 0;
}
//注册
int insert(int newfd)
{
    char *errmsg = NULL;
    char sql[128] = "insert into reg values(";

    sprintf(sql,"%s\"%s\"%s\"%s\"%s",sql,m.name,",",m.password,");");
    printf("%s\n",sql);
    if(sqlite3_exec(sq,sql,NULL,NULL,&errmsg) != SQLITE_OK )
    {
        fprintf(stderr,"err_msg[%d] : %s line:%d\n",\
                sqlite3_errcode(sq),sqlite3_errmsg(sq),__LINE__);    
       if(send(newfd,&m,sizeof(m),0) < 0)
       {
           ERR_MSG("send");
           return -1;
       }
        return -1;
    }
    m.type = 'y';
     if(send(newfd,&m,sizeof(m),0) < 0)
     {
        ERR_MSG("send");
        return -1;
     }
     return 0;
}
//返回查询的单词结果
//存储查询的记录
int find(int newfd)
{
    bzero(m.chin,sizeof(m.chin));
    char *errmsg = NULL;
    char sql[128] = "select * from dict where word=";
    sprintf(sql,"%s\"%s\"%s",sql,m.word,";");
    printf("%s\n",sql);
    if(sqlite3_exec(sq, sql, select_callBack_f, &newfd, &errmsg) != SQLITE_OK)
    {
        fprintf(stderr, "line:%d sqlite3_exec:%s\n", __LINE__, errmsg);

         return -1;
    }
    if(strlen(m.chin) == 0)
    {
        sprintf(m.chin,"查无此单词");
        if(send(newfd,&m,sizeof(m),0) < 0)
        {
            ERR_MSG("send");
            return -1;
        }
    }
    return 0;
}

int select_callBack_f(void *arg, int column, char **column_text, char **column_name)
{
    char *errmsg = NULL;
    int newfd = *(int*)arg;
    bzero(m.chin,sizeof(m.chin));
    bzero(m.time,sizeof(m.time));//二者需要更新
    strcat(m.chin,column_text[1]);
    if(send(newfd,&m,sizeof(m),0) < 0)
    {
       ERR_MSG("send");
       return -1;
    }

    long int t1;
    struct tm *s = NULL;
    time(&t1);
    s = localtime(&t1);
    
    snprintf(m.time,sizeof(m.time),"%d-%02d-%02d %02d:%02d:%02d",s->tm_year+1900,s->tm_mon+1,s->tm_mday,\
            s->tm_hour,s->tm_min,s->tm_sec);
    printf("%s\n",m.time);
    
    char sql[128] = "insert into his values (";
    sprintf(sql,"%s\"%s\"%s\"%s\"%s\"%s\"%s\"%s\"%s",sql,m.name,",",m.word,","\
            ,m.chin,",",m.time,");");
    printf("%s\n",sql);

    if(sqlite3_exec(sq,sql,NULL,NULL,&errmsg) != SQLITE_OK )
    {
        fprintf(stderr,"err_msg[%d] : %s line:%d\n",\
                sqlite3_errcode(sq),sqlite3_errmsg(sq),__LINE__);    
        return -1;
    }
    return 0;
}
//从his表中按用户名查找信息
int history(int newfd)
{
    char *errmsg = NULL;
    char sql[128] = "select * from his where name=";
    sprintf(sql,"%s\"%s\"%s",sql,m.name,";");
    printf("%s\n",sql);
    if(sqlite3_exec(sq, sql, select_callBack_h, &newfd, &errmsg) != SQLITE_OK)
    {
        fprintf(stderr, "line:%d sqlite3_exec:%s\n", __LINE__, errmsg);
         return -1;
    }
}
int select_callBack_h(void *arg, int column, char **column_text, char **column_name)
{
    int newfd = *(int*)arg;
    bzero(m.word,sizeof(m.word));
    bzero(m.chin,sizeof(m.chin));
    bzero(m.time,sizeof(m.time));
    strcat(m.word,column_text[1]);
    strcat(m.chin,column_text[2]);
    strcat(m.time,column_text[3]);

    if(send(newfd,&m,sizeof(m),0) < 0)
    {
        ERR_MSG("send");
        return -1;
    }
    return 0;
}

int quit(int newfd)
{
    char *errmsg = NULL;
    char sql[128] = "delete from load where name=";
    sprintf(sql,"%s\"%s\"%s",sql,m.name,";");
    printf("%s\n",sql);
    if(sqlite3_exec(sq,sql,NULL,NULL,&errmsg) != SQLITE_OK )
    {
        fprintf(stderr,"err_msg[%d] : %s line:%d\n",\
                sqlite3_errcode(sq),sqlite3_errmsg(sq),__LINE__);    
        return -1;
    }
    return 0;
}

.h文件

#ifndef __FUNC_H__
#define __FUNC_H__

#define ERR_MSG(msg){\
    fprintf(stderr,"line:%d\n",__LINE__);\
    perror(msg);\
}while(0);

struct msg
{
    char type;//消息类型
    char name[30];//用户名
    char password[30];//密码
    char word[30];//查找的单词
    char chin[50];//翻译
    char time[30];//查询时间
}m;

typedef void (*sighandler_t)(int);

//打开存在的数据库或创建不存在的数据库
void init_sqlite3();
//载入单词表
int word_install();
//搭建tcp服务器
//并发多进程服务器
int mu_pro();
//信号处理函数
void handler(int sig);
//子进程交互客户端函数
int deal_cli_msg(int newfd);

//登录
int load(int newfd);
//查询存储函数
int select_callBack(void *arg, int column, char **column_text, char **column_name);
//单词查找回调函数
int select_callBack_f(void *arg, int column, char **column_text, char **column_name);
//历史查询回调函数
int select_callBack_h(void *arg, int column, char **column_text, char **column_name);
//注册
int insert(int newfd);
//查找单词
int find(int newfd);
//查询历史记录
int history(int newfd);
//退出登录
int quit(int newfd);
#endif

Makefile文件

TARGET:=serve

OBJS:=main_s.o dict_s.o

CC:=gcc

CFLAGS:= -o
CFLAGSs:= -c -o

$(TARGET):$(OBJS)
    $(CC) $^ $(CFLAGS) $@ -lsqlite3

%.o:%.c 
    $(CC) $< $(CFLAGSs) $@

.PHONY:free

free:
    rm *.o

未考虑到服务端信息结构体作为全局变量,不同客户端对应子进程的调用可能会互相影响;

解决方法一:每个子进程定义一个信息结构体变量,但是传参极为麻烦;

解决方法二:进程间同步互斥。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值