基于linux环境tcp网络编程(在线英英词典)文档【3】

完整代码如下:

有真心想学习的,需要库的朋友,底下留言哦!

server.c:


#include <sys/types.h>
#include <sys/stat.h>
#include <sys/file.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <strings.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <signal.h>
#include <sqlite3.h>
#include <time.h>

#define N 64
#define M 512		
typedef struct		//消息结构体 
{
	int type;
	char name[N];
	char data[M];
}MSG;

int client(int connfd,sqlite3 *db);			//客户端命令选择函数
int login(int connfd, MSG *msg,sqlite3 *db);		//登录函数
int register_z(int connfd, MSG *msg,sqlite3 *db);	//注册函数
int search_word(int connfd, MSG *msg,sqlite3*db);	//查询单词函数
int history(int connfd, MSG *msg,sqlite3*db);		//查询历史记录函数
int history_date(char *date);

void handler(int signo)		//对僵尸进程收尸
{
	while(waitpid(-1,NULL,WNOHANG) > 0);
}

int main()
{
	int n;//
	sqlite3 *db;
	int connfd;//定义通信套接字
	signal(SIGCHLD, handler);
	/*1.创建套接字*/
	int sockfd;
	if((sockfd=socket(PF_INET, SOCK_STREAM, 0)) < 0)
	{
		perror("socket");
		return -1;
	}
	printf("socket success!\n");
	
	int on=1;
	if(0 > setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on)))//设置重复端口号使用
	{
		perror("setsockopt");
		return -1;
	}

	if(0 != sqlite3_open("my.db",&db))//打开当前目录下的数据库
	{
		fprintf(stderr,"sqlite3_open:%s\n",sqlite3_errmsg(db));
		return -1;
	}

	/*2.绑定本机地址和端口*/
	struct sockaddr_in myaddr;
	memset(&myaddr, 0, sizeof(myaddr));
	myaddr.sin_family     =AF_INET;
	myaddr.sin_port	      =htons(8888);
	myaddr.sin_addr.s_addr=inet_addr("127.0.0.1");//采用本机静态IP地址
	if(bind(sockfd, (struct sockaddr *)&myaddr,sizeof(myaddr))<0)
	{
		perror("bind");
		return -1;
	}
	printf("bind success!\n");

	/*3.监听套接字*/
	if(listen(sockfd, 8)<0)
	{
		perror("listen");
		return -1;
	}
	printf("listen success!\n");

	while(1)
	{

		/*4.接受tcp连接*/
		connfd=accept(sockfd, NULL, NULL);
		if(connfd < 0)
		{
			perror("accept");
			return -1;
		}
		printf("accept success!\n");

		pid_t pid=fork();	   //采用并发服务器,利用产生子进程进行通信
		if(pid < 0)
		{
			perror("fork");
			exit(EXIT_FAILURE);
		}
		else if(pid == 0)	  //子进程进行通信
		{
			close(sockfd);	  //关闭监听套接字
			client(connfd,db);//选择页面
		}
		close(connfd);
	}
	if(0 != sqlite3_close(db))	  //关闭数据库
	{
		fprintf(stderr,"sqlite3_close:%s\n",sqlite3_errmsg(db));
		return -1;
	}

	/*6.关闭套接字*/
	close(sockfd);
	return 0;
}

int client(int connfd,sqlite3 *db)			 //页面选择函数
{
	
	MSG msg;    //定义一个新的消息结构体用来接受客户端发给服务器的所有消息
loop1:	while(0 < recv(connfd, &msg, sizeof(MSG),0))	//接受到客户端发的消息
	{
		//printf("msg->name:%s\n",msg.name);
		switch(msg.type)
		{
			case 1:
				if(1 == login(connfd,&msg,db))	//调用登录函数
				{
					client(connfd,db);	//如返回值为1,又返回到选择函数
				}
				break;
			case 2:
				register_z(connfd,&msg,db);	//注册用户函数
				break;
			case 3:
				search_word(connfd,&msg,db);	//查询单词函数
				break;
			case 4:
				history(connfd,&msg,db);	//查询历史记录函数
				break;
			case 5:
				goto loop1;//当客户端返回上一级时服务器也需要返回上一级
			default:
				printf("input error!\n");
		}
	}
	close(connfd);		//关闭通信套接字
	exit(EXIT_FAILURE);	//关闭子进程
	return 0;
}

