转自:https://blog.csdn.net/xym_smart/article/details/78185944
服务器端
-
#include <stdio.h>
-
#include <string.h>
-
#include <sys/types.h>
-
#include <sys/socket.h>
-
#include <arpa/inet.h>
-
#include <pthread.h>
-
#include <sqlite3.h>
-
#include <time.h>
-
#include <sys/stat.h>
-
#include <fcntl.h>
-
#include <unistd.h>
-
#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 <stdio.h>
-
#include <string.h>
-
#include <sys/types.h>
-
#include <sys/socket.h>
-
#include <arpa/inet.h>
-
#include <time.h>
-
#include <sqlite3.h>
-
#include <string.h>
-
#include <sys/stat.h>
-
#include <fcntl.h>
-
#include <unistd.h>
-
#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;
- }