服务器端
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "LinkList.h"
#define PORT 9999
typedef struct _msg
{
int cmd;
int flag;
char username[20];
char password[20];
char msg[1024];
char frname[20];
char toname[20];
char time[50];
char filename[20];
}Msg;
sqlite3 *database;
Node *head;
//初始化套接字,返回监听套接字
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);
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;
int len = sizeof(client_addr);
int client_socket = accept(listen_socket, (struct sockaddr *)&client_addr, &len);
if(client_socket == -1)
{
perror("accept");
return -1;
}
printf("成功接收一个客户端:%s\n",inet_ntoa(client_addr.sin_addr));
return client_socket;
}
//注册
void reg(int client_socket, Msg *msg)
{
char *errmsg = NULL;
char **resultp = NULL;
int nrow, ncolumn;
char *sql = "select * from login";
int ret = sqlite3_get_table(database, sql, &resultp, &nrow, &ncolumn, &errmsg);
if (ret != SQLITE_OK)
{
printf ("数据库操作失败:%s\n", errmsg);
return;
}
printf("查找成功\n");
int i;
for(i = 0;i < (nrow+1) * ncolumn;i++)
{
if(strcmp(resultp[i],msg->username) == 0)
{
printf("用户已存在\n");
msg->cmd = -1;
write(client_socket,msg,sizeof(Msg));
return;
}
}
char buf[100];
sprintf (buf, "insert into login values('%s', '%s')", msg->username,msg->password);
ret = sqlite3_exec(database, buf, NULL, NULL, &errmsg);
if (ret != SQLITE_OK)
{
printf ("数据库操作失败:%s\n", errmsg);
return;
}
printf("%s用户注册成功\n",msg->username);
msg->cmd = 1001;
write(client_socket,msg,sizeof(Msg));
}
//用户登录
void login(int client_socket, Msg *msg)
{
char *errmsg = NULL;
char **resultp = NULL;
int nrow, ncolumn;
char *sql = "select * from login";
int ret = sqlite3_get_table(database, sql, &resultp, &nrow, &ncolumn, &errmsg);
if (ret != SQLITE_OK)
{
printf ("数据库操作失败:%s\n", errmsg);
return;
}
printf("查找成功\n");
int i;
for(i = 0;i < (nrow+1) * ncolumn;i++)
{
if(strcmp(resultp[i],msg->username) == 0 && strcmp(resultp[i+1],msg->password) == 0)
{
printf("%s登录成功\n",msg->username);
User user;
strcpy(user.username,msg->username);
user.client_socket = client_socket;
Insert_Last(head,user);
Display(head);
msg->cmd = 1002;
write(client_socket,msg,sizeof(Msg));
return;
}
}
msg->cmd = -2;
printf("用户名或密码错误,%s登录失败\n",msg->username);
write(client_socket,msg,sizeof(Msg));
}
//显示在线好友列表
void Display_Friend(int client_socket,Msg *msg)
{
Node* tmp = head->next;
while(tmp)
{
strcpy(msg->username,tmp->data.username);
write(client_socket,msg,sizeof(Msg));
tmp = tmp->next;
}
}
//群聊
void chat_all(int client_socket,Msg *msg)
{
Node* tmp = head->next;
Node* tmp1 = head->next;
while(tmp1)
{
if(tmp1->data.client_socket == client_socket)
{
strcpy(msg->frname,tmp1->data.username);
break;
}
tmp1 = tmp1->next;
}
strcpy(msg->toname,"all");
printf("%s发了一次群消息\n",msg->frname);
while(tmp)
{
write(tmp->data.client_socket,msg,sizeof(Msg));
tmp = tmp->next;
}
}
//私聊
void chat_along(int client_socket,Msg *msg)
{
Node* tmp1 = head->next;
Node* tmp2 = head->next;
while(tmp1)
{
if(tmp1->data.client_socket == client_socket)
{
strcpy(msg->frname,tmp1->data.username);
break;
}
tmp1 = tmp1->next;
}
printf("%s发给%s一条消息\n",msg->frname,msg->toname);
while(tmp2)
{
if(strcmp(tmp2->data.username,msg->toname) == 0)
{
msg->flag = 101;
write(tmp2->data.client_socket,msg,sizeof(Msg));
return;
}
tmp2 = tmp2->next;
}
if(tmp2 == NULL)
{
msg->flag = -101;
write(client_socket,msg,sizeof(Msg));
printf("您要发送的好友不存在\n");
return;
}
}
//注销
void logout(int client_socket,Msg *msg)
{
Node *tmp = head;
while(tmp->next)
{
if(tmp->next->data.client_socket == client_socket)
{
strcpy(msg->frname,tmp->next->data.username);
Node *p = tmp->next;
tmp->next = p->next;
free(p);
break;
}
}
char buf[100];
char *errmsg = NULL;
sprintf (buf, "delete from login where username = '%s'",msg->frname);
int ret = sqlite3_exec(database, buf, NULL, NULL, &errmsg);
if (ret != SQLITE_OK)
{
printf ("数据库操作失败:%s\n", errmsg);
return;
}
write(client_socket,msg,sizeof(Msg));
}
//文件传输
void file_transfer(int client_socket,Msg *msg)
{
Node *tmp1 = head->next;
Node *tmp2 = head->next;
while(tmp1)
{
if(tmp1->data.client_socket == client_socket)
{
strcpy(msg->frname,tmp1->data.username);
break;
}
tmp1 = tmp1->next;
}
while(tmp2)
{
if(strcmp(tmp2->data.username,msg->toname) == 0)
{
if(strcmp(msg->msg,"over") != 0)
{
msg->flag = 101;
usleep(15);
write(tmp2->data.client_socket,msg,sizeof(Msg));
return;
}
else
{
msg->flag = 102;
printf("%s给%s发了一个文件\n",msg->frname,msg->toname);
write(tmp2->data.client_socket,msg,sizeof(Msg));
return;
}
}
tmp2 = tmp2->next;
}
if(tmp2 == NULL)
{
msg->flag = -101;
write(client_socket,msg,sizeof(Msg));
printf("您要发送的好友不存在\n");
return;
}
}
//退出
void user_quit(int client_socket,Msg *msg)
{
Node *tmp = head;
while(tmp->next)
{
if(tmp->next->data.client_socket == client_socket)
{
strcpy(msg->frname,tmp->next->data.username);
Node *p = tmp->next;
tmp->next = p->next;
free(p);
break;
}
}
printf("%s退出登录\n",msg->frname);
write(client_socket,msg,sizeof(Msg));
}
//处理客户端通信的线程工作函数
void *handle_client(void* v)
{
int client_socket = (int)v;
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://在线好友显示
Display_Friend(client_socket,&msg);
break;
case 4://群聊
chat_all(client_socket,&msg);
break;
case 5://私聊
chat_along(client_socket,&msg);
break;
case 6://注销
logout(client_socket,&msg);
break;
case 7://退出
user_quit(client_socket,&msg);
break;
case 8://文件传输
file_transfer(client_socket,&msg);
break;
}
}
close(client_socket);
}
int main()
{
//打开数据库
int ret = sqlite3_open("chatroom.db", &database);
if (ret != SQLITE_OK)
{
printf ("打开数据库失败\n");
return -1;
}
printf("数据库打开成功\n");
//创建用户登录表
char *errmsg = NULL;
char *sql = "create table if not exists login(username TEXT,password TEXT)";
ret = sqlite3_exec(database, sql, NULL, NULL, &errmsg);
if (ret != SQLITE_OK)
{
printf ("数据库操作失败:%s\n", errmsg);
return -1;
}
printf("用户登录表创建成功\n");
//创建好友链表
head = Create_List();
if(head == NULL)
{
printf("链表创建失败\n");
return -1;
}
printf("链表创建成功\n");
//初始化套接字
int listen_socket = Init_Socket();
while(1)
{
//获取与客户端连接的套接字
int client_socket = MyAccept(listen_socket);
pthread_t pthread_id;
int ret = pthread_create(&pthread_id, NULL, handle_client,(void*)client_socket);
if(ret != 0)
{
perror("pthread_create");
return -1;
}
pthread_detach(pthread_id);
}
Clean_List(head);
Destroy(head);
close(listen_socket);
sqlite3_close(database);
return 0;
}
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "LinkList.h"
typedef struct _msg
{
int cmd;
int flag;
char username[20];
char password[20];
char msg[1024];
char frname[20];
char toname[20];
char time[50];
char filename[20];
}Msg;
sqlite3 *database;
//与服务器连接,返回与服务器通信的套接字
int MyConnect(char *argv[])
{
int socketfd = socket(AF_INET, SOCK_STREAM, 0);
if(socketfd == -1)
{
perror("socket");
return -1;
}
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(atoi(argv[2]));
inet_aton(argv[1],&(addr.sin_addr));
int ret = connect(socketfd, (struct sockaddr *)&addr, sizeof(addr));
if (ret == -1)
{
perror ("connect");
return -1;
}
printf ("成功连上服务器\n");
return socketfd;
}
void Ask_UserServer(int socketfd);
//登录界面
void interface()
{
time_t Time = time(NULL);
char *buf = ctime(&Time);
system("clear");
printf("%s",buf);
printf("|****************************|\n");
printf("| 欢迎使用 |\n");
printf("|****************************|\n");
printf("| 1、用户注册 |\n");
printf("| 2、用户登录 |\n");
printf("| 3、退出 |\n");
printf("|****************************|\n");
printf("请输入您要进行的操作:\n");
}
//用户界面
void userface()
{
time_t Time = time(NULL);
char *buf = ctime(&Time);
system("clear");
printf("%s",buf);
printf("|****************************|\n");
printf("| 主菜单 |\n");
printf("|****************************|\n");
printf("| 1、显示在线好友 |\n");
printf("| 2、群聊 |\n");
printf("| 3、私聊 |\n");
printf("| 4、查看聊天记录 |\n");
printf("| 5、用户注销 |\n");
printf("| 6、文件传输 |\n");
printf("| 7、退出 |\n");
printf("|****************************|\n");
printf("请输入您要进行的操作:\n");
}
//在线好友显示
void Display_Friend(int socketfd)
{
Msg msg;
msg.cmd = 3;
write (socketfd, &msg, sizeof(msg));
}
//群聊
void chat_all(int socketfd)
{
Msg msg;
msg.cmd = 4;
printf ("请输入要发送的内容: \n");
fgets(msg.msg, 1024, stdin);
write (socketfd, &msg, sizeof(msg));
}
//私聊
void chat_along(int socketfd)
{
Msg msg;
msg.cmd = 5;
printf("请输入您要发送的对象:\n");
scanf("%s",msg.toname);
while(getchar() != '\n');
printf ("请输入要发送的内容: \n");
fgets(msg.msg, 1024, stdin);
write (socketfd, &msg, sizeof(msg));
}
//将数据插入本地数据库
void insert_records(sqlite3 *database,Msg msg)
{
char buf[100];
char *errmsg = NULL;
sprintf (buf, "insert into records values('%s', '%s', '%s','%s')",msg.time,msg.frname,msg.toname,msg.msg);
int ret = sqlite3_exec(database, buf, NULL, NULL, &errmsg);
if (ret != SQLITE_OK)
{
printf ("数据库操作失败:%s\n", errmsg);
return;
}
}
//查看聊天记录
void get_records(sqlite3 *database)
{
char *errmsg = NULL;
char **resultp = NULL;
int nrow, ncolumn;
char *sql = "select * from records";
int ret = sqlite3_get_table(database, sql, &resultp, &nrow, &ncolumn, &errmsg);
if (ret != SQLITE_OK)
{
printf ("数据库操作失败:%s\n", errmsg);
return;
}
int i;
for (i = 0; i < (nrow+1)*ncolumn; i++)
{
if (i % ncolumn == 0)
printf ("\n");
printf ("%-26s", resultp[i]);
}
printf ("\n");
}
//用户注销
void logout(int socketfd)
{
Msg msg;
msg.cmd = 6;
write (socketfd, &msg, sizeof(msg));
}
//文件传输
void file_transfer(int socketfd)
{
Msg msg;
msg.cmd = 8;
printf("请输入您要发送的对象:\n");
scanf("%s",msg.toname);
while(getchar() != '\n');
printf("当前文件夹下的文件:\n");
system("ls");
printf ("请输入要发送的文件: \n");
fgets(msg.filename, 20, stdin);
char *tmp = msg.filename;
while(tmp)
{
if(*tmp == '\n')
{
*tmp = '\0';
break;
}
tmp++;
}
//printf("%s",msg.filename);
FILE *fp1 = fopen(msg.filename, "r");
if (fp1 == NULL)
{
perror ("fopen fp1");
return;
}
int ret;
while (ret = fread(msg.msg, sizeof(char), 1023, fp1))
{
msg.msg[1023] = '\0';
//sleep(2);
//printf("%s",msg.msg);
usleep(15);
write(socketfd, &msg, sizeof(msg));
memset(msg.msg,0,1024);
}
if(ret == 0 && !feof(fp1))
{
perror ("fread");
return;
}
strcpy(msg.msg,"over");
write(socketfd, &msg, sizeof(msg));
fclose(fp1);
}
void receive_file(Msg *msg)
{
FILE *fp2 = fopen("2.ppt", "a");
if (fp2 == NULL)
{
perror ("fopen fp2");
return;
}
fwrite(msg->msg,sizeof(char),1023,fp2);
fclose(fp2);
}
//退出登录
void user_quit(int socketfd)
{
Msg msg;
msg.cmd = 7;
write (socketfd, &msg, sizeof(msg));
}
//读写分离
void * readMsg(void *v)
{
int socketfd = (int)v;
Msg msg;
while (1)
{
read (socketfd, &msg, sizeof(msg));
time_t Time = time(NULL);
char *buf = ctime(&Time);
*(buf+24) = '\0';
strcpy(msg.time,buf);
switch(msg.cmd)
{
case 3:
printf("在线好友:%s\n",msg.username);
break;
case 4:
printf("%s %s发了一条群消息: %s\n",msg.time,msg.frname,msg.msg);
insert_records(database,msg);
break;
case 5:
if(msg.flag == 101)
{
printf("%s %s给您发了一条消息:%s",msg.time,msg.frname,msg.msg);
insert_records(database,msg);
}
else if(msg.flag == -101)
printf("您要发送的好友不存在\n");
break;
case 6:
printf("注销成功\n");
printf("按回车键返回......\n");
return;
case 7:
printf("退出成功\n");
printf("按回车键返回......\n");
return;
case 8:
if(msg.flag == 101)
{
receive_file(&msg);
}
else if(msg.flag == 102)
{
printf("%s 给您发送了一个文件\n",msg.frname);
}
else if(msg.flag == -101)
printf("您要发送的好友不存在\n");
break;
}
}
}
//注册
void reg(int socketfd)
{
Msg msg;
char username[20];
char password[20];
msg.cmd = 1;
printf("请输入用户名:");
//getchar();
//fgets(username,20,stdin);
scanf("%s",username);
strcpy(msg.username,username);
printf("请输入密码:");
//getchar();
//fgets(password,20,stdin);
scanf("%s",password);
strcpy(msg.password,password);
write(socketfd,&msg,sizeof(Msg));
read(socketfd,&msg,sizeof(Msg));
if(msg.cmd == -1)
{
printf("用户已存在,注册失败\n");
return;
}
else if(msg.cmd == 1001)
printf("注册成功\n");
}
//登录
void login(int socketfd)
{
Msg msg;
char username[20];
char password[20];
msg.cmd = 2;
printf("请输入用户名:");
scanf("%s",username);
strcpy(msg.username,username);
printf("请输入密码:");
scanf("%s",password);
strcpy(msg.password,password);
write(socketfd,&msg,sizeof(Msg));
read(socketfd,&msg,sizeof(Msg));
if(msg.cmd == -2)
{
printf("用户名或密码错误,登陆失败\n");
return;
}
else if(msg.cmd == 1002)
printf("登录成功\n");
pthread_t id;
pthread_create(&id, NULL, readMsg, (void *)socketfd);
pthread_detach(id);
sleep(2);
Ask_UserServer(socketfd);
}
//注册、登录服务
void Ask_Server(int socketfd)
{
int choice;
while(1)
{
interface();
scanf("%d",&choice);
switch(choice)
{
case 1:
reg(socketfd);
getchar();
sleep(2);
break;
case 2:
login(socketfd);
getchar();
sleep(2);
break;
case 3:
return;
default:
break;
}
}
}
//用户服务
void Ask_UserServer(int socketfd)
{
int choice;
while(1)
{
userface();
scanf("%d",&choice);
while(getchar()!= '\n');
switch(choice)
{
case 1:
Display_Friend(socketfd);
getchar();
break;
case 2:
chat_all(socketfd);
getchar();
break;
case 3:
chat_along(socketfd);
getchar();
break;
case 4:
get_records(database);
getchar();
break;
case 5:
logout(socketfd);
return;
case 6:
file_transfer(socketfd);
break;
case 7:
user_quit(socketfd);
return;
}
}
}
int main(int argc, char *argv[])
{
//打开数据库
int ret = sqlite3_open("chatroom.db", &database);
if (ret != SQLITE_OK)
{
printf ("打开数据库失败\n");
return -1;
}
//创建本地聊天记录表
char *errmsg = NULL;
char *sql = "create table if not exists records(time TEXT,frname TEXT,toname TEXT,msg TEXT)";
ret = sqlite3_exec(database, sql, NULL, NULL, &errmsg);
if (ret != SQLITE_OK)
{
printf ("数据库操作失败:%s\n", errmsg);
return -1;
}
int socketfd = MyConnect(argv);
Ask_Server(socketfd);
close(socketfd);
sqlite3_close(database);
return 0;
}