int login(int connfd,MSG *msg,sqlite3 *db)//登录函数
{
	char buff[M];		//定义查询用户名及密码的缓存空间
	char **resultp;		//定义函数之行后返回的结果空间
	char *errmsg=NULL;	//定义函数执行后返回的错误信息
	int nrow,ncolumn;	//定义数据库中的表的行数及列数
	int ret;
	memset(buff,0,sizeof(buff));
	sprintf(buff,"select * from user where username = '%s' and password = '%s'",msg->name,msg->data);//将从客户端接受到的用户名及密码放入缓存中

	if(0 != sqlite3_get_table(db,buff,&resultp,&nrow,&ncolumn,&errmsg))//执行SQL指令
	{
		printf("%s\n",errmsg);
		return -1;
	}	
	else
	{
		printf("client login success!\n");
	}
	if(1 == nrow)		//根据指定的条件查找完成后成功找到数据,返回有>0的行数
	{
		strcpy(msg->name,"OK");
		if (0 > (ret = send(connfd,msg,sizeof(MSG),0)))		//将成功的数据发送给客户端
		{
			perror("send1");
		}
		return 1;
	}
	if(0 == nrow )		//查询没有结果
	{
		strcpy(msg->data,"    登录失败\n密码或者用户名错误!\n");
		if (0 > (ret = send(connfd,msg,sizeof(MSG),0)))		//将查询结果失败的数据返回给客户端
		{
			perror("send1");
			return -1;
		}
		printf("login fail!\n");
	}
	else
		printf("login success!\n");
	return 0;
}

int register_z(int connfd,MSG *msg,sqlite3 *db)//注册函数
{
	char *errmsg=NULL;
	char buff[M];
	char **resultp;
	int nrow,ncolumn;

	memset(buff,0,sizeof(buff));
	sprintf(buff,"select * from user where username='%s'",msg->name);	//将按照查找指定的用户名SQL命令缓存到buff中
	if(0 != sqlite3_get_table(db,buff,&resultp,&nrow,&ncolumn,&errmsg))	//将buff中的命令执行
	{
		printf("%s\n",errmsg);
		return -1;
	}

	if(nrow >= 1)		//查询的行数返回值>=1
	{
		strcpy(msg->data,"用户已存在!\n");
	}
	else			//没有相同用户名情况下再去注册新的用户
	{
		memset(buff,0,sizeof(buff));
		sprintf(buff,"insert into user values('%s','%s')",msg->name,msg->data);	//将要添加新的用户名和密码缓存在buff中
		if(0 != sqlite3_exec(db,buff,NULL,NULL,&errmsg))			//使用函数执行SQL命令
		{
			printf("%s\n",errmsg);
			return -1;
		}
		else
		{
			printf("client register success!\n");
			strcpy(msg->data,"注册成功!\n");
		}
	}


	if(0 > send(connfd,msg,sizeof(MSG),0))	//发送查询成功与否的数据
	{
		perror("send");
		return -1;
	}
	
	printf("register success!\n");
	return 0;
}

int search_word(int connfd, MSG *msg, sqlite3 *db)//查询单词函数
{
	int i,j;
	char *errmsg=NULL;
	char buff[M];	//定义查找的单词和解释缓存区
	char order[M];	//定义装入历史记录的缓存区
	char date[M];
	char **resultp;
	int nrow,ncolumn;
	memset(buff,0,sizeof(buff));	//对缓存区清空
	memset(date,0,sizeof(date));	//对时间缓冲区清空
	sprintf(buff,"select * from word where word='%s'",msg->name);		//将要查询的单词名字SQL命令放入缓存中
	if(0 != sqlite3_get_table(db,buff,&resultp,&nrow,&ncolumn,&errmsg))	//执行SQL命令
	{
		printf("error: %s\n",errmsg);
		return -1;
	}
	int count=2;
	for(i=0; i < nrow; i++)			//行
	{
		for(j=1; j < ncolumn; j++)	//列
		{
			history_date(date);
			strcpy(msg->name,resultp[count]);	//单词
			strcpy(msg->data,resultp[count+1]);	//单词解释
			count +=2;				//只有两列,每次的单词解释都需要跳过单词名那一列
			sprintf(order,"insert into history values('%s','%s')",date,msg->name);	//将单词名和解释放入历史记录的缓存中
			if(0 != sqlite3_exec(db,order,NULL,NULL,&errmsg))			//执行SQL命令
			{
				printf("error: %s\n",errmsg);
				return -1;
			}
			printf("%s  %s\n",date,msg->name);

		}
	}
	if(0 == nrow)
	{
		printf("没有这个单词!\n");
		strcpy(msg->data,"NO");		//给客户端发一个没有找到单词的信号
		if(0 > send(connfd,msg,sizeof(MSG),0))
		{
			perror("send");
			return -1;
		}
	}
	else
	{
		printf("word search success!\n");
		if(0 > send(connfd, msg, sizeof(MSG), 0))	//给客户端发送查询到的解释
		{
			perror("send");
			return -1;
		}
	}

	return 0;
}

 

评论 18
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值