struct.h
#ifndef _STRUCT_H_//服务器端头文件
#define _STRUCT_H_
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <sqlite3.h>
#define PORT 9999
char myName[20];
sqlite3 * database;
struct Msg
{
int cmd; // 消息类型
char fromname[20];
char password[10];
char tag[50];
char toname[20];
char msg[1024]; // 消息内容
};
struct online
{
int sfd;
int on_flag;
int speek_flag;
char name[20];
struct online *next;
};
struct online *header;
#endif
server.c
#include "struct.h"
struct online *header = NULL;
// 初始化套接字,返回监听套接字
int init_socket()
{
int listen_socket = socket(AF_INET, SOCK_STREAM, 0);
if (listen_socket == -1)
{
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)
{
perror ("bind");
return -1;
}
ret = listen(listen_socket, 5);
if (ret == -1)
{
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)
{
perror ("accept");
}
printf ("成功接收一个客户端: %s\n", inet_ntoa(client_addr.sin_addr));
return client_socket;
}
//注册
int reg(int client_socket, struct Msg *msg)
{
printf ("%s进行注册\n", msg->fromname);
char *errmsg = NULL;
char **resultp = NULL;
int nrow, ncolumn;
char buf[100];
sprintf(buf,"select * from user where name = '%s';",msg->fromname);
int ret = sqlite3_get_table(database, buf, &resultp, &nrow, &ncolumn, &errmsg);
if (ret != SQLITE_OK)
{
printf ("数据库操作失败:%s\n", errmsg);
return -1;
}
//用户名已存在
if( nrow != 0 )
{
printf("该用户名已存在!\n");
msg->cmd = 1001;
write (client_socket, msg, sizeof(struct Msg));
return 0;
}
else
{
printf("用户名不存在,可以注册!\n");
char tag[20] = "emmmmm.....";
strcpy( msg->tag, tag );
//向数据库中插入用户信息
sprintf (buf, "insert into user values('%s', '%s', '%s')", msg->fromname, msg->password, msg->tag);
ret = sqlite3_exec(database, buf, NULL, NULL, &errmsg);
if (ret != SQLITE_OK)
{
printf ("数据库操作失败:%s\n", errmsg);
msg->cmd = 1002;
write (client_socket, msg, sizeof(struct Msg));
return -1;
}
msg->cmd = 1003;
printf("注册成功!\n");
write (client_socket, msg, sizeof(struct Msg));
}
sqlite3_free_table(resultp);
}
//登录
int login(int client_socket, struct Msg *msg)
{
printf ("%s进行登录\n", msg->fromname);
char *errmsg = NULL;
char **resultp = NULL;
int nrow, ncolumn;
char buf[100];
sprintf(buf,"select * from user where name = '%s';",msg->fromname);
int ret = sqlite3_get_table(database, buf, &resultp, &nrow, &ncolumn, &errmsg);
if (ret != SQLITE_OK)
{
printf ("数据库操作失败:%s\n", errmsg);
return -1;
}
if ( nrow == 0 )
{
printf ("该用户名不存在!\n");
msg->cmd = 2001;
write (client_socket, msg, sizeof(struct Msg));
}
else
{
//密码正确
if ( strcmp ( msg->password, resultp[4] ) == 0 )
{
//检查用户是否在线
struct online *temp = header;
while (temp != NULL)
{
//用户已在线
if (strcmp (temp->name, msg->fromname) == 0)
{
if (temp->on_flag == 1)
{
msg->cmd = 2002;
printf ("用户已在线\n");
write (client_socket, msg, sizeof(struct Msg));
return 0;
}
}
temp = temp->next;
}
//用户不在线,保存用户信息
struct online *node = (struct online *)malloc(sizeof(struct online));
node->sfd = client_socket;
node->on_flag = 1;
node->speek_flag = 1;
strcpy (node->name, msg->fromname);
strcpy (msg->tag, resultp[5]);
//将用户信息头插在在线链表中
node->next = header;
header = node;
msg->cmd = 2003;
printf ("登录成功!\n");
write (client_socket, msg, sizeof(struct Msg));
return 0;
}
printf ("密码输入错误!\n");
msg->cmd = 2004;
write (client_socket, msg, sizeof(struct Msg));
}
sqlite3_free_table (resultp);
return 0;
}
// 私聊
void priva(int client_socket, struct Msg *msg)
{
printf ("%s要给%s发一条消息\n", msg->fromname, msg->toname);
//遍历在线用户链表
struct online *temp = header;
while (temp != NULL)
{
//找到要发送的对象
if (strcmp (temp->name, msg->toname) == 0)
{
msg->cmd = 3001;
write (temp->sfd, msg, sizeof(struct Msg));
printf ("找到要发送的对象,消息发送成功!\n");
msg->cmd = 3002;
write (client_socket, msg, sizeof(struct Msg));
return ;
}
temp = temp->next;
}
printf ("没有找到要发送的对象!\n");
msg->cmd = 3003;
write (client_socket, msg, sizeof(struct Msg));
}
// 群发
void group(int client_socket, struct Msg *msg)
{
printf ("%s发一次群消息\n", msg->fromname);
//遍历在线用户链表
struct online *temp = header;
while (temp != NULL)
{
msg->cmd = 4001;
write (temp->sfd, msg, sizeof(struct Msg));
temp = temp->next;
}
msg->cmd = 4002;
printf ("群发消息成功!\n");
write (client_socket, msg, sizeof(struct Msg));
}
//查看在线用户
void check(int client_socket, struct Msg *msg)
{
printf ("%s查看在线用户\n", msg->fromname);
char buf[300] = {0};
int len;
//遍历在线用户链表
struct online *temp = header;
while (temp != NULL)
{
strcat ( buf, temp->name );
len = sizeof(buf);
buf[len] = ' ';
temp = temp->next;
}
strcpy ( msg->msg, buf );
printf ("在线用户有:%s\n",buf);
msg->cmd = 5001;
printf ("查看在线用户成功!\n");
write (client_socket, msg, sizeof(struct Msg));
}
//修改密码
int changepwd(int client_socket, struct Msg *msg)
{
printf ("%s修改密码\n", msg->fromname);
char *errmsg = NULL;
char **resultp = NULL;
int nrow, ncolumn;
char buf[100];
sprintf(buf,"select * from user where name = '%s';",msg->fromname);
int ret = sqlite3_get_table(database, buf, &resultp, &nrow, &ncolumn, &errmsg);
if (ret != SQLITE_OK)
{
printf ("数据库操作失败:%s\n", errmsg);
return -1;
}
//密码正确
if ( strcmp ( msg->password, resultp[4] ) == 0 )
{
char buf[100];
sprintf (buf, "update user set password = '%s' where name = '%s'", msg->msg, msg->fromname);
ret = sqlite3_exec(database, buf, NULL, NULL, &errmsg);
if (ret != SQLITE_OK)
{
printf ("数据库操作失败:%s\n", errmsg);
msg->cmd = 6001;
write (client_socket, msg, sizeof(struct Msg));
return -1;
}
msg->cmd = 6002;
printf("修改密码成功!\n");
write (client_socket, msg, sizeof(struct Msg));
}
else
{
msg->cmd = 6003;
printf("密码错误!\n");
write (client_socket, msg, sizeof(struct Msg));
}
}
//修改个性签名
int changetag(int client_socket, struct Msg *msg)
{
printf ("%s修改个性签名\n", msg->fromname);
char *errmsg = NULL;
char **resultp = NULL;
int nrow, ncolumn;
char buf[100];
sprintf(buf,"select * from user where name = '%s';",msg->fromname);
int ret = sqlite3_get_table(database, buf, &resultp, &nrow, &ncolumn, &errmsg);
if (ret != SQLITE_OK)
{
printf ("数据库操作失败:%s\n", errmsg);
return -1;
}
sprintf (buf, "update user set tag = '%s' where name = '%s'", msg->tag, msg->fromname);
ret = sqlite3_exec(database, buf, NULL, NULL, &errmsg);
if (ret != SQLITE_OK)
{
printf ("数据库操作失败:%s\n", errmsg);
msg->cmd = 7001;
write (client_socket, msg, sizeof(struct Msg));
return -1;
}
msg->cmd = 7002;
printf ("修改个性签名成功!\n");
write (client_socket, msg, sizeof(struct Msg));
}
int clientexit(int client_socket, struct Msg *msg)
{
printf("%s要退出聊天室\n",msg->fromname);
struct online *temp = header;
struct online *prev = NULL;
while (temp != NULL)
{
//找到在线用户节点
//如果是第一个节点
if (strcmp (temp->name, msg->fromname) == 0)
{
header = header->next;
free(temp);
temp = NULL;
msg->cmd = 1301;
printf ("删除在线用户节点成功!\n");
write (client_socket, msg, sizeof(struct Msg));
return 0;
}
else
{
prev = temp;
temp = temp->next;
if (strcmp (temp->name, msg->fromname) == 0)
{
prev->next = temp->next;
free(temp);
temp = NULL;
msg->cmd = 1301;
printf ("删除在线用户节点成功!\n");
write (client_socket, msg, sizeof(struct Msg));
return 0;
}
}
}
msg->cmd = 1302;
printf ("没有找到该用户节点!\n");
write (client_socket, msg, sizeof(struct Msg));
}
// 把 负责处理客户端通信的函数改成线程的工作函数
void* hanld_client(void* v)
{
int client_socket = (int)v;
struct Msg msg;
while(1)
{
// 从客户端读一个结构体数据
int ret = read(client_socket, &msg, sizeof(msg));
if (ret == -1)
{
perror ("read");
break;
}
// 代表客户端退出
if (ret == 0)
{
printf ("客户端退出\n");
break;
}
switch (msg.cmd)
{
case 1 : // 注册
reg(client_socket, &msg);
break;
case 2 : // 登录
login(client_socket, &msg);
break;
case 3 : // 私聊
priva(client_socket, &msg);
break;
case 4 : // 群聊
group(client_socket, &msg);
break;
case 5 : // 查看在线用户
check(client_socket, &msg);
break;
case 6: // 修改密码
changepwd(client_socket, &msg);
break;
case 7: // 修改个性签名
changetag(client_socket, &msg);
break;
/* case 8: // 找到要发送文件的对象
finduser(client_socket, &msg);
break;
case 9: // 发送文件
sendfile(client_socket, &msg);
break;*/
case 13: // 客户端退出
clientexit(client_socket, &msg);
break;
}
}
close (client_socket);
}
int main()
{
int listen_socket = init_socket();
// 打开数据库
int ret = sqlite3_open("user.db", &database);
if (ret != SQLITE_OK)
{
printf ("打开数据库失败\n");
return -1;
}
printf ("打开数据库成功\n");
char *errmsg = NULL;
char *sql = "create table if not exists user ( name TEXT, password TEXT, tag TEXT, primary key(name) )";
ret = sqlite3_exec(database, sql, NULL, NULL, &errmsg);
if (ret != SQLITE_OK)
{
printf ("数据库操作失败:%s\n", errmsg);
return -1;
}
while (1)
{
int client_socket = MyAccept(listen_socket);
// 创建一个线程去处理客户端的请求,主线程依然负责监听
pthread_t id;
pthread_create(&id, NULL, hanld_client, (void *)client_socket);
pthread_detach(id); // 线程分离
}
close (listen_socket);
sqlite3_close(database);
return 0;
}