聊天室项目实战
项目要求:
- 采用client/server架构
- client A登录聊天服务器前,需要注册自己的ID和密码
- 注册成功后,client A就可以通过自己的ID和密码登录聊天服务器
- 多个 Client X 可以同时登陆聊天服务器之后,与其他用户进行通讯聊天
- Client A 成功登陆后可以查看当前聊天室内其他在线用户 Client x
- Client A 可以选择发消息给某个特定的 Client X,即” 悄悄话” 功能
- Client A 可以选择发消息全部的在线用户,即” 群发消息” 功能
- Client A 在退出时需要保存聊天记录
- Server 可以内建一个特殊权限的账号 admin,用于管理聊天室
- Admin 可以将某个 Client X “提出聊天室”
- Admin 可以将某个 Client X ” 设为只能旁听,不能发言”
- Client 端发言增加表情符号,可以设置某些自定义的特殊组合来表达感情.如输入:),则会自动发送” XXX 向大家做了个笑脸”
项目分析:
1.需要创建一个数据库用来保存用户的账号,密码,昵称,手机号码,禁言标志位,会员标志位等信息,手机号码用来忘记密码功能中找回密码使用,而昵称是为了聊天时寻找对象使用;
2.创建一个在线用户的链表,保存在线用户的信息。
3.创建一个结构体用来保存发送的信息,包括通信协议,昵称,端口号,聊天内容等等……
4.使用select来写代码时,服务器并不需要创建线程,服务器会对所有的文件描述符进行检测,发现有状况发生时,立即响应处理。
5.在进行聊天时,要将所有的信息保存在文件中,作为聊天记录,在收到与发送的位置对文件进行读写操作即可。
本项目实现了,客户端之间信息的连续的发送
chatroom.h
#ifndef _CHATROOM_H_
#define _CHATROOM_H_
/*************库函数****************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <time.h>
#include <unistd.h>
#include <sys/select.h>
#include <sys/time.h>
#include <sqlite3.h>
#include <signal.h>
/*************宏定义*******************/
#define PORT 8888
#define SUCCESS 10001
#define FAILURE 10002
#define REGISTER 1000
#define LOGIN 2000
#define QUIT 3000
#define EXIST 4000
#define NOTEXIST 5000
#define ACCOUNTEXIT 6000
#define ACCOUNTNOTEXIT 7000
#define REGFAILURE 8000
#define REGSUCCESS 9000
#define ALLOWLOGIN 10000
#define REFUSELOGIN 11000
#define CHATREQUST 12000
#define ALLOWCHAT 13000
#define ACCEPTCHAT 13100
#define REFUSECHAT 14000
#define INSERT 15000
#define CHANGEPASS 16000
#define CHANGESUCCESS 17000
#define CHANGEFAILURE 18000
#define CONFIRMACCOUNT 19000
#define CHECKONLINE 20000
#define RETONLINE 21000
#define CHECKDONE 21100
#define PRECHATTING 22000
#define CHATTING 23000
#define CHECKHISTORY 24000
#define ALLOWCHECK 24001
#define CHECKHISDONE 25000
#define SENDGROUP 26000
#define RECVGROUP 27000
#define ACCEPTGROUNP 27001
#define EMOJONLINECHICK 28000
#define EMOJNOTONLINE 29000
#define EMOJONLINE 30000
#define SENDEMOJ 31000
#define PRERECVEMOJ 32000
#define RECVEMOJ 33000
#define OFFLINE 34000
#define FORRBIDDEN 35000
#define FUCKOUT 36000
#define DISMISS 37000
#define MEMBER 38000
#define NOTMEMBER 39000
#define NOTDISMISS 40000
#define NOTFUCK 41000
#define NOTONLINE 42000
#define FILESENDREQUST 43000
#define REFUSESEND 44000
#define ACCEPTSEND 45000
#define FILESEND 46000
#define RECVFILE 46001
#define SENDDONE 47000
#define SIGNAL 48000
#define PEOPLECHAT 49000
/*************结构体声明****************/
struct usernode
{
char name[10];
char TarName[10];
char password[20];
char account[10];
char telephone[20];
char onlinefriend[20][20];
char ChatBuf[20];
char Forbname[10];
char FileBuf[100];
char FilePath[40];
int cmd;
int OnlineFlag;
int Tofd;
int TargFd;
int num;
};
typedef struct usernode Node;
struct onlineInfo
{
char name[10];
char account[10];
int Flag;
int SelfFd;
int ForbFlag;
struct onlineInfo *next;
};
typedef struct onlineInfo OnlineInfo;
typedef OnlineInfo *Online;
struct info
{
char buf[30];
int Tofd;
};
struct chathistory
{
char name[10];
char cont[10];
int year;
int month;
int day;
int hour;
int min;
int sec;
};
typedef struct chathistory ChatHist;
/*************信息链表函数声明****************/
int OnlineInit(Online *Info);
int InsertLink(Online Info, int fd, int flag, char *name, char *account);
int OnlineJudge(Online l, char *Targname);
char *GetLinkName(Online l, int fd, char *n);
/*************界面函数声明****************/
void PrintTime();
void Loginshow(int sockfd);
void Registershow(int sockfd);
int loadshow(int sockfd);
void LogSuccshow(int sockfd);
int JudgeLog(char *Myacc, char *Mypass);
/*************数据库函数声明****************/
int InsertDb(char *n, char *a, char *p, int fd, char *t);
int Select(void *para, int columnCount, char **columnValue, char **columnName);
int JudgeInfo1(char *acc, char *pass, int tarfd);
int ConfirmInfo(void *para, int columnCount, char **columnValue, char **columnName);
int JudgeInfo2(char *acc, char *tele);
int ResetPass(int fd, char *acc);
int ChangePass(char *account, char *password);
char *GetName(char *acc, char *pass, char *n);
int Getname(void *para, int columnCount, char **columnValue, char **columnName);
int AddMember(char *acc);
int JudgeMember(char *acc);
int Judgemember(void *para, int columnCount, char **columnValue, char **columnName);
/*************聊天界面功能函数声明****************/
int PriChat(int sockfd);
int SendGroup(int sockfd);
int CheckOnline(int sockfd);
int SearChatHis(int sockfd);
void ForbidMod();
int PrintOnlineFriend(Online l, int fd);
int ChattingShow(int sockfd, int TargFd, char *name, char *Tarame);
int SendEmoj(int sockfd);
void Fuck(int sockfd);
void HiddenShow();
void Offline(int sockfd);
void Dismiss(int sockfd);
void member(int sockfd);
void FuckOffline();
int RecvChat(int sockfd);
void Transform(int sockfd);
void Exit(int sockfd);
/*************聊天记录函数声明****************/
int AddChatHist(char *Targname, char *chat);
void ShowChatHist();
/*************信号处理函数声明****************/
void hand(int tmp);
#endif
服务器部分:
服务器函数实现
#include "chatroom.h"
/*************数据库函数****************/
int InsertDb(char *a, char *n, char *p, int fd, char *t)
{
int ret;
char sql[200] = {0};
extern sqlite3 *ppdb;
char Tmp1[3] = "no";
sprintf(sql, "insert into chatroom (account, name, password, Tofd, telephone, member, forbid) values('%s', '%s', '%s', '%d', '%s', '%s', '%s');", a, n, p, fd, t, Tmp1, Tmp1);
ret = sqlite3_exec(ppdb, sql, NULL, NULL, NULL);
if(SQLITE_OK != ret)
{
perror("sqlite3_exec");
return FAILURE;
}
return SUCCESS;
}
char *GetName(char *acc, char *pass, char *n)
{
int ret;
extern sqlite3 *ppdb;
char sql[100] = {0};
extern char Tmpname[10];
memset(&Tmpname, 0, sizeof(Tmpname));
Node Tmp = {0};
strcpy(Tmp.account, acc);
strcpy(Tmp.password, pass);
sprintf(sql, "select *from chatroom;");
ret = sqlite3_exec(ppdb, sql, Getname, (void *)&Tmp, NULL);
if(SQLITE_OK != ret)
{
perror("sqlite3_exec");
exit(1);
}
strcpy(n, Tmpname);
return n;
}
int Getname(void *para, int columnCount, char **columnValue, char **columnName)
{
int ret;
char buf[10] = {0};
extern sqlite3 *ppdb;
Node Tmp = *((Node *)para);
extern char Tmpname[10];
if(!strcmp(columnValue[0], Tmp.account) && !strcmp(columnValue[2], Tmp.password))
{
strcpy(Tmpname, columnValue[1]);
}
return 0;
}
int AddMember(char *acc)
{
int ret;
char sql[200] = {0};
extern sqlite3 *ppdb;
char Tmp[4] = "yes";
sprintf(sql, "update chatroom set member = '%s' where account = '%s';", Tmp, acc);
ret = sqlite3_exec(ppdb, sql, NULL, NULL, NULL);
if(SQLITE_OK != ret)
{
perror("sqlite3_exec");
return FAILURE;
}
return SUCCESS;
}
int JudgeMember(char *acc)
{
int ret;
char sql[200] = {0};
extern sqlite3 *ppdb;
extern int MEMBERFLAG;
sprintf(sql, "select * from chatroom;");
ret = sqlite3_exec(ppdb, sql, Judgemember, (void *)acc, NULL);
if(SQLITE_OK != ret)
{
perror("sqlite3_exec");
return FAILURE;
}
if(MEMBERFLAG == 1)
{
MEMBERFLAG = 0;
return SUCCESS;
}
else
{
return FAILURE;
}
}
int Judgemember(void *para, int columnCount, char **columnValue, char **columnName)
{
extern int MEMBERFLAG;
if(!strcmp(columnValue[0], (char *)para) && !strcmp(columnValue[5], "yes"))
{
MEMBERFLAG = 1;
}
return 0;
}
int JudgeInfo1(char *acc, char *pass, int tarfd)
{
int ret;
char sql[200] = {0};
Node Tmp = {0};
extern sqlite3 *ppdb;
extern int FLAG;
char name[10];
FLAG = 0;
GetName(acc, pass, name);
Tmp.Tofd = tarfd; //客户端的fd
strcpy(Tmp.account, acc);
strcpy(Tmp.password, pass);
strcpy(Tmp.name, name);
sprintf(sql, "select * from chatroom;");
ret = sqlite3_exec(ppdb, sql, ConfirmInfo, (void *)&Tmp, NULL);
if(SQLITE_OK != ret)
{
perror("sqlite3_exec");
exit(1);
}
if(FLAG == 0)
{
Tmp.cmd = REFUSELOGIN;
ret = send(Tmp.Tofd, &Tmp, sizeof(Tmp), 0);
if(-1 == ret)
{
perror("ConfirmInfo send");
return FAILURE;
}
}
else if(FLAG == 1)
{
Tmp.cmd = ALLOWLOGIN;
ret = send(Tmp.Tofd, &Tmp, sizeof(Tmp), 0);
if(-1 == ret)
{
perror("ConfirmInfo send");
return FAILURE;
}
}
}
int ConfirmInfo(void *para, int columnCount, char **columnValue, char **columnName)
{
int ret;
char buf[10] = {0};
extern sqlite3 *ppdb;
extern int FLAG;
Node Tmp = *((Node *)para);
strcpy(buf, columnValue[0]);
if(!strcmp(columnValue[0], Tmp.account) && !strcmp(columnValue[2], Tmp.password))
{
FLAG = 1;
}
return 0;
}
int JudgeInfo2(char *acc, char *tele)
{
int ret;
char sql[200] = {0};
char *errmsg = NULL;
char **dbresult;
int row, column;
extern sqlite3 *ppdb;
printf("444444444\n");
memset(sql, 0, sizeof(sql));
sprintf(sql, "select account, telephone from chatroom where account = '%s' and telephone = '%s';", acc, tele);
ret = sqlite3_get_table(ppdb, sql, &dbresult, &row, &column, &errmsg);
if(SQLITE_OK == ret)
{
if(1 == row)
{
sqlite3_free_table(dbresult);
return SUCCESS;
}
}
sqlite3_free_table(dbresult);
return FAILURE;;
}
int ChangePass(char *account, char *password)
{
int ret;
char sql[200] = {0};
extern sqlite3 *ppdb;
sprintf(sql, "update chatroom set password = '%s' where account = '%s';", password, account);
ret = sqlite3_exec(ppdb, sql, NULL, NULL, NULL);
if(SQLITE_OK != ret)
{
perror("ChangePass sqlite3_exec");
return FAILURE;
}
return SUCCESS;
}
int JudgeLog(char *Myacc, char *Mypass)
{
int ret, i;
char sql[100] = {0};
extern sqlite3 *ppdb;
sprintf(sql, "select account from chatroom where password = '%s';", Mypass);
ret = sqlite3_exec(ppdb, sql, Select, Myacc, NULL);
if(SQLITE_OK != ret)
{
perror("sqlite3_execD");
exit(1);
}
}
int Select(void *para, int columnCount, char **columnValue, char **columnName)
{
int j;
for(j = 0; j < columnCount; j++)
{
if(!strcmp(para, columnValue[j]))
{
EXISTFLAG = EXIST;
return SUCCESS;
}
}
EXISTFLAG = NOTEXIST;
return FAILURE;
}
/*************信息链表初始化****************/
int OnlineInit(Online *Info)
{
(*Info) = (Online)malloc(sizeof(OnlineInfo));
if(NULL == (*Info))
{
return FAILURE;
}
(*Info)->next = NULL;
return SUCCESS;
}
int InsertLink(Online Info, int fd, int flag, char *name, char *account)
{
Online p = Info->next;
Online n = (Online)malloc(sizeof(OnlineInfo));
if(NULL == n)
{
return FAILURE;
}
while(p)
{
if(strcmp(p->account, account) == 0)
{
p->SelfFd = fd;
return SUCCESS;
}
else
{
p = p->next;
}
}
Online q = Info;
strcpy(n->name, name);
printf("%s\n", name);
printf("%s\n", n->name);
strcpy(n->account, account);
n->Flag = flag;
n->SelfFd = fd;
n->next = q->next;
q->next = n;
}
int OnlineJudge(Online l, char *Targname)
{
Online p = l->next;
while(p)
{
if(!(strcmp(p->name, Targname)) && p->Flag == 1)
{
return p->SelfFd; //聊天对象的fd
}
else
{
p = p->next;
}
if(NULL == p)
{
return REFUSECHAT;
}
}
}
int PrintOnlineFriend(Online l, int fd)
{
int i = 0, ret;
Online p = l->next;
Node Tmp = {0};
Tmp.cmd = RETONLINE;
Tmp.num = 0;
while(p)
{
if(p->Flag == 1)
{
strcpy(Tmp.onlinefriend[i], p->name);
i++;
Tmp.num = i;
}
p = p->next;
}
ret = send(fd, &Tmp, sizeof(Tmp), 0);
if(-1 == ret)
{
perror("PrintOnlineFriend send");
exit(1);
}
return SUCCESS;
}
char *GetLinkName(Online l, int fd, char *n)
{
Online p = l->next;
while(p)
{
if(p->SelfFd == fd)
{
strcpy(n, p->name);
return n;
}
else
{
p = p->next;
}
}
}
服务器部分
#include "chatroom1.h"
sqlite3 *ppdb;
Node Send = {0};
Node Recv = {0};
int FLAG = 0;
char Tmpname[10] = {0};
int TMPFD = 0;
char TMPCHATBUF[30] = {0};
int MEMBERFLAG = 0;
int PeopleChatFd[10] = {0};
int main()
{
int sockfd, fd[10] = {0}, i = 0, j, length, ret, opt = 1, MaxFd;
struct sockaddr_in server_addr;
struct sockaddr_in client_addr;
fd_set ReadFd, TmpFd;
char sql[200] = {0};
Node RecvBuf = {0};
Node Tmp = {0};
Online LinkNode;
ret = OnlineInit(&LinkNode);
if(FAILURE == ret)
{
printf("Init FAILURE\n");
return FAILURE;
}
ret = sqlite3_open("chatroom.db", &ppdb);
if(SQLITE_OK != ret)
{
perror("sqlite3_open");
exit(1);
}
sprintf(sql, "create table if not exists chatroom(account text primary key, name text, password text, Tofd integer, telephone text, member text, forbid text);");
ret = sqlite3_exec(ppdb, sql, NULL, NULL, NULL);
if(SQLITE_OK != ret)
{
perror("sqlite3_exec1A");
exit(1);
}
sockfd = socket(PF_INET, SOCK_STREAM, 0);
if(-1 == sockfd)
{
perror("socket");
exit(1);
}
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
bzero(&server_addr, sizeof(server_addr));
server_addr.sin_family = PF_INET;
server_addr.sin_port = htons(PORT);
server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
ret = bind(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr));
if(-1 == ret)
{
perror("bind");
exit(1);
}
ret = listen(sockfd, 100);
if(-1 == ret)
{
perror("listen");
exit(1);
}
printf("Listening...\n");
FD_ZERO(&ReadFd);
FD_ZERO(&TmpFd);
FD_SET(sockfd, &ReadFd);
MaxFd = sockfd + 1;
while(1)
{
TmpFd = ReadFd;
ret = select(MaxFd, &TmpFd, NULL, NULL, NULL);
if(-1 == ret)
{
perror("select");
exit(1);
}
if(FD_ISSET(sockfd, &TmpFd))
{
length = sizeof(client_addr);
fd[i] = accept(sockfd, (struct sockaddr *)&client_addr, &length);
if(-1 == fd[i])
{
perror("accept");
exit(1);
}
printf("Accept %d, Port %d\n", fd[i], client_addr.sin_port);
FD_SET(fd[i], &ReadFd);
MaxFd = fd[i] + 1;
i++;
}
else
{
for(j = 0; j < i; j++)
{
if(FD_ISSET(fd[j], &TmpFd))
{
memset(&RecvBuf, 0, sizeof(RecvBuf));
ret = recv(fd[j], &RecvBuf, sizeof(RecvBuf), 0);
if(-1 == ret)
{
perror("recv");
exit(1);
}
/************************************注册*************************************/
if(REGISTER == RecvBuf.cmd)
{
RecvBuf.Tofd = fd[j];
ret = InsertDb(RecvBuf.account, RecvBuf.name, RecvBuf.password, RecvBuf.Tofd, RecvBuf.telephone);
if(FAILURE == ret)
{
RecvBuf.cmd = REGFAILURE;
ret = send(RecvBuf.Tofd, &RecvBuf, sizeof(RecvBuf), 0);
if(-1 == ret)
{
perror("Regsend");
exit(1);
}
}
else if(SUCCESS == ret)
{
RecvBuf.cmd = REGSUCCESS;
ret = send(RecvBuf.Tofd, &RecvBuf, sizeof(RecvBuf), 0);
if(-1 == ret)
{
perror("Regsend");
exit(1);
}
}
RecvBuf.cmd = 0;
}
/************************************登录*************************************/
if(LOGIN == RecvBuf.cmd)
{
RecvBuf.Tofd = fd[j];
JudgeInfo1(RecvBuf.account, RecvBuf.password, RecvBuf.Tofd);
RecvBuf.cmd = 0;
}
if(INSERT == RecvBuf.cmd)
{
RecvBuf.OnlineFlag = 1;
RecvBuf.Tofd = fd[j];
//插入链表时,将自己的端口号一起插入,以便进行聊天
ret = InsertLink(LinkNode, RecvBuf.Tofd, RecvBuf.OnlineFlag, RecvBuf.name, RecvBuf.account);
if(FAILURE == ret)
{
printf("Insert Failure");
exit(1);
}
RecvBuf.cmd = 0;
}
/**********************************验证账号***********************************/
if(CONFIRMACCOUNT == RecvBuf.cmd)
{
printf("11111111\n");
RecvBuf.Tofd = fd[j];
ret = JudgeInfo2(RecvBuf.account, RecvBuf.telephone);
if(SUCCESS == ret)
{
RecvBuf.cmd = EXIST;
ret = send(RecvBuf.Tofd, &RecvBuf, sizeof(RecvBuf), 0);
if(-1 == ret)
{
perror("CONFIRMACCOUNT send");
exit(1);
}
}
else if(NOTEXIST == ret)
{
RecvBuf.cmd = NOTEXIST;
ret = send(RecvBuf.Tofd, &RecvBuf, sizeof(RecvBuf), 0);
if(-1 == ret)
{
perror("CONFIRMACCOUNT send");
exit(1);
}
}
RecvBuf.cmd = 0;
}
/**********************************修改密码***********************************/
if(CHANGEPASS == RecvBuf.cmd)
{
RecvBuf.Tofd = fd[j];
ret = ChangePass(RecvBuf.account, RecvBuf.password);
if(SUCCESS == ret)
{
RecvBuf.cmd = CHANGESUCCESS;
ret = send(RecvBuf.Tofd, &RecvBuf, sizeof(RecvBuf), 0);
if(-1 == ret)
{
perror("CHANGEPASS send");
exit(1);
}
}
RecvBuf.cmd = 0;
}
/************************************聊天*************************************/
if(CHATREQUST == RecvBuf.cmd)
{
RecvBuf.Tofd = fd[j]; //客户端的fd
Online l = LinkNode->next;
while(l) //判断是否被禁言
{
if(l->SelfFd == fd[j] && l->ForbFlag == 1)
{
RecvBuf.cmd = FORRBIDDEN;
ret = send(RecvBuf.Tofd, &RecvBuf, sizeof(RecvBuf), 0);
if(-1 == ret)
{
perror("Forbid send");
exit(1);
}
break;
}
else
{
l = l->next;
}
}
if(NULL == l)
{
ret = OnlineJudge(LinkNode, RecvBuf.TarName);
if(REFUSECHAT == ret)
{
RecvBuf.cmd = REFUSECHAT;
ret = send(RecvBuf.Tofd, &RecvBuf, sizeof(RecvBuf), 0);
printf("%d\n", RecvBuf.Tofd);
if(-1 == ret)
{
perror("Chat send");
return FAILURE;
}
}
else
{
RecvBuf.TargFd = ret; //聊天对象的fd
printf("%d\n", RecvBuf.TargFd);
Recv.Tofd = ret; //接收方的fd
Send.Tofd = RecvBuf.Tofd; //发送方的fd
GetLinkName(LinkNode, Recv.Tofd, Recv.name);
GetLinkName(LinkNode, Send.Tofd, Send.name);
GetLinkName(LinkNode, fd[j], RecvBuf.name);
RecvBuf.cmd = ALLOWCHAT;
ret = send(RecvBuf.Tofd, &RecvBuf, sizeof(RecvBuf), 0);
if(-1 == ret)
{
perror("Chat send");
return SUCCESS;
}
RecvBuf.cmd = ACCEPTCHAT;
ret = send(RecvBuf.TargFd, &RecvBuf, sizeof(RecvBuf), 0);
if(-1 == ret)
{
perror("Chat send");
return SUCCESS;
}
}
}
RecvBuf.cmd = 0;
}
/*
if(PRECHATTING == RecvBuf.cmd)
{
RecvBuf.Tofd = RecvBuf.TargFd; //接受信息对象的fd;
RecvBuf.TargFd = fd[j]; //发送信息对象的fd;
strcpy(Recv.name, RecvBuf.TarName);//此时,RecvBuf.name 是发送方的,RecvBuf.TarName是接收方
strcpy(Send.name, RecvBuf.name);
printf("Recv %s Send %s\n", Recv.name, Send.name);
ret = send(RecvBuf.Tofd, &RecvBuf, sizeof(RecvBuf), 0);
if(-1 == ret)
{
perror("PRECHATTING send");
exit(1);
}
} */
if(CHATTING == RecvBuf.cmd)
{
RecvBuf.Tofd = fd[j];
RecvBuf.cmd = CHATTING;
if(RecvBuf.Tofd != Send.Tofd)
{
strcpy(RecvBuf.name, Recv.name);
ret = send(Send.Tofd, &RecvBuf, sizeof(RecvBuf), 0);
if(-1 == ret)
{
perror("CHATTING send");
exit(1);
}
}
else
{
strcpy(RecvBuf.name, Send.name);
ret = send(Recv.Tofd, &RecvBuf, sizeof(RecvBuf), 0);
if(-1 == ret)
{
perror("CHATTING send");
exit(1);
}
}
}
/********************************查看在线好友*********************************/
if(CHECKONLINE == RecvBuf.cmd)
{
RecvBuf.Tofd = fd[j];
ret = PrintOnlineFriend(LinkNode, RecvBuf.Tofd);
if(FAILURE == ret)
{
perror("CHECKONLINE");
exit(1);
}
}
/********************************查看聊天记录*********************************/
if(CHECKHISTORY == RecvBuf.cmd)
{
RecvBuf.Tofd = fd[j];
RecvBuf.cmd = CHECKHISDONE;
ret = send(RecvBuf.Tofd, &RecvBuf, sizeof(RecvBuf), 0);
if(-1 == ret)
{
perror("CHECKHISTORY send");
exit(1);
}
}
/********************************群发*********************************/
if(SENDGROUP == RecvBuf.cmd)
{
RecvBuf.cmd = RECVGROUP;
Online l = LinkNode->next;
GetLinkName(LinkNode, fd[j], RecvBuf.name);
while(l)
{
if(l->SelfFd == fd[j] && l->ForbFlag == 1)
{
RecvBuf.cmd = FORRBIDDEN;
ret = send(fd[j], &RecvBuf, sizeof(RecvBuf), 0);
if(-1 == ret)
{
perror("send");
exit(1);
}
break;
}
else
{
l = l->next;
}
}
if(NULL == l)
{
l = LinkNode->next;
while(l != NULL && l->Flag == 1)
{
if(l->SelfFd != fd[j])
{
ret = send(l->SelfFd, &RecvBuf, sizeof(RecvBuf), 0);
if(-1 == ret)
{
perror("SENDGROUP send");
exit(1);
}
}
l = l->next;
}
}
RecvBuf.cmd = 0;
}
/********************************表情、常用语*********************************/
if(EMOJONLINECHICK == RecvBuf.cmd)
{
Online l = LinkNode->next;
while(l)
{
if(l->SelfFd == fd[j] && l->ForbFlag == 1)
{
RecvBuf.cmd = FORRBIDDEN;
ret = send(fd[j], &RecvBuf, sizeof(RecvBuf), 0);
if(-1 == ret)
{
perror("send");
exit(1);
}
break;
}
else
{
l = l->next;
}
}
if(NULL == l)
{
RecvBuf.Tofd = fd[j];
ret = OnlineJudge(LinkNode, RecvBuf.name);
if(REFUSECHAT == ret)
{
RecvBuf.cmd = EMOJNOTONLINE;
ret = send(RecvBuf.Tofd, &RecvBuf, sizeof(RecvBuf), 0);
if(-1 == ret)
{
perror("EMOJONLINECHICK send");
exit(1);
}
}
else
{
RecvBuf.TargFd = ret;
RecvBuf.cmd = RECVEMOJ;
GetLinkName(LinkNode, fd[j], RecvBuf.name);
ret = send(RecvBuf.TargFd, &RecvBuf, sizeof(RecvBuf), 0);
if(-1 == ret)
{
perror("EMOJONLINECHICK send");
exit(1);
}
}
}
}
/************************************退出************************************/
if(QUIT == RecvBuf.cmd)
{
FD_CLR(fd[j], &ReadFd);
close(fd[j]);
}
if(SIGNAL == RecvBuf.cmd)
{
FD_CLR(fd[j], &ReadFd);
close(fd[j]);
}
/************************************下线************************************/
if(OFFLINE == RecvBuf.cmd)
{
RecvBuf.Tofd = fd[j];
Online l = LinkNode;
Online m;
while(l)
{
if(l->next->SelfFd == fd[j])
{
m = l->next;
l->next = m->next;
free(m);
break;
}
else
{
l = l->next;
}
}
ret = send(RecvBuf.Tofd, &RecvBuf, sizeof(RecvBuf), 0);
if(-1 == ret)
{
perror("OFFLINE send");
exit(1);
}
}
/************************************会员************************************/
if(MEMBER == RecvBuf.cmd)
{
Online l = LinkNode->next;
while(l)
{
if(l->SelfFd == fd[j])
{
AddMember(l->account);
break;
}
else
{
l = l->next;
}
}
}
/************************************禁言************************************/
if(FORRBIDDEN == RecvBuf.cmd)
{
Online l = LinkNode->next;
while(l)
{
printf("4444\n");
if(l->SelfFd == fd[j])
{
ret = JudgeMember(l->account);
break;
}
else
{
l = l->next;
}
}
if(SUCCESS == ret)
{
l = LinkNode->next;
while(l)
{
if(!(strcmp(l->name, RecvBuf.Forbname)))
{
l->ForbFlag = 1;
break;
}
else
{
l = l->next;
}
}
}
else
{
RecvBuf.cmd = NOTMEMBER;
ret = send(fd[j], &RecvBuf, sizeof(RecvBuf), 0);
if(-1 == ret)
{
perror("send");
exit(1);
}
}
}
/**********************************解除禁言************************************/
if(DISMISS == RecvBuf.cmd)
{
Online l = LinkNode->next;
while(l)
{
if(l->SelfFd == fd[j])
{
ret = JudgeMember(l->account);
break;
}
else
{
l = l->next;
}
}
if(SUCCESS == ret)
{
l = LinkNode->next;
while(1)
{
if(!strcmp(l->name, RecvBuf.Forbname))
{
l->ForbFlag = 0;
break;
}
else
{
l = l->next;
}
}
}
else
{
RecvBuf.cmd = NOTDISMISS;
ret = send(fd[j], &RecvBuf, sizeof(RecvBuf), 0);
if(-1 == ret)
{
perror("send");
exit(1);
}
}
}
/************************************踢人************************************/
if(FUCKOUT == RecvBuf.cmd)
{
RecvBuf.Tofd = fd[j];
Online l = LinkNode->next;
while(1)
{
if(l->SelfFd == fd[j])
{
ret = JudgeMember(l->account);
break;
}
else
{
l = l->next;
}
}
if(SUCCESS == ret)
{
l = LinkNode->next;
while(1)
{
if(!strcmp(l->name, RecvBuf.name))
{
ret = send(l->SelfFd, &RecvBuf, sizeof(RecvBuf), 0);
if(-1 == ret)
{
perror("FUCKOUT send");
exit(1);
}
break;
}
else
{
l = l->next;
}
}
if(NULL == l)
{
RecvBuf.cmd = NOTONLINE;
ret = send(fd[j], &RecvBuf, sizeof(RecvBuf), 0);
if(-1 == ret)
{
perror("send");
exit(1);
}
}
}
else
{
RecvBuf.cmd = NOTFUCK;
ret = send(fd[j], &RecvBuf, sizeof(RecvBuf), 0);
if(-1 == ret)
{
perror("send");
exit(1);
}
}
}
}
/************************************文件传输********************************/
if(FILESENDREQUST == RecvBuf.cmd)
{
RecvBuf.Tofd = fd[j];
ret = OnlineJudge(LinkNode, RecvBuf.TarName);
if(REFUSECHAT == ret)
{
RecvBuf.cmd = REFUSESEND;
ret = send(RecvBuf.Tofd, &RecvBuf, sizeof(RecvBuf), 0);
if(-1 == ret)
{
perror("send");
exit(1);
}
}
else
{
RecvBuf.TargFd = ret;
RecvBuf.cmd = ACCEPTSEND;
ret = send(RecvBuf.Tofd, &RecvBuf, sizeof(RecvBuf), 0);
if(-1 == ret)
{
perror("send");
exit(1);
}
}
RecvBuf.cmd = 0;
}
if(FILESEND == RecvBuf.cmd)
{
printf("%d\n", RecvBuf.TargFd);
RecvBuf.cmd = RECVFILE;
ret = send(RecvBuf.TargFd, &RecvBuf, sizeof(RecvBuf), 0);
if(-1 == ret)
{
perror("send");
exit(1);
}
}
else if(SENDDONE == RecvBuf.cmd)
{
printf("%d\n", RecvBuf.TargFd);
ret = send(RecvBuf.TargFd, &RecvBuf, sizeof(RecvBuf), 0);
if(-1 == ret)
{
perror("send");
exit(1);
}
}
/****************************************************************************/
}
}
}
return 0;
}
客户端部分
客户端接口函数
#include "chatroom1.h"
int ACCOUNTFLAG = 0;
int EXISTFLAG = 0;
void hand(int tmp)
{
extern pthread_t tid[3];
extern int sockfd;
int ret;
Node Tmp ={0};
Tmp.cmd = SIGNAL;
ret = send(sockfd, &Tmp, sizeof(Tmp), 0);
if(-1 == ret)
{
perror("Exit send");
exit(1);
}
system("clear");
printf("\n\n\n\n\n\n");
printf("\t\t\t\t异常退出,正在保存后台数据,请稍等...\n\n\n");
sleep(2);
pthread_cancel(tid[0]);
close(sockfd);
exit(1);
}
void PrintTime()
{
time_t t;
struct tm *pt;
time(&t);
pt = localtime(&t);
printf("\t\t\t\t%d年%d月%d日%d:%d\n", pt->tm_year + 1900, pt->tm_mon, pt->tm_mday, pt->tm_hour, pt->tm_min);
}
void *Recv(void *arg)
{
int ret, sockfd, i;
char FileName[50] = {0};
FILE *fp;
extern pthread_t tid[3];
Node RecvBuf = {0};
sockfd = *(int *)arg;
while(1)
{
memset(&RecvBuf, 0, sizeof(RecvBuf));
ret = recv(sockfd, &RecvBuf, sizeof(RecvBuf), 0);
if(-1 == ret)
{
perror("recv");
exit(1);
}
switch(RecvBuf.cmd)
{
case RECVGROUP: //群发
system("clear");
printf("\t\t\t\t****************************************************\n\n");
printf("\t\t\t\t收到一条来自%s群发消息:%s\n", RecvBuf.name, RecvBuf.ChatBuf);
printf("\t\t\t\t输入 q 返回主界面\n\n");
break;
case RETONLINE: //在线好友
printf("\n");
printf("\t\t\t\t****************************************************\n\n");
printf("\t\t\t\t在线好友如下:\n\n");
for(i = 0; i <= RecvBuf.num; i++)
{
printf("\t\t\t\t%s\n\n", RecvBuf.onlinefriend[i]);
}
break;
case CHECKHISDONE: //聊天记录
system("clear");
ShowChatHist();
break;
case NOTMEMBER: //非会员
system("clear");
printf("\t\t\t\t****************************************************\n\n");
printf("\t\t\t\t您不是会员,无法这么做\n\n");
printf("\t\t\t\t\t\t\t\t输入 q 返回主界面\n\n");
break;
case NOTDISMISS: //无法解禁
system("clear");
printf("\t\t\t\t****************************************************\n\n");
printf("\t\t\t\t您不是会员,无法这么做\n\n");
printf("\t\t\t\t\t\t\t\t输入 q 返回主界面\n\n");
break;
case NOTFUCK:
system("clear");
printf("\t\t\t\t****************************************************\n\n");
printf("\t\t\t\t您不是会员,无法这么做\n\n");
printf("\t\t\t\t\t\t\t\t输入 q 返回主界面\n\n");
break;
case EMOJNOTONLINE:
system("clear");
printf("\t\t\t\t****************************************************\n\n");
printf("\t\t\t\t对方并不在线,无法接收到信息.\n\n");
break;
case RECVEMOJ:
system("clear");
printf("\t\t\t\t****************************************************\n\n");
printf("\t\t\t\t收到一条来自%s表情或常用语消息\n\n", RecvBuf.name);
printf("\t\t\t\t%s\n", RecvBuf.ChatBuf);
printf("\t\t\t\t\t\t\t\t\t输入 q 返回主界面\n\n");
break;
case FORRBIDDEN:
system("clear");
printf("\t\t\t\t****************************************************\n\n");
printf("\t\t\t\t您已被禁言,无法发送信息,成为会员解除禁言\n\n");
sleep(1);
system("clear");
break;
case NOTONLINE:
system("clear");
printf("\t\t\t\t****************************************************\n\n");
printf("\t\t\t\t对方已下线\n\n");
sleep(1);
system("clear");
break;
case FUCKOUT:
system("clear");
printf("\t\t\t\t****************************************************\n\n");
printf("\t\t\t\t您已被踢下线,输入r返回登录界面,成为会员报复Ta\n\n");
break;
case REFUSECHAT:
system("clear");
printf("\t\t\t\t****************************************************\n\n");
printf("\t\t\t\t对方并不在线\n\n");
printf("\t\t\t\t\t\t\t\t\t输入 q 返回主界面\n\n");
break;
case ALLOWCHAT:
system("clear");
printf("\t\t\t\t****************************************************\n\n");
printf("\t\t\t\t%s\n\n", RecvBuf.ChatBuf);
break;
case ACCEPTCHAT:
system("clear");
printf("\t\t\t\t\t\t\t\t输入k进行回复\n");
printf("\t\t\t\t****************************************************\n\n");
printf("\t\t\t\t\t\t\t\t%s\n", RecvBuf.name);
printf("\t\t\t\t\t\t\t\t%s\n\n", RecvBuf.ChatBuf);
break;
case CHATTING:
printf("\n");
printf("\t\t\t\t\t\t\t\t%s\n", RecvBuf.name);
printf("\t\t\t\t\t\t\t\t%s\n\n", RecvBuf.ChatBuf);
ret = AddChatHist(RecvBuf.name, RecvBuf.ChatBuf);
if(FAILURE == ret)
{
printf("Insert Failure\n");
exit(1);
}
if(!strcmp(RecvBuf.ChatBuf, "bye"))
{
pthread_cancel(tid[1]);
}
break;
case REFUSESEND:
system("clear");
printf("\t\t\t\t对方不在线,无法接收文件\n\n");
sleep(1);
system("clear");
break;
case ACCEPTSEND:
fp = fopen(RecvBuf.FilePath, "r");
RecvBuf.cmd = FILESEND;
while(ret = fread(RecvBuf.FileBuf, 1, sizeof(RecvBuf.FileBuf), fp))
{
send(sockfd, &RecvBuf, sizeof(RecvBuf), 0);
memset(RecvBuf.FileBuf, 0, sizeof(RecvBuf.FileBuf));
}
RecvBuf.cmd = SENDDONE;
send(sockfd, &RecvBuf, sizeof(RecvBuf), 0);
fclose(fp);
break;
case RECVFILE:
fp = fopen("myhello.txt", "a");
ret = fwrite(RecvBuf.FileBuf, 1, strlen(RecvBuf.FileBuf), fp);
if(0 == ret)
{
perror("fwrite");
exit(1);
}
fclose(fp);
break;
case SENDDONE:
printf("\t\t\t\t收到一个文件\n\n");
break;
}
}
}
void *Send(void *arg)
{
int ret, sockfd, oldtype;
extern pthread_t tid[3];
extern char filename[15];
extern char Myname[10];
FILE *fp;
Node Tmp = {0};
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldtype);
sockfd = *(int *)arg;
fp = fopen(filename, "a");
while(1)
{
scanf("%s", Tmp.ChatBuf);
Tmp.cmd = CHATTING;
ret = send(sockfd, &Tmp, sizeof(Tmp), 0);
if(-1 == ret)
{
perror("send");
exit(1);
}
ret = AddChatHist(Myname, Tmp.ChatBuf);
if(FAILURE == ret)
{
printf("Insert Failure\n");
exit(1);
}
if(!strcmp(Tmp.ChatBuf, "bye"))
{
close(tid[1]);
break;
}
}
fclose(fp);
}
int loadshow(int sockfd)
{
system("clear");
PrintTime();
printf("\t\t\t\t****************************************************\n\n");
printf("\t\t\t\t*** 简易聊天室 ***\n\n");
printf("\t\t\t\t*** 1.登录 ***\n\n");
printf("\t\t\t\t*** 2.注册 ***\n\n");
printf("\t\t\t\t*** 3.忘记密码 ***\n\n");
printf("\t\t\t\t*** 4.退出 ***\n\n");
printf("\t\t\t\t****************************************************\n\n");
printf("\t\t\t\t请输入你的选择 : \n");
}
void Exit(int sockfd)
{
int ret;
extern pthread_t tid[3];
Node Tmp = {0};
Tmp.cmd = QUIT;
ret = send(sockfd, &Tmp, sizeof(Tmp), 0);
if(-1 == ret)
{
perror("Exit send");
exit(1);
}
pthread_cancel(tid[0]);
close(sockfd);
exit(1);
}
void Loginshow(int sockfd) //登录
{
int ret;
FILE *fp;
Node LogInfo = {0};
extern char Myname[10];
extern char filename[15];
PrintTime();
printf("\t\t\t\t****************************************************\n\n");
printf("\t\t\t\t请输入账号:\n\n");
printf("\t\t\t\t");
scanf("%s", LogInfo.account);
printf("\n");
printf("\t\t\t\t请输入密码:\n\n");
printf("\t\t\t\t");
scanf("%s", LogInfo.password);
LogInfo.cmd = LOGIN;
ret = send(sockfd, &LogInfo, sizeof(LogInfo), 0);
if(-1 == ret)
{
perror("Logsend");
exit(1);
}
memset(&LogInfo, 0, sizeof(LogInfo));
ret = recv(sockfd, &LogInfo, sizeof(LogInfo), 0);
if(-1 == ret)
{
perror("recv");
exit(1);
}
if(ALLOWLOGIN == LogInfo.cmd)
{
int ret;
LogInfo.cmd = INSERT;
ret = send(sockfd, &LogInfo, sizeof(LogInfo), 0);
if(-1 == ret)
{
perror("Logsend");
exit(1);
}
system("clear");
PrintTime();
printf("\t\t\t\t****************************************************\n\n");
printf("\t\t\t\t登录成功,正在跳转聊天界面。\n\n\n");
sleep(1);
printf("\t\t\t\t\t\t欢迎回来 ");
printf("%s\n\n", LogInfo.name);
sleep(1);
system("clear");
strcpy(Myname, LogInfo.name);
strcpy(filename, LogInfo.name);
strcat(filename, ".txt");
fp = fopen(filename, "a");
fclose(fp);
LogSuccshow(sockfd);
}
else if(REFUSELOGIN == LogInfo.cmd)
{
system("clear");
PrintTime();
printf("\t\t\t\t****************************************************\n\n");
printf("\t\t\t\t登录失败,请检查你的账号与密码。\n");
printf("\t\t\t\t跳转登录界面中,请稍候...\n");
sleep(1);
}
}
void Registershow(int sockfd) //注册
{
Node RegInfo = {0};
int ret, length1, length2;
char TmpPass[20] = {0};
PrintTime();
printf("\t\t\t\t****************************************************\n\n");
printf("\t\t\t\t请输入账号:\n\n");
printf("\t\t\t\t");
scanf("%s", RegInfo.account);
printf("\n");
printf("\t\t\t\t请输入密码(16字节以内):\n\n");
printf("\t\t\t\t");
scanf("%s", RegInfo.password);
printf("\n");
printf("\t\t\t\t请确认密码(16字节以内):\n\n");
printf("\t\t\t\t");
scanf("%s", TmpPass);
printf("\n");
printf("\t\t\t\t请输入昵称:\n\n");
printf("\t\t\t\t");
scanf("%s", RegInfo.name);
printf("\n");
printf("\t\t\t\t请输入绑定手机号:\n\n");
printf("\t\t\t\t");
scanf("%s", RegInfo.telephone);
length1 = strlen(RegInfo.password);
length2 = strlen(RegInfo.telephone);
if(length1 > 16)
{
printf("\t\t\t\t密码长度不符合,请重新注册。\n");
sleep(1);
system("clear");
}
else if(strcmp(RegInfo.password, TmpPass) != 0)
{
printf("\t\t\t\t两次密码不一致,请重新注册.\n");
sleep(1);
system("clear");
}
else if(length2 != 11)
{
printf("\t\t\t\t手机号码无效,请重新输入。\n");
sleep(1);
system("clear");
}
else
{
RegInfo.cmd = REGISTER;
ret = send(sockfd, &RegInfo, sizeof(RegInfo), 0);
if(-1 == ret)
{
perror("Regsend");
exit(1);
}
memset(&RegInfo, 0, sizeof(RegInfo));
ret = recv(sockfd, &RegInfo, sizeof(RegInfo), 0);
if(REGFAILURE == RegInfo.cmd)
{
system("clear");
PrintTime();
printf("\t\t\t\t****************************************************\n\n");
printf("\t\t\t\t您使用的账号已存在,请重新选择账号进行注册!!\n");
printf("\t\t\t\t跳转中,请稍后!\n");
sleep(1);
system("clear");
}
else if(REGSUCCESS == RegInfo.cmd)
{
system("clear");
PrintTime();
printf("\t\t\t\t****************************************************\n\n");
printf("\t\t\t\t注册成功,正在跳转登录界面。\n");
sleep(2);
system("clear");
}
}
}
void ForgetPass(int sockfd) //忘记密码
{
char account[10] = {0};
char tele[12] = {0};
int length, ret;
Node Tmp = {0};
PrintTime();
printf("\t\t\t\t****************************************************\n\n");
printf("\t\t\t\t请输入您的账号:\n\n");
printf("\t\t\t\t");
scanf("%s", account);
printf("\n");
printf("\t\t\t\t请输入绑定的手机号码:\n\n");
printf("\t\t\t\t");
scanf("%s", tele);
length = strlen(tele);
if(length != 11)
{
printf("\t\t\t\t输入的手机号码无效,请重新输入。\n");
sleep(1);
system("clear");
}
else
{
Tmp.cmd = CONFIRMACCOUNT;
strcpy(Tmp.account, account);
strcpy(Tmp.telephone, tele);
ret = send(sockfd, &Tmp, sizeof(Tmp), 0);
if(-1 == ret)
{
perror("CONFIRMACCOUNT send");
exit(1);
}
memset(&Tmp, 0, sizeof(Tmp));
ret = recv(sockfd, &Tmp, sizeof(Tmp), 0);
if(-1 == ret)
{
perror("rcv");
exit(1);
}
if(EXIST == Tmp.cmd)
{
printf("\t\t\t\t正在为您跳转修改密码界面,请稍后...\n");
sleep(1);
system("clear");
ResetPass(sockfd, Tmp.account);
}
else if(NOTEXIST == Tmp.cmd)
{
printf("\t\t\t\t此账号不存在,跳转注册界面中...\n\n");
sleep(1);
system("clear");
}
}
}
int ResetPass(int sockfd, char *account) //密码重置
{
char password[20] = {0};
char Tmppass[20] = {0};
int length, ret;
Node Tmp = {0};
PrintTime();
printf("\t\t\t\t****************************************************\n\n");
printf("\t\t\t\t请输入密码(16字节以内):\n\n");
printf("\t\t\t\t");
scanf("%s", password);
printf("\n");
printf("\t\t\t\t请确认密码(16字节以内):\n\n");
printf("\t\t\t\t");
scanf("%s", Tmppass);
printf("\n");
length = strlen(password);
while(length > 16 || strcmp(password, Tmppass) != 0)
{
if(length > 16)
{
printf("\t\t\t\t密码长度不符合,请重新输入\n");
sleep(1);
system("clear");
PrintTime();
printf("\t\t\t\t****************************************************\n\n");
printf("\t\t\t\t请输入密码(16字节以内):\n\n");
printf("\t\t\t\t");
scanf("%s", password);
printf("\n");
printf("\t\t\t\t请确认密码(16字节以内):\n\n");
printf("\t\t\t\t");
scanf("%s", Tmppass);
printf("\n");
length = strlen(password);
}
else if(strcmp(password, Tmppass) != 0)
{
printf("\t\t\t\t两次密码不一致,请重新输入.\n");
sleep(1);
system("clear");
PrintTime();
printf("\t\t\t\t****************************************************\n\n");
printf("\t\t\t\t请输入密码(16字节以内):\n\n");
printf("\t\t\t\t");
scanf("%s", password);
printf("\n");
printf("\t\t\t\t请确认密码(16字节以内):\n\n");
printf("\t\t\t\t");
scanf("%s", Tmppass);
printf("\n");
length = strlen(password);
}
}
strcpy(Tmp.account, account);
strcpy(Tmp.password, password);
Tmp.cmd = CHANGEPASS;
ret = send(sockfd, &Tmp, sizeof(Tmp), 0);
if(-1 == ret)
{
perror("send");
return FAILURE;
}
memset(&Tmp, 0, sizeof(Tmp));
ret = recv(sockfd, &Tmp, sizeof(Tmp), 0);
if(-1 == ret)
{
perror("recv");
return FAILURE;
}
if(CHANGESUCCESS == Tmp.cmd)
{
printf("\t\t\t\t修改密码成功,跳转登录界面中...\n\n");
sleep(1);
system("clear");
}
}
void LogSuccshow(int sockfd)
{
system("clear");
char choice[10] = {0};
extern char Myname[10];
extern pthread_t tid[3];
int ret, oldtype;
int i = 0;
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldtype);
ret = pthread_create(&tid[0],NULL, Recv, (void *)&sockfd);
if(0 != ret)
{
perror("pthread_creat");
exit(1);
}
while(1)
{
PrintTime();
printf("\t\t\t\t**********************************************************\n\n");
printf("\t\t\t\t\t\t\t%s\n", Myname);
printf("\t\t\t\t\t a.私聊 \n\n");
printf("\t\t\t\t\t b.群发 \n\n");
printf("\t\t\t\t\t c.查看在线好友 \n\n");
printf("\t\t\t\t\t d.查看聊天记录 \n\n");
printf("\t\t\t\t\t e.开通会员 \n\n");
printf("\t\t\t\t\t f.禁言模式(会员)\n\n");
printf("\t\t\t\t\t g.解除禁言(会员)\n\n");
printf("\t\t\t\t\t h.表情、常用语 \n\n");
printf("\t\t\t\t\t i.踢人(会员) \n\n");
printf("\t\t\t\t\t j.下线 \n\n");
printf("\t\t\t\t\t t.文件传输 \n\n");
printf("\t\t\t\t***********************************************************\n\n");
printf("\t\t\t\t请输入你的选择:\n");
printf("\t\t\t\t");
scanf("%s", choice);
switch(choice[0])
{
case 'a':
system("clear");
PriChat(sockfd);
break;
case 'b':
SendGroup(sockfd);
break;
case 'c':
system("clear");
CheckOnline(sockfd);
break;
case 'd':
system("clear");
SearChatHis(sockfd);
break;
case 'e':
system("clear");
member(sockfd);
break;
case 'f':
system("clear");
ForbidMod(sockfd);
break;
case 'g':
system("clear");
Dismiss(sockfd);
break;
case 'h':
system("clear");
SendEmoj(sockfd);
break;
case 'i':
system("clear");
Fuck(sockfd);
break;
case 'j':
system("clear");
Offline(sockfd);
i = 9;
break;
case 'k':
RecvChat(sockfd);
break;
case 't':
Transform(sockfd);
break;
case 'q':
system("clear");
break;
case 'r':
FuckOffline();
i = 9;
break;
default:
printf("Unkown choice\n");
sleep(1);
system("clear");
}
if(i == 9)
{
printf("1 = %d\n", i);
break;
}
}
}
/*************聊天功能函数****************/
int PriChat(int sockfd)
{
int ret;
Node SendBuf = {0};
extern pthread_t tid[3];
PrintTime();
printf("\t\t\t\t****************************************************\n\n");
printf("\t\t\t\t请输入你想私聊的对象:\n");
printf("\t\t\t\t");
scanf("%s",SendBuf.TarName);
printf("\n\n");
printf("\t\t\t\t请输入你想说的话:\n");
printf("\t\t\t\t");
scanf("%s",SendBuf.ChatBuf);
SendBuf.cmd = CHATREQUST;
ret = send(sockfd, &SendBuf, sizeof(SendBuf), 0);
if(-1 == ret)
{
perror("PriChat send");
return FAILURE;
}
ret = pthread_create(&tid[1], NULL, Send, (void *)&sockfd);
if(0 != ret)
{
perror("pthread_create");
exit(1);
}
pthread_join(tid[1], NULL);
return SUCCESS;
}
int RecvChat(int sockfd)
{
int ret;
extern pthread_t tid[3];
system("clear");
PrintTime();
printf("\t\t\t\t****************************************************\n\n");
ret = pthread_create(&tid[1], NULL, Send, (void *)&sockfd);
if(0 != ret)
{
perror("pthread_create");
exit(1);
}
pthread_join(tid[1], NULL);
}
int ChattingShow(int sockfd, int TargFd, char *name, char *Tarname)
{
int ret;
Node Tmp = {0};
extern char filename[15];
FILE *fp;
Tmp.TargFd = TargFd;
Tmp.Tofd = sockfd;
strcpy(Tmp.TarName, Tarname);
strcpy(Tmp.name, name);
printf("%s %s \n", Tarname, name);
PrintTime();
printf("\t\t\t\t简易聊天室\n");
printf("\t\t\t\t****************************************************\n\n");
printf("\t\t\t\t");
scanf("%s", Tmp.ChatBuf); //聊天内容
fp = fopen(filename, "a");
if(NULL == fp)
{
perror("fopen");
return FAILURE;
}
ret = AddChatHist(name, Tmp.ChatBuf);
if(FAILURE == ret)
{
printf("Add Failure");
exit(1);
}
fclose(fp);
Tmp.cmd = PRECHATTING;
ret = send(sockfd, &Tmp, sizeof(Tmp), 0);
if(-1 == ret)
{
perror("ChattingShow send");
return FAILURE;
}
return SUCCESS;
}
int ChattingShow2(int sockfd, int TargFd, char *name, char *Tarname)
{
int ret;
Node Tmp = {0};
Tmp.TargFd = TargFd;
Tmp.Tofd = sockfd;
strcpy(Tmp.TarName, Tarname);
strcpy(Tmp.name, name);
system("clear");
PrintTime();
printf("\t\t\t\t简易聊天室 回复请输入'k'\n");
printf("\t\t\t\t****************************************************\n\n");
return SUCCESS;
}
int SendGroup(int sockfd)
{
int ret;
Node Tmp = {0};
system("clear");
PrintTime();
printf("\t\t\t\t简易聊天室 \n");
printf("\t\t\t\t****************************************************\n\n");
printf("\t\t\t\t请输入群发的信息内容:");
scanf("%s", Tmp.ChatBuf);
Tmp.cmd = SENDGROUP;
ret = send(sockfd, &Tmp, sizeof(Tmp), 0);
if(-1 == ret)
{
perror("SendGroup send");
exit(1);
}
sleep(2);
system("clear");
}
int CheckOnline(int sockfd)
{
int ret;
Node Tmp = {0};
Tmp.cmd = CHECKONLINE;
ret = send(sockfd, &Tmp, sizeof(Tmp), 0);
if(-1 == ret)
{
perror("CheckOnline");
exit(1);
}
sleep(2);
}
int SearChatHis(int sockfd)
{
int ret;
Node Tmp = {0};
Tmp.cmd = CHECKHISTORY;
printf("11111\n");
ret = send(sockfd, &Tmp, sizeof(Tmp), 0);
if(-1 == ret)
{
perror("SearChatHis send");
exit(1);
}
}
void ShowChatHist()
{
char choice[10] = {0};
extern char filename[15];
FILE *fp;
ChatHist HisTmp = {0};
int ret;
PrintTime();
printf("\t\t\t\t****************************************************\n\n");
ret = 1;
fp = fopen(filename, "r");
while(ret)
{
ret = fread(&HisTmp, 1, sizeof(HisTmp), fp);
printf("\t\t\t\t%d年%d月%d日%d:%d:%d\n", HisTmp.year, HisTmp.month, HisTmp.day, HisTmp.hour, HisTmp.min,HisTmp.sec);
printf("\t\t\t\t%s\n", HisTmp.name);
printf("\t\t\t\t%s\n\n", HisTmp.cont);
}
printf("\t\t\t\t\t\t\t输入q返回上一级菜单\n\n");
fclose(fp);
}
void member(int sockfd)
{
int ret;
Node Tmp = {0};
char choice[10] = {0};
PrintTime();
printf("\t\t\t\t简易聊天室 \n");
printf("\t\t\t\t****************************************************\n\n");
printf("\t\t\t\t你愿意誓死守护皇家的荣誉吗?\n\n");
printf("\t\t\t\tyes or no \n\n");
printf("\t\t\t\t");
scanf("%s", choice);
if(!strcmp(choice, "yes"))
{
Tmp.cmd = MEMBER;
ret = send(sockfd, &Tmp, sizeof(Tmp), 0);
if(-1 == ret)
{
perror("sned");
exit(1);
}
printf("\t\t\t\t恭喜你成为尊贵的会员,拥有踢人,禁言等功能\n\n");
sleep(2);
system("clear");
}
else
{
printf("\t\t\t\t注定与荣耀无缘\n\n");
sleep(2);
}
}
void ForbidMod(int sockfd)
{
char name[10] = {0};
Node Tmp = {0};
int ret;
printf("\t\t\t\t请输入你想禁言的昵称\n\n");
printf("\t\t\t\t");
scanf("%s", Tmp.Forbname);
Tmp.cmd = FORRBIDDEN;
ret = send(sockfd, &Tmp, sizeof(Tmp), 0);
if(-1 == ret)
{
perror("ForbidMod send");
exit(1);
}
system("clear");
}
void Dismiss(int sockfd)
{
char name[10] = {0};
Node Tmp = {0};
int ret;
printf("\t\t\t\t请输入你想解除禁言的昵称\n\n");
printf("\t\t\t\t");
scanf("%s", Tmp.Forbname);
Tmp.cmd = DISMISS;
ret = send(sockfd, &Tmp, sizeof(Tmp), 0);
if(-1 == ret)
{
perror("ForbidMod send");
exit(1);
}
system("clear");
}
void Offline(int sockfd)
{
int ret;
Node Tmp = {0};
Tmp.cmd = OFFLINE;
ret = send(sockfd, &Tmp, sizeof(Tmp), 0);
if(-1 == ret)
{
perror("OFFLINE send");
exit(1);
}
}
void FuckOffline()
{
extern pthread_t tid[3];
pthread_cancel(tid[0]);
}
void Fuck(int sockfd)
{
int ret;
Node Tmp = {0};
printf("\t\t\t\t请输入你想踢下线的用户\n");
printf("\t\t\t\t");
scanf("%s", Tmp.name);
Tmp.cmd = FUCKOUT;
ret = send(sockfd, &Tmp, sizeof(Tmp), 0);
if(-1 == ret)
{
perror("Fuck send");
exit(1);
}
sleep(1);
system("clear");
}
void LogSuccshow1()
{
PrintTime();
printf("\t\t\t\t****************************************************\n\n");
printf("\t\t\t\t\t a.私聊 \n\n");
printf("\t\t\t\t\t b.群发 \n\n");
printf("\t\t\t\t\t c.查看在线好友 \n\n");
printf("\t\t\t\t\t d.查看聊天记录 \n\n");
printf("\t\t\t\t\t e.禁言模式 \n\n");
printf("\t\t\t\t\t f.表情、常用语 \n\n");
printf("\t\t\t\t\t g.踢人 \n\n");
printf("\t\t\t\t\t h.下线 \n\n");
printf("\t\t\t\t****************************************************\n\n");
printf("\t\t\t\t请输入你的选择:\n");
}
void Transform(int sockfd)
{
int ret;
char filepath[30] = {0};
FILE *fp;
Node Tmp = {0};
printf("\t\t\t\t请输入接收方的昵称\n\n");
printf("\t\t\t\t");
scanf("%s", Tmp.TarName);
printf("\t\t\t\t请输入文件名\n\n");
printf("\t\t\t\t");
scanf("%s", Tmp.FilePath);
Tmp.cmd = FILESENDREQUST;
ret = send(sockfd, &Tmp, sizeof(Tmp), 0);
if(-1 == ret)
{
perror("send");
exit(1);
}
usleep(1000);
system("clear");
}
int AddChatHist(char *Targname, char *chat)
{
int ret;
time_t t;
struct tm *pt;
extern char filename[15];
FILE *fp;
time(&t);
pt = localtime(&t);
ChatHist Tmp = {0};
Tmp.year = pt->tm_year + 1900;
Tmp.month = pt->tm_mon;
Tmp.day = pt->tm_mday;
Tmp.hour = pt->tm_hour;
Tmp.min = pt->tm_min;
Tmp.sec = pt->tm_sec;
strcpy(Tmp.name, Targname);
strcpy(Tmp.cont, chat);
fp = fopen(filename, "a");
if(NULL == fp)
{
perror("fopen");
return FAILURE;
}
ret = fwrite(&Tmp, 1, sizeof(ChatHist), fp);
if(0 == ret)
{
perror("fwrite");
return FAILURE;
}
fclose(fp);
return SUCCESS;
}
int SendEmoj(int sockfd)
{
char choice[10] = {0};
int ret;
extern char *Emoj[8];
extern char *languae[5];
Node Tmp = {0};
PrintTime();
printf("\t\t\t\t简易聊天室\n");
printf("\t\t\t\t****************************************************\n\n");
printf("\t\t\t\t请输入发送对象的昵称:\n\n");
printf("\t\t\t\t");
scanf("%s", Tmp.name);
system("clear");
PrintTime();
printf("\t\t\t\t简易聊天室\n");
printf("\t\t\t\t****************************************************\n\n");
printf("\t\t\t\t*** 1.表情 2.常用语 ***\n\n");
printf("\t\t\t\t****************************************************\n\n");
printf("\t\t\t\t请输入你的选择:\n\n");
printf("\t\t\t\t");
scanf("%s", choice);
while(!(atoi(&choice[0]) == 1 || atoi(&choice[0]) == 2))
{
printf("\t\t\t\t你输入有误,请重新输入\n\n");
printf("\t\t\t\t");
memset(choice, 0, sizeof(choice));
scanf("%s", choice);
}
if(atoi(&choice[0]) == 1)
{
memset(choice, 0, sizeof(choice));
system("clear");
PrintTime();
printf("\t\t\t\t简易聊天室\n");
printf("\t\t\t\t****************************************************\n\n");
printf("\t\t\t\t*** 1.<( ̄︶ ̄)> ***\n\n");
printf("\t\t\t\t*** 2.<( ̄︶ ̄)/ ***\n\n");
printf("\t\t\t\t*** 3.(# ̄▽ ̄#) ***\n\n");
printf("\t\t\t\t*** 4.b( ̄▽ ̄)d ***\n\n");
printf("\t\t\t\t*** 5. ~>_<~ ***\n\n");
printf("\t\t\t\t*** 6. (>﹏<) ***\n\n");
printf("\t\t\t\t*** 7. (┬_┬) ***\n\n");
printf("\t\t\t\t*** 8.(︶^︶)=凸 ***\n\n");
printf("\t\t\t\t****************************************************\n\n");
printf("\t\t\t\t请输入你的选择:\n\n");
printf("\t\t\t\t");
scanf("%s", choice);
switch(atoi(&choice[0]))
{
case 1:
strcpy(Tmp.ChatBuf, Emoj[0]);
break;
case 2:
strcpy(Tmp.ChatBuf, Emoj[1]);
break;
case 3:
strcpy(Tmp.ChatBuf, Emoj[2]);
break;
case 4:
strcpy(Tmp.ChatBuf, Emoj[3]);
break;
case 5:
strcpy(Tmp.ChatBuf, Emoj[4]);
break;
case 6:
strcpy(Tmp.ChatBuf, Emoj[5]);
break;
case 7:
strcpy(Tmp.ChatBuf, Emoj[6]);
break;
case 8:
strcpy(Tmp.ChatBuf, Emoj[7]);
break;
default:
printf("\t\t\t\tUnkown choose\n");
sleep(1);
system("clear");
}
printf("%s\n", Tmp.ChatBuf);
Tmp.cmd = EMOJONLINECHICK;
ret = send(sockfd, &Tmp, sizeof(Tmp), 0);
if(-1 == ret)
{
perror("EMOJ send");
exit(1);
}
}
else if(atoi(&choice[0]) == 2)
{
memset(choice, 0, sizeof(choice));
system("clear");
PrintTime();
printf("\t\t\t\t简易聊天室\n");
printf("\t\t\t\t****************************************************\n\n");
printf("\t\t\t\t*** 1.祝 ***\n\n");
printf("\t\t\t\t*** 2.大家 ***\n\n");
printf("\t\t\t\t*** 3.圣诞节 ***\n\n");
printf("\t\t\t\t*** 4.元旦节 ***\n\n");
printf("\t\t\t\t*** 5.快乐 ***\n\n");
printf("\t\t\t\t****************************************************\n\n");
printf("\t\t\t\t请输入你的选择:\n\n");
printf("\t\t\t\t");
scanf("%s", choice);
switch(atoi(&choice[0]))
{
case 1:
strcpy(Tmp.ChatBuf, languae[0]);
break;
case 2:
strcpy(Tmp.ChatBuf, languae[1]);
break;
case 3:
strcpy(Tmp.ChatBuf, languae[2]);
break;
case 4:
strcpy(Tmp.ChatBuf, languae[3]);
break;
case 5:
strcpy(Tmp.ChatBuf, languae[4]);
break;
default:
printf("\t\t\t\tUnkown choose\n");
sleep(1);
system("clear");
}
Tmp.cmd = EMOJONLINECHICK;
ret = send(sockfd, &Tmp, sizeof(Tmp), 0);
if(-1 == ret)
{
perror("EMOJ send");
exit(1);
}
}
sleep(1);
system("clear");
}
#include "chatroom1.h"
pthread_t tid[3];
char Myname[10];
char filename[15];
char GroupMsg[10];
int sockfd;
char *Emoj[8] = {"<( ̄︶ ̄)>", "<( ̄︶ ̄)/", "(# ̄▽ ̄#)", "b( ̄▽ ̄)d", "~>_<~", "(>﹏<)", "(┬_┬)", "(︶^︶)=凸"};
char *languae[5] = {"祝", "大家", "圣诞节", "元旦节", "快乐"};
int main()
{
int ret;
char choice[10] = {0};
struct sockaddr_in server_addr;
sockfd = socket(PF_INET, SOCK_STREAM, 0);
if(-1 == sockfd)
{
perror("socket");
exit(1);
}
bzero(&server_addr, sizeof(server_addr));
server_addr.sin_family = PF_INET;
server_addr.sin_port = htons(PORT);
server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
printf("Connecting...\n");
ret = connect(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr));
if(-1 == ret)
{
perror("connect");
exit(1);
}
signal(SIGINT, hand);
while(1)
{
loadshow(sockfd);
printf("\t\t\t\t");
scanf("%s", choice);
switch(atoi(&choice[0]))
{
case 1:
system("clear");
Loginshow(sockfd);
break;
case 2:
system("clear");
Registershow(sockfd);
break;
case 3:
system("clear");
ForgetPass(sockfd);
break;
case 4:
Exit(sockfd);
break;
default:
printf("\t\t\t\tUnkown Choice\n");
sleep(1);
}
}
return 0;
}
总结:
对于这个项目中,让我最为印象深刻的部分是私聊界面的实现,当主线程执行到私聊时,需要另外开辟两个线程,一个用来接收,另一个用来发送信息,这样就可以连续的发送,直到发送了指定的内容再结束,那么此时会出现一个问题,受邀请聊天方,如果直接清屏的话,输入依然是上一个界面的scanf,那么此时如若回复信息的话,并不是真正的回复信息,而是执行了上一次的scanf,我是通过提示用户输入一个字符进行回复状态,其实这个字符只是完成被“隐藏的”scanf,那么通过这个字符去调用一个发送的线程,此时就能实现两个客户端的相互通信。