聊天室(c/s架构)

项目要求:

(1)采用 Client/Server 架构 。 

(2) Client A 登陆聊天服务器前,需要注册自己的 ID 和密码。 

(3)注册成功后,ClientA 就可以通过自己的 ID 和密码登陆聊天服务器 。 

(4). 多个 Client X 可以同时登陆聊天服务器之后,与其他用户进行通讯聊天。 

(5).Client A 成功登陆后可以查看当前聊天室内其他在线用户 Client x。 

(6). Client A 可以选择发消息给某个特定的 Client X,即”悄悄话”功能。

(7). Client A 可以选择发消息全部的在线用户,即”群发消息”功能。 

(8). Client A 在退出时需要保存聊天记录。 

(9). Server 端维护一个所有登陆用户的聊天会的记录文件,以便备查。

1、服务器

#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <sqlite3.h>

#define PORT 9999

struct User   //用户信息结构体
{
	char name[20];        //储存用户名
	char password[20];    //储存密码
	char signature[50];   //储存个性签名
	int  socket;          //储存套接字
	int  cmd;      		  // 消息类型
	char msg[1024];       // 消息内容
	char toname[20];
	char fromname[20];
	char logout;
	char file_name[20];
	char file_msg[1024];
};

struct User user[5];

sqlite3 * database;

sqlite3 * server_sqlite()    //数据库函数
{
	sqlite3 * database;
	
	// 打开数据库
	int ret = sqlite3_open("usermes.db", &database);
	if (ret != SQLITE_OK)
	{
		printf ("错误代码\n");
		perror("sqlite3_open");
		return NULL;
	}
	
	char *errmsg = NULL;
	char *sql = "create table if not exists usermes(name TEXT, password TEXT, signature TEXT, primary key(name))";
	ret = sqlite3_exec(database, sql, NULL, NULL, &errmsg);
	if (ret != SQLITE_OK)
	{
		printf ("数据库操作失败:%s\n", errmsg);
		return NULL;
	}
	return database;
}

int init_socket()   //套接字初始化
{
	int listen_socket = socket (AF_INET, SOCK_STREAM, 0);
	if(listen_socket == -1)
	{
		printf("错误代码55\n");
		perror("socket");
		return -1;
	}

	struct sockaddr_in addr;
	memset(&addr, 0, sizeof(addr));
	addr.sin_family  = AF_INET;     // 设置地址族
	addr.sin_port    = htons(PORT); // 设置本地端口
	addr.sin_addr.s_addr = htonl(INADDR_ANY);   // 使用本地的任意IP地址
	
	int  ret = bind(listen_socket,  (struct sockaddr *)&addr, sizeof(addr));  //绑定套接字
	if (ret == -1)
	{
		printf("错误代码69\n");
		perror ("bind");
		return -1;
	}
	
	// 3、监听本地套接字
	ret = listen(listen_socket, 5);
	if (ret == -1)
	{
		printf("错误代码78\n");
		perror ("listen");
		return -1;
	}
	
	printf("等待客户连接。。。。\n");
	return listen_socket;
}

int MyAccept(int listen_socket)  //连接客户端
{
	struct sockaddr_in client_addr; // 用来保存客户端的ip和端口信息
	int len = sizeof(client_addr);
	int client_socket = accept(listen_socket, (struct sockaddr *)&client_addr,  &len);
	if (client_socket == -1)
	{
		printf("错误代码93\n");
		perror ("accept");
	}
	
	printf ("成功接收一个客户端: %s\n", inet_ntoa(client_addr.sin_addr));
	
	return client_socket;
}

void reg(int client_socket, struct User *buf)  //注册
{
	char str[1024];
	sqlite3 * database;
	int i;
	database = server_sqlite();   //打开数据库
	char *errmsg = NULL;
	sprintf (str, "insert into usermes values('%s', '%s', '666')", buf->name, buf->password);
	int ret = sqlite3_exec(database, str, NULL, NULL, &errmsg);
	if (ret != SQLITE_OK)
	{
		printf ("数据库操作失败:%s\n", errmsg);
		buf->cmd = -2;
		write(client_socket, buf, sizeof(struct User));
	}
	else
	{
		printf("注册成功\n");
		buf->cmd = 1000;
		write(client_socket, buf, sizeof(struct User));
	}
	sqlite3_close(database);     // 关闭数据库
}

void log_in(int client_socket, struct User *buf)  //登录
{
	sqlite3 * database = server_sqlite();
	char *errmsg = NULL;
	char **resultp = NULL;
	int nrow, ncolumn;
	char *sql = "select * from usermes";
	int ret = sqlite3_get_table(database, sql, &resultp, &nrow, &ncolumn, &errmsg);
	if (ret != SQLITE_OK)
	{
		printf ("数据库操作失败:%s\n", errmsg);
		return;
	}
	printf("正在匹配账户和密码....\n");
	int i;
	int k;
	for (i = 3; i < (nrow+1)*ncolumn; i++)
	{
		if(strncmp(resultp[i], buf->name, strlen(buf->name)) == 0)
		{
			if(strncmp(resultp[i+1], buf->password, strlen(buf->password)) == 0)
			{
				for(k = 0; k < 5; k++)
				{
					if(user[k].socket == 0)
					{
						strcpy (user[k].name , buf->name);
						user[k].so
  • 4
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值