linux c多线程技术开发并发词典查询server与client
server与client功能说明
使用多线程并发技术实现服务端程序,解析所有客户端请求与回复,客户端功能有登录,注册,查单词,历史查询记录查询(功能可扩展,词库采用(key vaule形式).txt格式村存储)
忠告
这不是优秀的代码手编写,各路高手请勿多多关照,代码有好有坏的地方,有什么问题还望各路高手指出,技术无限,分享精神有限 ------纯原创,转载请说明出处(代码不止我这一版但是其他的很多都需要积分下载)
下面开始代码正文
dict_server.c
.
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<errno.h>
#include<string.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<pthread.h>
#include<time.h>
typedef struct cliinfo{
int cli_fd;//客户端连接后操作符
struct sockaddr_in cliaddr;//保存连接客户端信息
} CLIINFO;
void* connect_client(void* arg)
{
CLIINFO *info = (CLIINFO *)arg;
char ip[16];
memset(ip,0,16);
printf("client : ip = %s port = %d\n",inet_ntop(AF_INET,&(info->cliaddr.sin_addr.s_addr),ip,16),ntohs(info->cliaddr.sin_port));//打印连接客户端信息
char buf[1024];
char fdbuf[1024];
int flag = 0;
int ret = -1;
while(1)
{
start:
flag = 0;
ret = -1;
memset(buf,0,sizeof(buf));
ret = read(info->cli_fd,buf,sizeof(buf));
if(ret < 0)
{
perror("read");
break;
}
else if(ret == 0)//客户端退出检测
{
printf("ip : %s client close\n",inet_ntop(AF_INET,&(info->cliaddr.sin_addr.s_addr),ip,16));
break;
}
//登录认证(打开用户信息文件读取进行查询)
//int fd = open("/home/unix-hjl/userinfo.txt",O_RDONLY);
FILE *file = NULL;
file = fopen("/home/unix-hjl/userinfo.txt", "r+");
if(file == NULL)
{
break;
}
else
{
while(!feof(file))
{
memset(fdbuf,0,sizeof(fdbuf));
fgets(fdbuf,sizeof(fdbuf),file);
if(strncmp(fdbuf,buf,strlen(buf)) == 0)
{
write(info->cli_fd,"yes",3);//回写登录成功标志
fclose(file);//关闭文件描述符
printf("login \n");
flag = 1;//登录成功标志置 1
break;
}
}
if(flag != 1)
{
if(strncmp(buf,"3",1) == 0)
{
//执行注册
memset(buf,0,sizeof(buf));
read(info->cli_fd,buf,sizeof(buf));
fwrite(buf,1,strlen(buf),file);
char h_str[64];
char name[16];
memset(h_str,0,sizeof(h_str));
memset(name,0,sizeof(name));
int x = 0;
for(x; buf[x] != ' '; ++x)
{
name[x] = buf[x];
}
sprintf(h_str,"%s%s",name,"_historyfind.txt");
FILE *f = fopen(h_str,"w+");//创建历史记录文件
if(f == NULL)
{
printf("创建文件失败!!!\n");
}
write(info->cli_fd,"1",1);
fclose(f);
fclose(file);
goto start;
}
else
{
write(info->cli_fd,"no",3);//回写登录失败标志
}
}
if(flag)
{
char path_str[64];
char name_str[16];
memset(path_str,0,sizeof(path_str));
memset(name_str,0,sizeof(name_str));
int x = 0;
for(x; buf[x] != ' '; ++x)
{
name_str[x] = buf[x];
}
sprintf(path_str,"%s%s%s","/home/unix-hjl/",name_str,"_historyfind.txt");
FILE *user_fd = fopen(path_str,"r");
if(file == NULL)
{
perror("open");
break;
}
while(!feof(file))
{
memset(fdbuf,0,sizeof(fdbuf));
fgets(fdbuf,sizeof(fdbuf),user_fd);
write(info->cli_fd,fdbuf,strlen(fdbuf));//回写历史记录
}
usleep(5000);
write(info->cli_fd,"endl",4);//回写结束
fclose(user_fd);
while(1)
{
//进入查询
memset(buf,0,sizeof(buf));
ret = read(info->cli_fd,buf,sizeof(buf));
if(ret == 0)//客户端退出检测
{
printf("client ip : %s close\n",inet_ntop(AF_INET,&(info->cliaddr.sin_addr.s_addr),ip,16));
pthread_exit(NULL);
}
if(strncmp(buf,"quitlogin",9) == 0)
{
printf("quit login\n");//退出查询
break;
}
file = fopen("/home/unix-hjl/dict.txt","r");
if(file == NULL)
{
perror("open");
break;
}
char cmp_str[32];
while(!feof(file))
{
memset(cmp_str,0,sizeof(cmp_str));
memset(fdbuf,0,sizeof(fdbuf));
fgets(fdbuf,sizeof(fdbuf),file);
int i = 0;
for(i; (fdbuf[i] != ' ') && (strlen(fdbuf)) ; ++i)
{
cmp_str[i] = fdbuf[i];
}
int len = strlen(buf) - 1;
if((strncmp(cmp_str,buf,i) == 0) && ( i == len))
{
write(info->cli_fd,fdbuf,strlen(fdbuf));//回写查询记录
FILE *fd = fopen(path_str,"a+");
fwrite(fdbuf,1,strlen(fdbuf),fd);//向文件写入查询记录
usleep(1000);//延时,避免粘包导致异常
write(info->cli_fd,"endl",4);//回写结束
fclose(fd);
flag = 0;
break;
}
}
if(flag != 0)
{
write(info->cli_fd,"2",1);//未查询到
}
usleep(100);
flag = 1;
fclose(file);//关闭文件描述符
}
}
}
}
close(info->cli_fd);
free(info);
}
int main(int argc,char *argv[])
{
if(argc < 3)
{
fprintf(stderr,"USER:%s IP PORT",argv[0]);
return -1;
}
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);
int ret = -1;
int sock_fd = -1;
//1、创建socket套接字 AF_INET SOCK_STREAM
sock_fd = socket(AF_INET,SOCK_STREAM,0);
if(sock_fd < 0)
{
perror("socket error");
exit(-1);
}
//2、绑定bind
struct sockaddr_in addr;
addr.sin_family = AF_INET;//设置地址族
addr.sin_port = htons(atoi(argv[2]));//设置端口
inet_pton(AF_INET,argv[1],&addr.sin_addr.s_addr);//设置IP
ret = bind(sock_fd,(struct sockaddr *)&addr,sizeof(addr));
if(ret < 0)
{
perror("socket error");
exit(-1);
}
//2、监听
ret = listen(sock_fd,128);
if(ret < 0)
{
perror("listen error");
exit(-1);
}
struct sockaddr_in cliaddr;
socklen_t len = sizeof(cliaddr);
CLIINFO *info;
while(1)
{
//3、提取
int cli_fd = accept(sock_fd,(struct sockaddr *)&cliaddr,&len);
if(cli_fd < 0)
{
perror("accept error");
exit(-1);
}
pthread_t pthid;
info = malloc(sizeof(CLIINFO));
info->cli_fd = cli_fd;
info->cliaddr = cliaddr;
pthread_create(&pthid,&attr,connect_client,info);
}
//6、关闭连接
close(sock_fd);
return 0;
}
dict_client.c
.
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<errno.h>
#include<string.h>
#include<sys/socket.h>
#include<arpa/inet.h>
/*
说明:
历史记录每次登录时直接显示
*/
//1、登录认证
int login(char *user_arg, int fd)
{
char buf[1024];
memset(buf,0,sizeof(buf));
write(fd,user_arg,strlen(user_arg));
int ret = read(fd,buf,sizeof(buf));
if(ret < 0)
{
perror("read");
return -1;//System Error
}
else if(strncmp(buf,"yes",3) == 0)
{
return 0;//登录成功
}
return 1;//登录失败
}
//2、登录历史查询记录回显
int display_history(int fd)
{
char buf[1024];
memset(buf,0,sizeof(buf));
while(1)
{
//printf("debug-1\n");//测试点
memset(buf,0,sizeof(buf));
int ret = read(fd,buf,sizeof(buf));
if(ret < 0)
{
perror("read");
return -1;//System Error
}
else if((ret > 0) && (strncmp(buf,"endl",4) != 0))
{
write(STDOUT_FILENO,buf,strlen(buf));//显示历史查询记录
}
else
{
printf("\n");
break;//收到结束标志,结束读取
}
}
return 0;
}
//3、查询单词
int fandByDict(char *word,int fd)
{
char buf[1024];
write(fd,word,strlen(word));
while(1)
{
memset(buf,0,sizeof(buf));
int ret = read(fd,buf,sizeof(buf));
if(ret < 0)
{
perror("read");
return -1;//System Error
}
else if((ret > 0) && ((strncmp(buf,"endl",4) != 0)))
{
if(strcmp(buf,"2") == 0)
{
printf("%s",buf);
return 2;//未查到单词
}
write(STDOUT_FILENO,buf,strlen(buf));
}
else
{
break;//收到结束标志,结束读取
}
}
return 0;
}
//4、注册账户
int register_account(char *info,int fd)
{
write(fd,"3",1);
char buf[1024];
memset(buf,0,sizeof(buf));
write(fd,info,strlen(info));
usleep(100);
memset(buf,0,sizeof(buf));
read(fd,buf,sizeof(buf));
if(strncmp(buf,"1",1) == 0)
{
return 0;//注册成功
}
return 1;//注册失败
}
//tcp客户端
int main(int argc, char *argv[])
{
if(argc < 3)
{
fprintf(stderr,"USER:%s IP PORT",argv[0]);
return -1;
}
int sock_fd = -1;
int ret = -1;
//1、创建socket套接字 AF_INET SOCK_STREAM
sock_fd = socket(AF_INET,SOCK_STREAM,0);
if(sock_fd < 0)
{
perror("socket error");
exit(1);
}
//2、建立连接 connect
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(atoi(argv[2]));
inet_pton(AF_INET,argv[1],&addr.sin_addr.s_addr);
ret = connect(sock_fd,(struct sockaddr *)&addr,sizeof(addr));
if(ret < 0)
{
perror("connect error");
exit(1);
}
char buf[1024];
while(1)
{
int n = 3;
int count = 0;//登录n次失败将推出客户端
memset(buf,0,sizeof(buf));
printf("1、退出客户端请输入:quitfind\n2、登录请输入:login\n3、注册请输入:register请输入选择:\n");
fgets(buf,sizeof(buf),stdin);
if(strncmp(buf,"quitfind",8) == 0)
{
break;//退出查询
}
if(strncmp(buf,"register",8) == 0)//注册账号
{
printf("请输入账号和密码(格式 name pwd):\n");
fgets(buf,sizeof(buf),stdin);
ret = register_account(buf,sock_fd);
if(ret == 0)
{
printf("注册账号成功!!!\n");
memset(buf,0,sizeof(buf));
}
}
if(strncmp(buf,"login",5) == 0)
{
login:
printf("请输入账号密码(格式为name pwd):\n");
memset(buf,0,sizeof(buf));
fgets(buf,sizeof(buf),stdin);
if(login(buf,sock_fd) == 0)
{
printf("登录成功!!!\n");//登录成功
printf("历史查询记录:\n");
display_history(sock_fd);//显示历史记录
while(1)
{
//printf("debug\n");
memset(buf,0,sizeof(buf));
printf("请输入需要查询的单词(输入 quitlogin 退出登录):\n");
fgets(buf,sizeof(buf),stdin);
if(strncmp(buf,"quitlogin",9) == 0)
{
write(sock_fd,"quitlogin",9);
usleep(100);
break;//退出查询
}
ret = fandByDict(buf,sock_fd);
if(ret == 2)
{
printf("未搜索到单词:%s\n",buf);
}
}
}
else
{
++count;
printf("第:%d 次登录失败,还可尝试 %d 次后将推出程序!!!\n",count,n-count);
if(count == n)
{
break;//登录失败,退出客户端
}
goto login;
}
}
printf("%s",buf);
}
//5、关闭连接
close(sock_fd);
return 0;
}
纯原创,转载请说明出处(分享给需要的盆友们)