一、设计思路
聊天室主要基于socket网络编程来实现,所以第一步一定是使服务端和客户端连接通信,接下来就是发包和收包了。
在整个程序中,我将函数进行封装,其中一定要注意的是运算符的优先级,否则会出现Send:Socket operation on non-socket的错误。
对于服务器端,我使用了epoll实现服务器接收请求并处理请求
对于客户端,我将服务器返回的结果单独开线程进行(一定要用好锁和条件变量!),要尽可能减小锁的粒度,并且在send函数之后pthread_cond_wait()挂起等待。
在整个程序中,于我而言第一大难点是加好友和加群,因为不能让客户端发送完就一直等待,所以我创建了新的线程。第二是聊天segementation fault,第三是发送文件,经过向别人取经,我采用定长发包,多次循环,直到文件内容全部发送完成
在这其中,我还使用了数据库
server.c
#include "wrap.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <ctype.h>
#define SERV_PORT 8000
int main(void) {
struct sockaddr_in serveraddr,clientaddr;
int sockfd,addrlen,confd;
char ipstr[128];
sockfd = Socket(AF_INET, SOCK_STREAM, 0);
bzero(&serveraddr,sizeof(serveraddr));
serveraddr.sin_family = AF_INET;
serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
serveraddr.sin_port = htons(SERV_PORT);
Bind(sockfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr));
Listen(sockfd,128);
while(1) {
addrlen = sizeof(clientaddr);
confd = Accept(sockfd, &clientaddr, &addrlen);
inet_ntop(AF_INET, &clientaddr.sin_addr.s_addr, ipstr, sizeof(ipstr));
printf("client IP %s\tport %d\n",
inet_ntop(AF_INET, &clientaddr.sin_addr.s_addr, ipstr, sizeof(ipstr)),
ntohs(clientaddr.sin_addr.s_addr));//IP地址端口号
//处理客户端请求
Close(confd);
}
Close(sockfd);
return 0;
}
client.c
#include "wrap.h"
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define SERV_PORT 8000
int main(int argc, char *argv[]) {
struct sockaddr_in serveraddr;
char ipstr[ ]="192.168.30.134";
int confd;
confd = Socket(AF_INET, SOCK_STREAM, 0);
bzero(&serveraddr, sizeof(serveraddr));
serveraddr.sin_family = AF_INET;
inet_pton(AF_INET, ipstr, &serveraddr.sin_addr.s_addr);
serveraddr.sin_port = htons(SERV_PORT);
Connect(confd, (struct sockaddr *)&serveraddr, sizeof(serveraddr));
//请求服务器处理数据
Close(confd);
return 0;
}
二、问题
1.send recv包
在服务器和客户端连接上之后,主要就是通过send、recv包进行通信,所以PACK的结构体至关重要,需要足够明确且全面。但我因为开始没有什么思路,所以结构体的定义和封装的send()函数借鉴了别人的思路,我只做到了调用(就是会向里面传参)。。
#include <stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/types.h>
#include<sys/socket.h>
#define BUFSIZE 1024
#define MAX_CHAR 100
#define FRI_MAX 100
#define MAX_FILE 10000
typedef struct _user
{
char name[MAX_CHAR];
char passwd[MAX_CHAR];
int statu_s;
int fd;
char chat[MAX_CHAR];
struct _user *next;
}User;
typedef struct _relation
{
char name1[MAX_CHAR];
char name2[MAX_CHAR];
int statu_s;
struct _relation *next;
}Relation;
typedef struct _recordinfo
{
char name1[MAX_CHAR];
char name2[MAX_CHAR];
char message[BUFSIZE];
struct _recordinfo *next;
}Recordinfo;
typedef struct _friends
{
char friends[FRI_MAX][MAX_CHAR];
int friends_status[FRI_MAX];
int friends_num;
}FRI_INFO;
typedef struct _group
{
char groups[FRI_MAX][MAX_CHAR];
int grp_num;
}GROUP_INFO;
typedef struct _record
{
char name1[MAX_CHAR];
char name2[MAX_CHAR];
char message[MAX_CHAR];
}RECORD_INFO;
typedef struct _data
{
int send_fd;
int recv_fd;
char send_name[MAX_CHAR];
char recv_name[MAX_CHAR];
char mes[MAX_CHAR * 3];
}DATA;
typedef struct file
{
int size;
char mes[MAX_FILE];
}FIle;
typedef struct _pack
{
int type;
DATA data;
FIle file;
FRI_INFO fri_info;
GROUP_INFO grp_info;
RECORD_INFO rec_info[55];
}PACK;
客户端
void send_pack(int type, char *send_name, char *recv_name, char *mes)
{
PACK pack_send;
memset(&pack_send, 0, sizeof(PACK));
pack_send.type = type;
pack_send.data.recv_fd = confd;
strcpy(pack_send.data.send_name, send_name);
strcpy(pack_send.data.recv_name, recv_name);
strcpy(pack_send.data.mes, mes);
if(send(confd, &pack_send, sizeof(PACK), 0) < 0)
my_err("send",__LINE__);
}
服务端
void send_more(int fd, int type, PACK *recv_pack, char *mes)
{
PACK pack_send;
char temp[MAX_CHAR];
memcpy(&pack_send, recv_pack, sizeof(PACK));
strcpy(temp,pack_send.data.recv_name);
pack_send.type = type;
strcpy(pack_send.data.recv_name, pack_send.data.send_name);
strcpy(pack_send.data.send_name, temp);
strcpy(pack_send.data.mes, mes);
pack_send.data.recv_fd = pack_send.data.send_fd;
pack_send.data.send_fd = fd;
if(send(fd, &pack_send, sizeof(PACK), 0) < 0)
my_err("send", __LINE__);
}
void send_pack(int fd, PACK *recv_pack, char *ch)
{
PACK pack_send;
memcpy(&pack_send, recv_pack, sizeof(PACK));
printf("%s\t%s\n", pack_send.data.recv_name, pack_send.data.send_name);
strcpy(pack_send.data.recv_name, pack_send.data.send_name);
strcpy(pack_send.data.send_name, "server");
strcpy(pack_send.data.mes, ch);
pack_send.data.recv_fd = pack_send.data.send_fd;
pack_send.data.send_fd = fd;
if(send(fd, &pack_send, sizeof(PACK), 0) < 0)
my_err("send", __LINE__);
}
2.epoll(多路复用IO)
(1).epoll_create()
创建一个epoll句柄,参数size用来告诉内核监听的文件描述符个数,跟内存大小有关
#include <sys/epoll.h>
int epoll_create(int size)
size:告诉内核监听的数目
(2).epoll_ctl()
控制某个epoll监控的文件描述符上的事件:注册、修改、删除。
#include <sys/epoll.h>
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)
epfd:为epoll_creat的句柄
op:表示动作,用3个宏来表示:
EPOLL_CTL_ADD(注册新的fd到epfd),
EPOLL_CTL_MOD(修改已经注册的fd的监听事件),
EPOLL_CTL_DEL(从epfd删除一个fd);
event:告诉内核需要监听的事件 struct
epoll_event
{
__uint32_t events; /* Epoll events */
epoll_data_t data; /* User data variable */
};
EPOLLIN :表示对应的文件描述符可以读(包括对端SOCKET正常关闭)
EPOLLOUT:表示对应的文件描述符可以写
(3).epoll_wait()
等待所监控文件描述符上有事件的产生
#include <sys/epoll.h>
int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout)
events:用来从内核得到事件的集合,
maxevents:告之内核这个events有多大,这个maxevents的值不能大于创建epoll_create()时的size,
timeout:是超时时间
-1:阻塞
0:立即返回,非阻塞
>0:指定微秒
返回值:成功返回有多少文件描述符就绪,时间到时返回0,出错返回-1
3.正则表达式
用于退出聊天。
4.pthread_cond_wait:
pthread _mutex_lock(&mutex)
while或if(线程执行的条件是否成立)
pthread_cond_wait(&cond, &mutex);
线程执行
pthread_mutex_unlock(&mutex);
三、源码
1.服务器端
#include "wrap.h"
#include "chat.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <ctype.h>
#include <mysql/mysql.h>
#include <sys/epoll.h>
#include <error.h>
#include <unistd.h>
#include <sys/stat.h>
#define SERV_PORT 8000
#define MAX_EVENTS 1000
#define OFFLINE 0
#define ONLINE 1
#define ONE_CHAT 2
#define MANY_CHAT 3
#define FRIEND 1
#define FRI_BLK 2
#define GRP 3
#define GRP_OWN 4
#define GRP_ADM 5
#define EXIT -1
#define REGISTE 1
#define LOGIN 2
#define CHECK_FRI 3
#define GET_FRI_STA 4
#define ADD_FRI 5
#define DEL_FRI 6
#define SHI_FRI 7
#define CRE_GRP 8
#define ADD_GRP 9
#define OUT_GRP 10
#define DEL_GRP 11
#define SET_GRP_ADM 12
#define KICK_GRP 13
#define CHECK_GRP 14
#define CHECK_MEM_GRP 15
#define CHAT_ONE 16
#define CHAT_MANY 17
#define CHECK_MES_FRI 18
#define CHECK_MES_GRP 19
#define RECV_FILE 20
#define SEND_FILE 21
User *U_read(); //读取用户信息表
Relation *R_read(); //读取关系表
Recordinfo *RC_read(); //读取消息记录
void Insert(User *pNew); //注册
void Insert_R(Relation *pNew);
void Insert_RC(Recordinfo *pNew);
void Delete_R(Relation *pNew);
void DeleteLink();
void DeleteLink_R();
void DeleteLink_RC();
void *Menu(void *recv_pack_t);
void Exit(PACK *recv_pack);
void registe(PACK *recv_pack); //注册
void login(PACK *recv_pack); //登陆
void check_fri(PACK *recv_pack); //查看好友列表
void get_fri_sta(PACK *recv_pack); //获取好友状态
void add_fri(PACK *recv_pack); //添加好友
void del_fri(PACK *recv_pack); //删除好友
void shi_fri(PACK *recv_pack); //屏蔽好友
void cre_grp(PACK *recv_pack);
void add_grp(PACK *recv_pack);
void out_grp(PACK *recv_pack);
void del_grp(PACK *recv_pack);
void set_grp_adm(PACK *recv_pack); //设置管理员
void kick_grp(PACK *recv_pack); //踢人
void check_grp(PACK *recv_pack); //查看群列表
void check_mem_grp(PACK *recv_pack);//查看群中成员
void chat_one(PACK *recv_pack); //私聊
void chat_many(PACK *recv_pack); //群聊
void recv_file(PACK *recv_pack); //接收文件
void send_file(PACK *recv_pack); //发送文件
void check_mes_fri(PACK *recv_pack);//查看与好友聊天记录
void check_mes_grp(PACK *recv_pack);//查看群组聊天记录
void send_more(int fd, int flag, PACK *recv_pack, char *mes);
void send_pack(int fd, PACK *recv_pack, char *ch);
MYSQL mysql;
User *pHead = NULL;
Relation *pStart = NULL;
Recordinfo *pRec = NULL;
PACK Mex_Box[100];
int sign;
int count;
int main(void) {
struct sockaddr_in serveraddr,clientaddr;
int sockfd,addrlen,confd;
char ipstr[128];
int epfd;
struct epoll_event ev,events[MAX_EVENTS];
int nready;
int i=0;
int ret;
PACK recv_t;
PACK *recv_pack;
pthread_t pid;
addrlen = sizeof(clientaddr);
if(mysql_init(&mysql)==NULL){
my_err("mysql_init",__LINE__);
return -1;
}
if(mysql_real_connect(&mysql,"127.0.0.1","root","123456","chatroom",0,NULL,0)==NULL){
my_err("mysql_real_connect",__LINE__);
return -1;
}
printf("Loading...\n");
sockfd = Socket(AF_INET,SOCK_STREAM,0);
bzero(&serveraddr,sizeof(serveraddr));
serveraddr.sin_family = AF_INET;
serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
serveraddr.sin_port = htons(SERV_PORT);
Bind(sockfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr));
Listen(sockfd,128);
epfd=epoll_create(MAX_EVENTS);
ev.data.fd=sockfd;
ev.events=EPOLLIN ;
epoll_ctl(epfd,EPOLL_CTL_ADD,sockfd,&ev);
sleep(1);
printf("服务器启动成功!\n");
//读数据
pHead=U_read();
pStart=R_read();
pRec=RC_read();
User *t=pHead;
while(1){
nready = epoll_wait(epfd, events, MAX_EVENTS, 1000); //等待事件到来
for(i = 0; i < nready; i++){
if(events[i].data.fd == sockfd){
confd = Accept(sockfd, (struct sockaddr *)&clientaddr, &addrlen);
printf("Connected client IP: %s, fd: %d\n",inet_ntoa(clientaddr.sin_addr), confd);
ev.data.fd = confd; //设置与要处理事件相关的文件描述符
ev.events = EPOLLIN ; //设置要处理的事件类型
epoll_ctl(epfd, EPOLL_CTL_ADD, confd, &ev); //注册epoll事件
continue;
}
else if(events[i].events & EPOLLIN){
memset(&recv_t, 0, sizeof(PACK));
ret=recv(events[i].data.fd, &recv_t, sizeof(PACK), MSG_WAITALL);
recv_t.data.send_fd=events[i].data.fd;
if (ret < 0) {
Close(events[i].data.fd);
perror("recv");
continue;
}
else if(ret==0) {
ev.data.fd = events[i].data.fd;
while(t){
if(t->fd == ev.data.fd){
t->statu_s = OFFLINE;
break;
}
t = t->next;
}
printf("OFFLINE(fd): %d\n",ev.data.fd);
epoll_ctl(epfd, EPOLL_CTL_DEL, events[i].data.fd, &ev);
Close(events[i].data.fd);
continue;
}
printf("------------------\n");
printf("type : %d\n", recv_t.type);
printf("send_name : %s\n", recv_t.data.send_name);
printf("recv_name : %s\n",recv_t.data.recv_name);
printf("mes : %s\n", recv_t.data.mes);
printf("------------------\n\n");
recv_t.data.recv_fd = events[i].data.fd;
recv_pack = (PACK*)malloc(sizeof(PACK));
memcpy(recv_pack, &recv_t, sizeof(PACK));
Menu((void*)recv_pack);
}
}
}
Close(epfd);
Close(sockfd);
free(recv_pack);
DeleteLink();
DeleteLink_R();
DeleteLink_RC();
return 0;
}
//读取用户信息表
User *U_read()
{
MYSQL_RES *res = NULL;
MYSQL_ROW row;
char query[1000];
User *pEnd, *pNew;
sprintf(query, "select * from user_data");
mysql_real_query(&mysql, query, strlen(query));
res = mysql_store_result(&mysql);
while(row = mysql_fetch_row(res)){
pNew = (User *)malloc(sizeof(User));
strcpy(pNew->name, row[0]);
strcpy(pNew->passwd, row[1]);
pNew->statu_s = OFFLINE;
pNew->next = NULL;
if(pHead == NULL)
pHead = pNew;
else
pEnd->next = pNew;
pEnd = pNew;
}
return pHead;
}
//读取关系表
Relation *R_read()
{
MYSQL_RES *res = NULL;
MYSQL_ROW row;
char query[1000];
Relation *pEnd, *pNew;
sprintf(query, "select * from friends");
mysql_real_query(&mysql, query, strlen(query));
res = mysql_store_result(&mysql);
while(row = mysql_fetch_row(res)){
pNew = (Relation *)malloc(sizeof(Relation));
strcpy(pNew->name1, row[0]);
strcpy(pNew->name2, row[1]);
pNew->statu_s = row[2][0] - '0';
pNew->next = NULL;
if(pStart == NULL)
pStart = pNew;
else
pEnd->next = pNew;
pEnd = pNew;
}
return pStart;
}
//读取消息记录
Recordinfo *RC_read()
{
MYSQL_RES *res = NULL;
MYSQL_ROW row;
char query[1000];
Recordinfo *pEnd, *pNew;
sprintf(query, "select * from records");
mysql_real_query(&mysql, query, strlen(query));
res = mysql_store_result(&mysql);
while(row = mysql_fetch_row(res)){
pNew = (Recordinfo *)malloc(sizeof(Recordinfo));
strcpy(pNew->name1, row[0]);
strcpy(pNew->name2, row[1]);
strcpy(pNew->message, row[2]);
pNew->next = NULL;
if(pRec == NULL)
pRec = pNew;
else
pEnd->next = pNew;
pEnd = pNew;
}
return pRec;
}
//处理函数
void *Menu(void *recv_pack_t)
{
PACK *recv_pack;
recv_pack = (PACK *)recv_pack_t;
switch(recv_pack->type)
{
case EXIT:
Exit(recv_pack);
break;
case REGISTE:
registe(recv_pack);
break;
case LOGIN:
login(recv_pack);
break;
case CHECK_FRI:
check_fri(recv_pack);
break;
case GET_FRI_STA:
get_fri_sta(recv_pack);
break;
case ADD_FRI:
add_fri(recv_pack);
break;
case DEL_FRI:
del_fri(recv_pack);
break;
case SHI_FRI:
shi_fri(recv_pack);
break;
case CRE_GRP:
cre_grp(recv_pack);
break;
case ADD_GRP:
add_grp(recv_pack);
break;
case OUT_GRP:
out_grp(recv_pack);
break;
case DEL_GRP:
del_grp(recv_pack);
break;
case SET_GRP_ADM:
set_grp_adm(recv_pack);
break;
case KICK_GRP:
kick_grp(recv_pack);
break;
case CHECK_GRP:
check_grp(recv_pack);
break;
case CHECK_MEM_GRP:
check_mem_grp(recv_pack);
break;
case CHAT_ONE:
chat_one(recv_pack);
break;
case CHAT_MANY:
chat_many(recv_pack);
break;
case CHECK_MES_FRI:
check_mes_fri(recv_pack);
break;
case CHECK_MES_GRP:
check_mes_grp(recv_pack);
break;
case RECV_FILE:
recv_file(recv_pack);
break;
case SEND_FILE:
send_file(recv_pack);
break;
default:
break;
}
}
//退出
void Exit(PACK *recv_pack)
{
User *t = pHead;
while(t){
if(strcmp(t->name, recv_pack->data.send_name) == 0){
t->statu_s = OFFLINE;
break;
}
t = t->next;
}
Close(recv_pack->data.send_fd);
}
//注册
void registe(PACK *recv_pack)
{
char query[1000];
int a;
char ch[5];
int fd;
fd = recv_pack->data.send_fd;
User *t = pHead;
int flag = 0;
User *pNew = (User *)malloc(sizeof(User));
while(t){
if(strcmp(t->name, recv_pack->data.send_name) == 0){
flag = 1;
break;
}
t = t->next;
}
//添加到数据库中并发送信息给客户端
if(flag == 0){
strcpy(pNew->name, recv_pack->data.send_name);
strcpy(pNew->passwd, recv_pack->data.mes);
pNew->statu_s = OFFLINE;
Insert(pNew);
memset(query, 0, strlen(query));
sprintf(query, "insert into user_data values('%s', '%s')", recv_pack->data.send_name, recv_pack->data.mes);
mysql_real_query(&mysql, query, strlen(query));
ch[0] = '1';
}
else//重名
ch[0] = '0';
ch[1] = '\0';
send_pack(fd, recv_pack, ch);
}
//注册——加入链表
void Insert(User *pNew)
{
User *t = pHead;
if(t==NULL){
t=pNew;
pNew->next = NULL;
}
else{
while(t && t->next != NULL)
t = t->next;
t->next = pNew;
pNew->next = NULL;
}
}
//登陆
void login(PACK *recv_pack)
{
char ch[5];
int fd = recv_pack->data.send_fd;
int i;
User *t = pHead;
int flag = 0;
while(t)
{
if(strcmp(t->name, recv_pack->data.send_name) == 0 && strcmp(t->passwd, recv_pack->data.mes) == 0){
flag = 1;
break;
}
t = t->next;
}
if(flag == 0)//不存在
ch[0] = '0';
else{
if(t->statu_s == OFFLINE){
ch[0] = '1';
t->statu_s = ONLINE;
t->fd = recv_pack->data.send_fd;
}
else //在线
ch[0] = '2';
}
ch[1] = '\0';
send_pack(fd, recv_pack, ch);
for(i = 0; i < sign; i++)
{
//私聊
if((ch[0] == '1') && strcmp(recv_pack->data.send_name, Mex_Box[i].data.recv_name) == 0 && (Mex_Box[i].type == CHAT_ONE)){
send_more(fd, CHAT_ONE, &Mex_Box[i], "1");
count++;
}
//群聊
if((ch[0] == '1') && strcmp(recv_pack->data.send_name, Mex_Box[i].data.send_name) == 0 && (Mex_Box[i].type == CHAT_MANY)){
send_more(fd, CHAT_MANY, &Mex_Box[i], "2");
count++;
}
//加好友
if((ch[0] == '1') && strcmp(recv_pack->data.send_name, Mex_Box[i].data.recv_name) == 0 && (Mex_Box[i].type == ADD_FRI)){
Menu((void *)&Mex_Box[i]);
count++;
}
//加群
if((ch[0] == '1') && strcmp(recv_pack->data.send_name, Mex_Box[i].data.recv_name) == 0 && (Mex_Box[i].type == ADD_GRP)){
Menu((void *)&Mex_Box[i]);
count++;
}
//设置管理员/踢人
if((ch[0] == '1') && strcmp(recv_pack->data.send_name, Mex_Box[i].data.mes) == 0){
send_more(fd, Mex_Box[i].type, &Mex_Box[i], "6");
count++;
}
//发文件
if((ch[0] == '1') && strcmp(recv_pack->data.send_name, Mex_Box[i].data.recv_name) == 0 && strcmp(Mex_Box[i].data.mes, "success") == 0)
{
send_file(&Mex_Box[i]);
count++;
}
}
if(count == sign)
sign = count = 0;
}
//查看好友列表
void check_fri(PACK *recv_pack)
{
int flag = CHECK_FRI;
MYSQL_RES *res = NULL;
MYSQL_ROW row;
char query[700];
int rows;
int i;
int fd = recv_pack->data.send_fd;
int statu_s;
memset(query, 0, strlen(query));
sprintf(query, "select * from friends where name1='%s' or name2='%s'", recv_pack->data.send_name, recv_pack->data.send_name);
mysql_real_query(&mysql, query, strlen(query));
res = mysql_store_result(&mysql);
rows = mysql_num_rows(res); //行数
if(rows == 0)
recv_pack->fri_info.friends_num = 0;
else{
i = 0;
while(row = mysql_fetch_row(res)){
if(strcmp(row[0], recv_pack->data.send_name) == 0){
strcpy(recv_pack->fri_info.friends[i], row[1]);
statu_s = row[2][0] - '0';
recv_pack->fri_info.friends_status[i] = statu_s;
i++;
}
else if(strcmp(row[1], recv_pack->data.send_name) == 0){
strcpy(recv_pack->fri_info.friends[i], row[0]);
statu_s = row[2][0] - '0';
recv_pack->fri_info.friends_status[i] = statu_s;
i++;
}
}
recv_pack->fri_info.friends_num = i;
}
send_more(fd, flag, recv_pack, "");
}
//获取好友状态
void get_fri_sta(PACK *recv_pack)
{
int flag = GET_FRI_STA;
char ch[5];
int fd = recv_pack->data.send_fd;
User *t = pHead;
int flag2 = 0;
while(t){
if(strcmp(t->name, recv_pack->data.send_name) == 0){
flag2 = 1;
break;
}
t = t->next;
}
if(t->statu_s == OFFLINE)
ch[0] = '0';
else
ch[0] = '1';
ch[1] = '\0';
send_more(fd, flag, recv_pack, ch);
}
//添加好友
void add_fri(PACK *recv_pack)
{
char query[1700];
int flag = ADD_FRI;
int fd = recv_pack->data.send_fd;
char ch[5];
char temp[MAX_CHAR];
User *t = pHead;
int flag2 = 0;
Relation *q = pStart;
int flag3 = 0;
Relation *pNew = (Relation *)malloc(sizeof(Relation));
while(q){
if((strcmp(q->name1, recv_pack->data.recv_name) == 0 && strcmp(q->name2, recv_pack->data.send_name) == 0) || (strcmp(q->name1, recv_pack->data.send_name) == 0 && strcmp(q->name2, recv_pack->data.recv_name) == 0)){
flag3 = 1;
break;
}
q = q->next;
}
if(flag3 == 1){
//已经是好友
ch[0] = '4';
send_more(fd, flag, recv_pack, ch);
free(pNew);
pNew = NULL;
return;
}
else{
while(t){
if(strcmp(t->name, recv_pack->data.recv_name) == 0){
flag2 = 1;
break;
}
t = t->next;
}
//该用户不存在
if(flag2 == 0){
ch[0] = '3';
send_more(fd, flag, recv_pack, ch);
free(pNew);
pNew = NULL;
return;
}
else{
if(t->statu_s != OFFLINE){
fd = t->fd;
if(recv_pack->data.mes[0] == '0')
ch[0] = '0';
else if(recv_pack->data.mes[0] == 'y'){
ch[0] = '1';
strcpy(pNew->name1, recv_pack->data.recv_name);
strcpy(pNew->name2, recv_pack->data.send_name);
pNew->statu_s = FRIEND;
printf("add----\n");
Insert_R(pNew);
memset(query, 0, strlen(query));
sprintf(query, "insert into friends values('%s', '%s', %d)", recv_pack->data.recv_name, recv_pack->data.send_name, FRIEND);
mysql_real_query(&mysql, query, strlen(query));
}
else if(recv_pack->data.mes[0] == 'n')
ch[0] = '2';
strcpy(temp,recv_pack->data.recv_name);
strcpy(recv_pack->data.recv_name, recv_pack->data.send_name);
strcpy(recv_pack->data.send_name, temp);
send_more(fd, flag, recv_pack, ch);
}
else if(t->statu_s == OFFLINE)
memcpy(&Mex_Box[sign++], recv_pack, sizeof(PACK)); //登陆
}
}
}
//加入关系表
void Insert_R(Relation *pNew)
{
Relation *t = pStart;
if(t==NULL){
t=pNew;
pNew->next = NULL;
}
else{
while(t && t->next != NULL)
t = t->next;
t->next = pNew;
pNew->next = NULL;
}
}
//删除好友
void del_fri(PACK *recv_pack)
{
char query[1700];
int flag = DEL_FRI;
char ch[5];
int fd = recv_pack->data.send_fd;
Relation *q = pStart;
int flag3 = 0;
while(q){
if((strcmp(q->name1, recv_pack->data.mes) == 0 && strcmp(q->name2, recv_pack->data.send_name) == 0) || (strcmp(q->name1, recv_pack->data.send_name) == 0 && strcmp(q->name2, recv_pack->data.mes) == 0)){
flag3 = 1;
break;
}
q = q->next;
}
if(flag3 == 0)//不是好友
ch[0] = '0';
else{
Delete_R(q);
memset(query, 0, strlen(query));
sprintf(query, "delete from friends where (name1='%s' and name2='%s') or (name1='%s' and name2='%s')", recv_pack->data.send_name, recv_pack->data.mes, recv_pack->data.mes, recv_pack->data.send_name);
mysql_real_query(&mysql, query, strlen(query));
ch[0] = '1';
}
send_more(fd, flag, recv_pack, ch);
}
//删除出关系表
void Delete_R(Relation *pNew)
{
Relation *t = pStart;
Relation *ptr;
while(t){
if((strcmp(t->name1, pNew->name1) == 0 && strcmp(t->name2, pNew->name2) == 0) || (strcmp(t->name1, pNew->name2) == 0 && strcmp(t->name2, pNew->name2) == 0)){
if(pStart == t){
pStart = t->next;
free(t);
return;
}
ptr->next = t->next;
free(t);
return;
}
ptr = t;
t = t->next;
}
}
//屏蔽好友
void shi_fri(PACK *recv_pack)
{
char query[1700];
int flag = SHI_FRI;
char ch[5];
int fd = recv_pack->data.send_fd;
Relation *q = pStart;
int flag3 = 0;
while(q){
if((strcmp(q->name1, recv_pack->data.mes) == 0 && strcmp(q->name2, recv_pack->data.send_name) == 0) || (strcmp(q->name1, recv_pack->data.send_name) == 0 && strcmp(q->name2, recv_pack->data.mes) == 0)){
flag3 = 1;
break;
}
q = q->next;
}
if(flag3 == 0)
ch[0] = '0';
else{
q->statu_s = FRI_BLK;
memset(query, 0, strlen(query));
sprintf(query, "update friends set status=%d where (name1='%s' and name2='%s') or (name1='%s' and name2='%s')", FRI_BLK, recv_pack->data.send_name, recv_pack->data.mes, recv_pack->data.mes, recv_pack->data.send_name);
mysql_real_query(&mysql, query, strlen(query));
ch[0] = '1';
}
send_more(fd, flag, recv_pack, ch);
}
//创建群
void cre_grp(PACK *recv_pack)
{
char query[1000];
int flag = CRE_GRP;
int fd = recv_pack->data.send_fd;
char ch[5];
Relation *q = pStart;
int flag3 = 0;
Relation *pNew = (Relation *)malloc(sizeof(Relation));
while(q){
if(strcmp(q->name2, recv_pack->data.mes) == 0){
flag3 = 1;
break;
}
q = q->next;
}
if(flag3 == 1)
ch[0] = '0';
else{
ch[0] = '1';
strcpy(pNew->name1, recv_pack->data.send_name);
strcpy(pNew->name2, recv_pack->data.mes);
pNew->statu_s = GRP_OWN;
Insert_R(pNew);
memset(query, 0, strlen(query));
sprintf(query, "insert into friends values('%s', '%s', %d)", recv_pack->data.send_name, recv_pack->data.mes, GRP_OWN);
mysql_real_query(&mysql, query, strlen(query));
}
send_more(fd, flag, recv_pack, ch);
}
//加群
void add_grp(PACK *recv_pack)
{
char query[15000];
int flag = ADD_GRP;
int fd = recv_pack->data.send_fd;
char ch[5];
User *t = pHead;
Relation *q = pStart;
int flag2 = 0;
Relation *pNew = (Relation *)malloc(sizeof(Relation));
if(strcmp(recv_pack->data.mes, "y") == 0){
while(t){
if(strcmp(t->name, recv_pack->data.recv_name) == 0){
fd = t->fd;
break;
}
t = t->next;
}
ch[0] = '2';
printf("%s\n", recv_pack->file.mes);
strcpy(pNew->name1, recv_pack->data.recv_name);
strcpy(pNew->name2, recv_pack->data.send_name);
pNew->statu_s = GRP;
Insert_R(pNew);
memset(query, 0, strlen(query));
sprintf(query, "insert into friends values('%s', '%s', %d)", recv_pack->data.recv_name, recv_pack->data.send_name, GRP);
mysql_real_query(&mysql, query, strlen(query));
send_more(fd, flag, recv_pack, ch);
return;
}
else if(strcmp(recv_pack->data.mes, "n") == 0){
while(t){
if(strcmp(t->name, recv_pack->data.recv_name) == 0){
fd = t->fd;
break;
}
t = t->next;
}
ch[0] = '3';
send_more(fd, flag, recv_pack, ch);
return;
}
while(q){
if(strcmp(q->name2, recv_pack->data.mes) == 0 && (q->statu_s == GRP_OWN)){
flag2 = 1;
strcpy(recv_pack->data.recv_name, q->name1);
break;
}
q = q->next;
}
if(flag2 == 0){
//该群不存在
ch[0] = '0';
send_more(fd, flag, recv_pack, ch);
return;
}
else if(flag2 == 1){
t = pHead;
while(t){
if(strcmp(recv_pack->data.recv_name, t->name) == 0 && (t->statu_s != OFFLINE)){
ch[0] = '1';
fd = t->fd;
strcpy(recv_pack->file.mes, recv_pack->data.mes);
send_more(fd, flag, recv_pack, ch);
return;
}
else if(strcmp(recv_pack->data.recv_name, t->name) == 0 && (t->statu_s == OFFLINE)){
memcpy(&Mex_Box[sign++], recv_pack, sizeof(PACK));
break;
}
t = t->next;
}
}
}
//退群
void out_grp(PACK *recv_pack)
{
char query[1000];
int flag = OUT_GRP;
char ch[5];
int fd = recv_pack->data.send_fd;
Relation *q = pStart;
int flag_3 = 0;
while(q){
if(strcmp(q->name2, recv_pack->data.mes) == 0){
flag_3 = 1;
break;
}
q = q->next;
}
if(flag_3 == 0)
ch[0] = '0';
else{
ch[0] = '1';
Delete_R(q);
memset(query, 0, strlen(query));
sprintf(query, "delete from friends where name1='%s' and name2='%s'", recv_pack->data.send_name, recv_pack->data.mes);
mysql_real_query(&mysql, query, strlen(query));
}
send_more(fd, flag, recv_pack, ch);
}
//解散群
void del_grp(PACK *recv_pack)
{
char query[1000];
int flag = DEL_GRP;
char ch[5];
int fd = recv_pack->data.send_fd;
Relation *q = pStart;
int flag3 = 0;
int flag2 = 0;
while(q){
if(strcmp(q->name2, recv_pack->data.mes) == 0){
flag2 = 1;
break;
}
q = q->next;
}
q = pStart;
while(q){
if(strcmp(q->name1, recv_pack->data.send_name) == 0 && strcmp(q->name2, recv_pack->data.mes) == 0 && (q->statu_s == GRP_OWN)){
flag3 = 1;
break;
}
q = q->next;
}
if(flag2 == 0)
ch[0] = '0';
else if(flag3 == 1 && flag2 == 1){
ch[0] = '1';
q = pStart;
while(q){
if(strcmp(q->name2, recv_pack->data.mes) == 0)
Delete_R(q);
q = q->next;
}
memset(query, 0, strlen(query));
sprintf(query, "delete from friends where name2='%s'", recv_pack->data.mes);
mysql_real_query(&mysql, query, strlen(query));
}
else if(flag3 == 0 && flag2 == 1)
ch[0] = '2';
send_more(fd, flag, recv_pack, ch);
}
//设置管理员
void set_grp_adm(PACK *recv_pack)
{
char query[1000];
int flag = SET_GRP_ADM;
char ch[5];
int fd = recv_pack->data.send_fd;
int fd2;
User *t = pHead;
Relation *q = pStart;
int flag3 = 0;
int flag2 = 0;
int flag1 = 0;
while(q){
if(strcmp(q->name2, recv_pack->data.recv_name) == 0){
flag2 = 1;
break;
}
q = q->next;
}
q = pStart;
while(q){
if(strcmp(q->name2, recv_pack->data.recv_name) == 0 && strcmp(q->name1, recv_pack->data.mes) == 0){
flag1 = 1;
break;
}
q = q->next;
}
q = pStart;
while(q){
if(strcmp(q->name1, recv_pack->data.send_name) == 0 && strcmp(q->name2, recv_pack->data.recv_name) == 0 && q->statu_s == GRP_OWN){
flag3 = 1;
break;
}
q = q->next;
}
if(flag3 == 1 && flag2 == 1 && flag1 == 1){
ch[0] = '1';
q = pStart;
while(q){
if(strcmp(q->name1, recv_pack->data.mes) == 0 && strcmp(q->name2, recv_pack->data.recv_name) == 0){
q->statu_s = GRP_ADM;
break;
}
q = q->next;
}
while(t){
if(strcmp(t->name, recv_pack->data.mes) == 0 && (t->statu_s != OFFLINE)){
fd2 = t->fd;
send_more(fd2, flag, recv_pack, "6");
}
else if(strcmp(t->name, recv_pack->data.mes) == 0 && (t->statu_s == OFFLINE))
memcpy(&Mex_Box[sign++], recv_pack, sizeof(PACK));
t = t->next;
}
memset(query, 0, strlen(query));
sprintf(query, "update friends set status=%d where name1='%s' and name2='%s'", GRP_ADM, recv_pack->data.mes, recv_pack->data.recv_name);
mysql_real_query(&mysql, query, strlen(query));
}
else if(flag3 == 0 && flag2 == 1 && flag1 == 1)
ch[0] = '2';
else if(flag1 == 0)
ch[0] = '3';
else if(flag2 == 0)
ch[0] = '0';
send_more(fd, flag, recv_pack, ch);
}
//踢人
void kick_grp(PACK *recv_pack)
{
char query[1000];
int flag = KICK_GRP;
char ch[5];
int fd = recv_pack->data.send_fd;
int fd2;
User *t = pHead;
Relation *q = pStart;
int flag3 = 0;
int flag1 = 0;
int flag2 = 0;
int flag4 = 0;
while(q){
if(strcmp(q->name2, recv_pack->data.recv_name) == 0){
flag1 = 1;
break;
}
q = q->next;
}
q = pStart;
while(q){
if(strcmp(q->name2, recv_pack->data.recv_name) == 0 && strcmp(q->name1, recv_pack->data.mes) == 0){
flag2 = 1;
break;
}
q = q->next;
}
q = pStart;
while(q){
if(strcmp(q->name1, recv_pack->data.send_name) == 0 && strcmp(q->name2, recv_pack->data.recv_name) == 0 && (q->statu_s == GRP_OWN || q->statu_s == GRP_ADM)){
flag3 = 1;
break;
}
q = q->next;
}
q = pStart;
while(q){
if(strcmp(q->name1, recv_pack->data.mes) == 0 && (q->statu_s == (GRP))){
flag4 = 1;
break;
}
q = q->next;
}
if(flag3 == 1 && flag1 == 1 && flag2 == 1 && flag4 == 1){
ch[0] = '1';
Delete_R(q);
while(t){
if(strcmp(t->name, recv_pack->data.mes) == 0 && (t->statu_s != OFFLINE)){
fd2 = t->fd;
send_more(fd2, flag, recv_pack, "6");
}
else if(strcmp(t->name, recv_pack->data.mes) == 0 && (t->statu_s == OFFLINE))
memcpy(&Mex_Box[sign++], recv_pack, sizeof(PACK));
t = t->next;
}
memset(query, 0, strlen(query));
sprintf(query, "delete from friends where name1='%s' and name2='%s'", recv_pack->data.mes, recv_pack->data.recv_name);
mysql_real_query(&mysql, query, strlen(query));
}
else if(flag3 == 0 && flag1 == 1 && flag2 == 1 && flag4 == 1)
ch[0] = '2';
else if(flag4 == 0)
ch[0] = '4';
else if(flag2 == 0)
ch[0] = '3';
else if(flag1 == 0)
ch[0] = '0';
send_more(fd, flag, recv_pack, ch);
}
//查看所加群
void check_grp(PACK *recv_pack)
{
int flag = CHECK_GRP;
int fd = recv_pack->data.send_fd;
Relation *q = pStart;
int i = 0;
while(q){
if(strcmp(q->name1, recv_pack->data.send_name) == 0 && (q->statu_s == GRP || q->statu_s == GRP_OWN || q->statu_s == GRP_ADM)){
strcpy(recv_pack->grp_info.groups[i], q->name2);
i++;
}
q = q->next;
}
recv_pack->grp_info.grp_num = i;
send_more(fd, flag, recv_pack, "");
}
//查看群中成员
void check_mem_grp(PACK *recv_pack)
{
int flag = CHECK_MEM_GRP;
int fd = recv_pack->data.send_fd;
Relation *q = pStart;
int i = 0;
while(q){
if(strcmp(q->name2, recv_pack->data.mes) == 0 && (q->statu_s == GRP || q->statu_s == GRP_OWN || q->statu_s == GRP_ADM)){
strcpy(recv_pack->fri_info.friends[i], q->name1);
i++;
}
q = q->next;
}
recv_pack->fri_info.friends_num = i;
send_more(fd, flag, recv_pack, "");
}
//私聊
void chat_one(PACK *recv_pack)
{
int flag = CHAT_ONE;
char ch[5];
int fd = recv_pack->data.send_fd;
char temp[MAX_CHAR];
MYSQL_RES *res = NULL;
MYSQL_ROW row;
char query[1500];
int rows;
int i = 0;
User *t = pHead;
Relation *q = pStart;
int flag2 = 0;
int flag3 = 0;
Recordinfo *pNew = (Recordinfo *)malloc(sizeof(Recordinfo));
if(strcmp(recv_pack->data.mes, "q") == 0){
while(t){
if(strcmp(t->name, recv_pack->data.send_name) == 0){
t->statu_s = ONLINE;
t->chat[0] = '\0';
free(pNew);
pNew = NULL;
return;
}
t = t->next;
}
}
while(q){
//不是好友
if(((strcmp(q->name1,recv_pack->data.send_name) == 0 && strcmp(q->name2, recv_pack->data.recv_name) == 0) || (strcmp(q->name2,recv_pack->data.send_name) == 0 && strcmp(q->name1, recv_pack->data.recv_name) == 0)) && (q->statu_s == FRI_BLK)){
ch[0] = '3';
send_more(fd, flag, recv_pack, ch);
free(pNew);
pNew = NULL;
return;
}
q = q->next;
}
t = pHead;
while(t){
if(strcmp(t->name, recv_pack->data.recv_name) == 0){
flag2 = 1;
break;
}
t = t->next;
}
if(flag2 == 0){
//用户不存在
ch[0] = '0';
send_more(fd, flag, recv_pack, ch);
free(pNew);
pNew = NULL;
return;
}
else
{
if(recv_pack->data.mes[0] == '1'){
memset(query, 0, strlen(query));
sprintf(query, "select * from off_records where name1='%s' and name2='%s'", recv_pack->data.recv_name, recv_pack->data.send_name);
mysql_real_query(&mysql, query, strlen(query));
res = mysql_store_result(&mysql);
rows = mysql_num_rows(res);
while(row = mysql_fetch_row(res)){
strcpy(pNew->name1, row[0]);
strcpy(pNew->name2, row[1]);
strcpy(pNew->message, row[2]);
Insert_RC(pNew);
memset(query, 0, strlen(query));
sprintf(query, "insert into records values('%s', '%s', '%s')", row[0], row[1], row[2]);
mysql_real_query(&mysql, query, strlen(query));
strcpy(recv_pack->rec_info[i].name1, row[0]);
strcpy(recv_pack->rec_info[i].name2, row[1]);
strcpy(recv_pack->rec_info[i].message, row[2]);
i++;
if(i > 50)
break;
}
recv_pack->rec_info[i].message[0] = '0';
send_more(fd, flag, recv_pack, "6");
memset(query, 0, strlen(query));
sprintf(query, "delete from off_records where name1='%s' and name2='%s'", recv_pack->data.recv_name, recv_pack->data.send_name);
mysql_real_query(&mysql, query, strlen(query));
t = pHead;
while(t){
if(strcmp(t->name, recv_pack->data.send_name) == 0){
t->statu_s = ONE_CHAT;
strcpy(t->chat, recv_pack->data.recv_name);
break;
}
t = t->next;
}
t = pHead;
while(t){
if(strcmp(t->name, recv_pack->data.recv_name) == 0 && (t->statu_s != OFFLINE)){
flag3 = 1;
break;
}
t = t->next;
}
if(flag3 == 1){
ch[0] = '1';
fd = t->fd;
strcpy(temp,recv_pack->data.recv_name);
strcpy(recv_pack->data.recv_name, recv_pack->data.send_name);
strcpy(recv_pack->data.send_name, temp);
send_more(fd, flag, recv_pack, ch);
}
else{
ch[0] = '2';
send_more(fd, flag, recv_pack, ch);
memcpy(&Mex_Box[sign++], recv_pack, sizeof(PACK));
}
}
else{
t = pHead;
while(t){
if(strcmp(t->name, recv_pack->data.recv_name) == 0 && strcmp(t->chat, recv_pack->data.send_name) == 0 && (t->statu_s == ONE_CHAT)){
fd = t->fd;
strcpy(pNew->name1, recv_pack->data.send_name);
strcpy(pNew->name2, recv_pack->data.recv_name);
strcpy(pNew->message, recv_pack->data.mes);
Insert_RC(pNew);
memset(query, 0, strlen(query));
sprintf(query, "insert into records values('%s', '%s', '%s')", recv_pack->data.send_name, recv_pack->data.recv_name, recv_pack->data.mes);
mysql_real_query(&mysql, query, strlen(query));
memset(temp, 0, MAX_CHAR);
strcpy(temp,recv_pack->data.recv_name);
strcpy(recv_pack->data.recv_name, recv_pack->data.send_name);
send_more(fd, flag, recv_pack, recv_pack->data.mes);
return;
}
else if(strcmp(t->name, recv_pack->data.recv_name) == 0 && strcmp(t->chat, recv_pack->data.send_name) != 0){
memset(query, 0, strlen(query));
sprintf(query, "insert into off_records values('%s', '%s', '%s')", recv_pack->data.send_name, recv_pack->data.recv_name, recv_pack->data.mes);
mysql_real_query(&mysql, query, strlen(query));
free(pNew);
pNew = NULL;
return;
}
t = t->next;
}
}
}
}
//加入聊天记录
void Insert_RC(Recordinfo *pNew)
{
Recordinfo *p = pRec;
if(p==NULL){
p=pNew;
pNew->next = NULL;
}
else{
while(p && p->next != NULL)
p = p->next;
p->next = pNew;
pNew->next = NULL;
}
}
//群聊
void chat_many(PACK *recv_pack)
{
int flag = CHAT_MANY;
char ch[5];
int fd = recv_pack->data.send_fd;
char temp[MAX_CHAR];
MYSQL_RES *res = NULL;
MYSQL_ROW row;
char query[1500];
int rows;
PACK recv_t;
recv_t.type = flag;
int i = 0,j = 0;
User *t = pHead;
Relation *q = pStart;
int flag2 = 0;
Recordinfo *pNew = (Recordinfo *)malloc(sizeof(Recordinfo));
if(strcmp(recv_pack->data.mes, "q") == 0){
while(t){
if(strcmp(t->name, recv_pack->data.send_name) == 0){
t->statu_s = ONLINE;
free(pNew);
pNew = NULL;
return;
}
t = t->next;
}
}
while(q){
if(strcmp(q->name2, recv_pack->data.recv_name) == 0 && (q->statu_s >= GRP)){
flag2 = 1;
break;
}
q = q->next;
}
if(flag2 == 0){
//不是群成员
ch[0] = '0';
send_more(fd, flag, recv_pack, ch);
free(pNew);
pNew = NULL;
return;
}
else{
if(strcmp(recv_pack->data.mes, "1") == 0){
//加入群聊
memset(query, 0, strlen(query));
sprintf(query, "select * from records where name2='%s'", recv_pack->data.recv_name);
mysql_real_query(&mysql, query, strlen(query));
res = mysql_store_result(&mysql);
rows = mysql_num_rows(res);
if(rows != 0){
while(row = mysql_fetch_row(res)){
if(rows <= 30){
strcpy(recv_pack->rec_info[i].name1, row[0]);
strcpy(recv_pack->rec_info[i].name2, row[1]);
strcpy(recv_pack->rec_info[i].message, row[2]);
}
else{
if(rows - i <= 30){
strcpy(recv_pack->rec_info[j].name1, row[0]);
strcpy(recv_pack->rec_info[j].name2, row[1]);
strcpy(recv_pack->rec_info[j].message, row[2]);
j++;
}
}
i++;
}
}
if(rows <= 30)
recv_pack->rec_info[i].message[0] = '0';
else
recv_pack->rec_info[j].message[0] = '0';
send_more(fd, flag, recv_pack, "6");
free(pNew);
pNew = NULL;
t = pHead;
while(t){
if(strcmp(t->name, recv_pack->data.send_name) == 0){
t->statu_s = MANY_CHAT;
strcpy(t->chat, recv_pack->data.recv_name);
break;
}
t = t->next;
}
q = pStart;
while(q){
if(strcmp(q->name1, recv_pack->data.send_name) != 0 && strcmp(q->name2, recv_pack->data.recv_name) == 0 && (q->statu_s >= GRP)){
t = pHead;
while(t){
if(strcmp(q->name1, t->name) == 0 && (t->statu_s != OFFLINE)){
ch[0] = '1';
fd = t->fd;
send_more(fd, flag, recv_pack, ch);
break;
}
else if(strcmp(q->name1, t->name) == 0 && (t->statu_s == OFFLINE)){
strcpy(recv_t.data.send_name, t->name);
strcpy(recv_t.data.recv_name, recv_pack->data.recv_name);
memcpy(&Mex_Box[sign++], &recv_t, sizeof(PACK));
break;
}
t = t->next;
}
}
q = q->next;
}
}
else{
strcpy(pNew->name1, recv_pack->data.send_name);
strcpy(pNew->name2, recv_pack->data.recv_name);
strcpy(pNew->message, recv_pack->data.mes);
Insert_RC(pNew);
memset(query, 0, strlen(query));
sprintf(query, "insert into records values('%s', '%s', '%s')", recv_pack->data.send_name, recv_pack->data.recv_name, recv_pack->data.mes);
mysql_real_query(&mysql, query, strlen(query));
q = pStart;
while(q){
if(strcmp(q->name2, recv_pack->data.recv_name) == 0 && (q->statu_s >= GRP)){
t = pHead;
while(t){
if(strcmp(q->name1, t->name) == 0 && strcmp(t->chat, recv_pack->data.recv_name) == 0 && (t->statu_s == MANY_CHAT)){
fd = t->fd;
bzero(temp, MAX_CHAR);
strcpy(temp,recv_pack->data.recv_name);
strcpy(recv_pack->data.recv_name, recv_pack->data.send_name);
send_more(fd, flag, recv_pack, recv_pack->data.mes);
strcpy(recv_pack->data.send_name, temp);
bzero(temp, MAX_CHAR);
strcpy(temp,recv_pack->data.recv_name);
strcpy(recv_pack->data.recv_name, recv_pack->data.send_name);
strcpy(recv_pack->data.send_name, temp);
break;
}
t = t->next;
}
}
q = q->next;
}
}
}
}
//查看与好友聊天记录
void check_mes_fri(PACK *recv_pack)
{
int i = 0;
int flag = CHECK_MES_FRI;
char ch[5];
int fd = recv_pack->data.send_fd;
Relation *q = pStart;
Recordinfo *p = pRec;
int flag2 = 0;
while(q){
if(((strcmp(q->name1, recv_pack->data.send_name) == 0 && strcmp(q->name2, recv_pack->data.mes) == 0) || (strcmp(q->name2, recv_pack->data.send_name) == 0 && strcmp(q->name1, recv_pack->data.mes) == 0)) && (q->statu_s == FRIEND)) {
flag2 = 1;
break;
}
q = q->next;
}
if(flag2 == 0)
ch[0] = '0';
else{
ch[0] = '1';
while(p){
if((strcmp(p->name1, recv_pack->data.send_name) == 0 && strcmp(p->name2, recv_pack->data.mes) == 0) || (strcmp(p->name2, recv_pack->data.send_name) == 0 && strcmp(p->name1, recv_pack->data.mes) == 0)){
strcpy(recv_pack->rec_info[i].name1, p->name1);
strcpy(recv_pack->rec_info[i].name2, p->name2);
strcpy(recv_pack->rec_info[i].message, p->message);
i++;
if(i > 50)
break;
}
p = p->next;
}
}
recv_pack->rec_info[i].message[0] = '0';
send_more(fd, flag, recv_pack, ch);
}
//查看群组聊天记录
void check_mes_grp(PACK *recv_pack)
{
int i = 0;
int flag = CHECK_MES_GRP;
char ch[5];
int fd = recv_pack->data.send_fd;
Relation *q = pStart;
Recordinfo *p = pRec;
int flag2 = 0;
while(q){
if(strcmp(q->name1, recv_pack->data.send_name) == 0 && strcmp(q->name2, recv_pack->data.mes) == 0 && (q->statu_s >= GRP)){
flag2 = 1;
break;
}
q = q->next;
}
if(flag2 == 0)
ch[0] = '0';
else{
ch[0] = '1';
while(p){
if((strcmp(p->name2, recv_pack->data.mes) == 0)) {
strcpy(recv_pack->rec_info[i].name1, p->name1);
strcpy(recv_pack->rec_info[i].name2, p->name2);
strcpy(recv_pack->rec_info[i].message, p->message);
i++;
if(i > 50)
break;
}
p = p->next;
}
}
recv_pack->rec_info[i].message[0] = '0';
send_more(fd, flag, recv_pack, ch);
}
//接收文件
void recv_file(PACK *recv_pack)
{
int flag = RECV_FILE;
int fd = recv_pack->data.send_fd;
int length = 0;
int i = 0;
char mes[MAX_CHAR * 3 + 1];
char *name;
bzero(mes, MAX_CHAR * 3 + 1);
int fp;
User *t = pHead;
int flag2 = 0;
if(strcmp(recv_pack->data.mes,"send") == 0){
while(t){
if(strcmp(t->name, recv_pack->data.recv_name) == 0){
flag2 = 1;
break;
}
t = t->next;
}
if(flag2 == 1){
file.file_name[file.sign_file][0] = '_';
for(i = 0; i < strlen(recv_pack->data.send_name); i++){
if(recv_pack->data.send_name[i] == '/'){
name = strrchr(recv_pack->data.send_name, '/');
name++;
strcat(file.file_name[file.sign_file],name);
break;
}
}
if(i == strlen(recv_pack->data.send_name))
strcat(file.file_name[file.sign_file],recv_pack->data.send_name);
strcpy(file.file_send_name[file.sign_file], recv_pack->data.recv_name);
fp = creat(file.file_name[file.sign_file], S_IRWXU);
file.sign_file++;
close(fp);
send_more(fd, flag, recv_pack, "1");
}
else
send_more(fd, flag, recv_pack, "0");
}
else if(strcmp(recv_pack->data.mes, "success") == 0){
while(t){
if(strcmp(t->name, recv_pack->data.recv_name) == 0 && (t->statu_s != OFFLINE)){
flag2 = 1;
break;
}
t = t->next;
}
if(flag2 == 1)
send_file(recv_pack);
else if(flag2 == 0)
memcpy(&Mex_Box[sign++], recv_pack, sizeof(PACK));
}
else{
for(i = 0; i < file.sign_file; i++){
if(strcmp(recv_pack->data.recv_name, file.file_send_name[i]) == 0){
fp = open(file.file_name[i], O_WRONLY | O_APPEND);
break;
}
}
if(write(fp, recv_pack->file.mes, recv_pack->file.size) < 0)
my_err("write", __LINE__);
close(fp);
//send_more(fd, flag, recv_pack, "");
}
}
//发送文件
void send_file(PACK *recv_pack)
{
int flag = SEND_FILE;
int fd = recv_pack->data.send_fd;
int fd2;
int fp;
int length = 0;
PACK send_file;
send_file.type = flag;
char temp[MAX_CHAR];
User *t = pHead;
int flag_2 = 0;
int i = 0;
while(t)
{
if(strcmp(t->name, recv_pack->data.recv_name) == 0)
{
fd2 = t->fd;
break;
}
t = t->next;
}
if(strcmp(recv_pack->data.mes, "success") == 0)
{
strcpy(temp,recv_pack->data.recv_name);
strcpy(recv_pack->data.recv_name, recv_pack->data.send_name);
strcpy(recv_pack->data.send_name, temp);
send_more(fd2, flag, recv_pack, "5");
}
else if(recv_pack->data.mes[0] == 'y')
{
for(i = 0; i < file.sign_file; i++)
if(strcmp(file.file_send_name[i], recv_pack->data.send_name) == 0)
break;
send_more(fd2, flag, recv_pack, "1");
strcpy(recv_pack->data.recv_name, file.file_name[i]);
send_more(fd, flag, recv_pack, "4");
strcpy(send_file.data.send_name, recv_pack->data.recv_name);
strcpy(send_file.data.recv_name, recv_pack->data.send_name);
fp = open(file.file_name[i], O_RDONLY);
if(fp == -1)
printf("未找到文件%s!\n", file.file_name[i]);
while((length = read(fp, send_file.file.mes, MAX_FILE - 1)) > 0)
{
send_file.file.size = length;
if(send(fd, &send_file, sizeof(PACK), 0) < 0)
my_err("send",__LINE__);
bzero(send_file.file.mes, MAX_FILE);
}
printf("发送成功!\n");
send_more(fd, flag, recv_pack, "3");
send_more(fd2, flag, recv_pack, "2");
remove(file.file_name[i]);
file.file_send_name[i][0] = '\0';
close(fp);
}
else if(recv_pack->data.mes[0] == 'n')
{
send_more(fd2, flag, recv_pack, "0");
for(i = 0; i < file.sign_file; i++)
if(strcmp(file.file_send_name[i], recv_pack->data.send_name) == 0)
break;
remove(file.file_name[i]);
file.file_send_name[i][0] = '\0';
}
}
void send_more(int fd, int type, PACK *recv_pack, char *mes)
{
PACK pack_send;
char temp[MAX_CHAR];
memcpy(&pack_send, recv_pack, sizeof(PACK));
strcpy(temp,pack_send.data.recv_name);
pack_send.type = type;
strcpy(pack_send.data.recv_name, pack_send.data.send_name);
strcpy(pack_send.data.send_name, temp);
strcpy(pack_send.data.mes, mes);
pack_send.data.recv_fd = pack_send.data.send_fd;
pack_send.data.send_fd = fd;
if(send(fd, &pack_send, sizeof(PACK), 0) < 0)
my_err("send", __LINE__);
}
//发送信息
void send_pack(int fd, PACK *recv_pack, char *ch)
{
PACK pack_send;
memcpy(&pack_send, recv_pack, sizeof(PACK));
strcpy(pack_send.data.recv_name, pack_send.data.send_name);
strcpy(pack_send.data.send_name, "server");
strcpy(pack_send.data.mes, ch);
pack_send.data.recv_fd = pack_send.data.send_fd;
pack_send.data.send_fd = fd;
if(send(fd, &pack_send, sizeof(PACK), 0) < 0)
my_err("send", __LINE__);
}
//销毁链表
void DeleteLink()
{
User *q = pHead;
if(pHead == NULL)
return;
while(pHead){
q = pHead->next;
free(pHead);
pHead = q;
}
pHead = NULL;
}
void DeleteLink_R()
{
Relation *q = pStart;
if(pStart == NULL)
return;
while(pStart){
q = pStart->next;
free(pStart);
pStart = q;
}
pStart = NULL;
}
void DeleteLink_RC()
{
Recordinfo *q = pRec;
if(pRec == NULL)
return;
while(pRec){
q = pRec->next;
free(pRec);
pRec = q;
}
pRec = NULL;
}
2.客户端
#include "wrap.h"
#include "chat.h"
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <pthread.h>
#include <unistd.h>
#define SERV_PORT 8000
#define MAX_LINE 20
#define EXIT -1
#define REGISTE 1
#define LOGIN 2
#define CHECK_FRI 3
#define GET_FRI_STA 4
#define ADD_FRI 5
#define DEL_FRI 6
#define SHI_FRI 7
#define CRE_GRP 8
#define ADD_GRP 9
#define OUT_GRP 10
#define DEL_GRP 11
#define SET_GRP_ADM 12
#define KICK_GRP 13
#define CHECK_GRP 14
#define CHECK_MEM_GRP 15
#define CHAT_ONE 16
#define CHAT_MANY 17
#define CHECK_MES_FRI 18
#define CHECK_MES_GRP 19
#define SEND_FILE 20
#define RECV_FILE 21
#define PASSIVE 0
#define ACTIVE 1
void *get_back(); //服务器返回结果
void Menu(); //主菜单
void Menu_friends(); //好友管理
void Menu_groups(); //群管理
void Menu_message(); //聊天记录
void Menu_mes_box(); //消息盒子
int login_menu(); //登陆菜单
int login(); //登陆
void registe(); //注册
void check_fri(); //查看好友列表
void add_fri(); //添加好友
void del_fri(); //删除好友
void shi_fri(); //屏蔽好友
void cre_grp(); //创建群
void add_grp(); //加群
void out_grp(); //退群
void power_grp_menu(); //群管理权限
void del_grp(); //解散群
void set_grp_adm(); //设置管理员
void kick_grp(); //踢人
void check_grp_menu(); //查看群
void check_grp(); //查看所加群
void check_mem_grp(); //查看群中成员
void Menu_chat(); //聊天+聊天记录
void chat_one(); //私聊
void chat_many(); //群聊
void check_mes_fri(); //查看与好友聊天记录
void check_mes_grp(); //查看群组聊天记录
void send_pack(int type, char *send_name, char *recv_name, char *mes);
void send_file(); //发送文件
void recv_file(PACK *recv_pack); //接收文件
int get_file_size(char *send_file_name); //得到文件大小
int confd;
char user[MAX_CHAR]; //当前登陆的账号名称
char grp_name[MAX_CHAR];
FRI_INFO fri_info; //好友列表信息
GROUP_INFO grp_info; //群列表信息
RECORD_INFO rec_info[55]; //聊天记录
int signal;
//来自外部的请求——消息盒子
char name[100][MAX_CHAR]; //发给的人
char mes_box[100][MAX_CHAR];//消息记录
int mes_box_inc[100];//加群/好友
int sign;
int sign_ive[100];//消息状态
char mes_file[MAX_CHAR * 3];
pthread_mutex_t mutex;
pthread_cond_t cond;
int main(int argc, char *argv[]) {
struct sockaddr_in serveraddr;
char ipstr[ ]="127.0.0.1";
pthread_t tid;
confd = Socket(AF_INET, SOCK_STREAM, 0);
bzero(&serveraddr, sizeof(serveraddr));
serveraddr.sin_family = AF_INET;
inet_pton(AF_INET, ipstr, &serveraddr.sin_addr.s_addr);
serveraddr.sin_port = htons(SERV_PORT);
Connect(confd, (struct sockaddr *)&serveraddr, sizeof(serveraddr));
pthread_mutex_init(&mutex, NULL);
pthread_cond_init(&cond, NULL);
if(login_menu() == 0){
//判断是否登陆成功
Close(confd);
return 0;
}
pthread_create(&tid, NULL, get_back, NULL);
Menu();
Close(confd);
return 0;
}
//服务器返回结果
void *get_back()
{
pthread_mutex_t mutex_g;
pthread_mutex_init(&mutex_g, NULL);
while(1)
{
int flag;
int i = 0;
int fd;
PACK recv_pack;
int ret = recv(confd, &recv_pack, sizeof(PACK), MSG_WAITALL);
if(ret < 0)
my_err("recv", __LINE__);
switch(recv_pack.type)
{
case CHECK_FRI:
memcpy(&fri_info, &recv_pack.fri_info, sizeof(FRI_INFO));
pthread_cond_signal(&cond);
break;
case GET_FRI_STA:
flag = recv_pack.data.mes[0] - '0';
if(flag == 0)
printf("%s---离线\n",recv_pack.data.recv_name);
else if(flag == 1)
printf("%s---在线\n",recv_pack.data.recv_name);
pthread_cond_signal(&cond);
break;
case ADD_FRI:
flag = recv_pack.data.mes[0] - '0';
if(flag == 0){
sign_ive[sign] = PASSIVE;
sprintf(name[sign], "%s", recv_pack.data.send_name);
mes_box_inc[sign] = ADD_FRI;
sprintf(mes_box[sign], "%s请求加你为好友(y/n): ", recv_pack.data.send_name);
sign++;
}
else if(flag == 1){
sign_ive[sign] = ACTIVE;
sprintf(mes_box[sign], "%s已同意请求", recv_pack.data.send_name);
sign++;
}
else if(flag == 2){
sign_ive[sign] = ACTIVE;
sprintf(mes_box[sign], "%s拒绝了你的请求", recv_pack.data.send_name);
sign++;
}
else if(flag == 3){
sign_ive[sign] = ACTIVE;
sprintf(mes_box[sign], "%s账号不存在", recv_pack.data.send_name);
sign++;
}
else if(flag == 4){
sign_ive[sign] = ACTIVE;
sprintf(mes_box[sign], "%s已是你的好友", recv_pack.data.send_name);
sign++;
}
break;
case DEL_FRI:
flag = recv_pack.data.mes[0] - '0';
if(flag == 0)
printf("\n他不是你的好友!\n");
else if(flag == 1)
printf("\n删除成功!\n");
pthread_cond_signal(&cond);
break;
case SHI_FRI:
flag = recv_pack.data.mes[0] - '0';
if(flag == 0)
printf("\n他不是你的好友!\n");
else if(flag == 1)
printf("\n屏蔽成功!\n");
pthread_cond_signal(&cond);
break;
case CRE_GRP:
flag = recv_pack.data.mes[0] - '0';
if(flag == 0)
printf("\n该群名已被注册!\n");
else if(flag == 1)
printf("\n创建成功!\n");
pthread_cond_signal(&cond);
break;
case ADD_GRP:
flag = recv_pack.data.mes[0] - '0';
if(flag == 0)
printf("\n该群不存在!\n");
else if(flag == 1){
memset(grp_name, 0, MAX_CHAR);
strcpy(grp_name, recv_pack.file.mes);
sign_ive[sign] = PASSIVE;
sprintf(name[sign], "%s", recv_pack.data.recv_name);
mes_box_inc[sign] = ADD_GRP;
sprintf(mes_box[sign], "%s请求加入群聊%s(y/n): ", recv_pack.data.recv_name, recv_pack.file.mes);
sign++;
}
else if(flag == 2){
sign_ive[sign] = ACTIVE;
sprintf(mes_box[sign], "你已加入群聊%s", recv_pack.data.recv_name);
sign++;
}
else if(flag == 3){
sign_ive[sign] = ACTIVE;
sprintf(mes_box[sign], "加入群聊%s请求被拒绝", recv_pack.data.recv_name);
sign++;
}
break;
case OUT_GRP:
flag = recv_pack.data.mes[0] - '0';
if(flag == 0)
printf("\n该群不存在!\n");
else if(flag == 1)
printf("\n退群成功!\n");
pthread_cond_signal(&cond);
break;
case DEL_GRP:
flag = recv_pack.data.mes[0] - '0';
if(flag == 0)
printf("\n该群不存在!\n");
else if(flag == 1)
printf("\n解散群成功!\n");
else if(flag == 2)
printf("\n仅群主有权解散群!\n");
pthread_cond_signal(&cond);
break;
case SET_GRP_ADM:
flag = recv_pack.data.mes[0] - '0';
if(flag == 0)
printf("\n该群不存在!\n");
else if(flag == 1)
printf("\n设置管理员成功!\n");
else if(flag == 2)
printf("\n只有群主可以设置管理员!\n");
else if(flag == 3)
printf("\n此用户不在群中!\n");
else if(flag == 6){
sign_ive[sign] = ACTIVE;
sprintf(mes_box[sign], "你被设置为群%s的管理员!", recv_pack.data.send_name);
sign++;
break;
}
if(flag != 6)
pthread_cond_signal(&cond);
break;
case KICK_GRP:
flag = recv_pack.data.mes[0] - '0';
if(flag == 0)
printf("\n该群不存在!\n");
else if(flag == 1)
printf("\n踢人成功!\n");
else if(flag == 2)
printf("\n只有群主/管理员可以踢人!\n");
else if(flag == 3)
printf("\n此用户不在群中!\n");
else if(flag == 4)
printf("\n踢人失败!\n");
else if(flag == 6){
sign_ive[sign] = ACTIVE;
sprintf(mes_box[sign], "你被踢出群聊%s", recv_pack.data.send_name);
sign++;
break;
}
if(flag != 6)
pthread_cond_signal(&cond);
break;
case CHECK_GRP:
memcpy(&grp_info, &recv_pack.grp_info, sizeof(GROUP_INFO));
pthread_cond_signal(&cond);
break;
case CHECK_MEM_GRP:
memcpy(&fri_info, &recv_pack.fri_info, sizeof(FRI_INFO));
pthread_cond_signal(&cond);
break;
case CHAT_ONE:
flag = recv_pack.data.mes[0] - '0';
if(flag == 0){
printf("\n该用户不存在!\n");
signal = 1;
pthread_cond_signal(&cond);
}
else if(flag == 1){
sign_ive[sign] = ACTIVE;
sprintf(mes_box[sign], "%s邀你私聊", recv_pack.data.send_name);
sign++;
}
else if(flag == 2){
printf("\n该用户不在线!\n");
pthread_cond_signal(&cond);
}
else if(flag == 3){
printf("\n该好友已被屏蔽!\n");
signal = 1;
pthread_cond_signal(&cond);
}
else if(flag == 6){
memcpy(&rec_info, &recv_pack.rec_info, sizeof(rec_info));
pthread_cond_signal(&cond);
}
else
printf("\n%s: %s\n", recv_pack.data.send_name, recv_pack.data.mes);
break;
case CHAT_MANY:
flag = recv_pack.data.mes[0] - '0';
if(flag == 0){
printf("\n该群不存在!\n");
signal = 1;
pthread_cond_signal(&cond);
}
else if(flag == 1){
sign_ive[sign] = ACTIVE;
sprintf(mes_box[sign], "\n群%s有人进入群聊\n", recv_pack.data.send_name);
sign++;
}
else if(flag == 2){
sign_ive[sign] = ACTIVE;
sprintf(mes_box[sign],"\n群%s有新消息\n",recv_pack.data.send_name);
sign++;
}
else if(flag == 6){
memcpy(&rec_info, &recv_pack.rec_info, sizeof(rec_info));
pthread_cond_signal(&cond);
}
else
printf("%s: %s\n", recv_pack.data.send_name, recv_pack.data.mes);
break;
case CHECK_MES_FRI:
flag = recv_pack.data.mes[0] - '0';
if(flag == 0)
printf("该用户不是你的好友!\n");
else if(flag == 1){
memcpy(&rec_info, &recv_pack.rec_info, sizeof(rec_info));
printf("\n-----------聊天记录-----------\n");
if(rec_info[0].message[0] == '0')
printf("暂无历史记录\n");
else{
while(rec_info[i].message[0] != '0'){
printf("%s-->%s: %s\n",rec_info[i].name1, rec_info[i].name2, rec_info[i].message);
i++;
}
}
}
pthread_cond_signal(&cond);
break;
case CHECK_MES_GRP:
flag = recv_pack.data.mes[0] - '0';
if(flag == 0)
printf("你不是该群成员!\n");
else if(flag == 1){
memcpy(&rec_info, &recv_pack.rec_info, sizeof(rec_info));
printf("-----------聊天记录-----------\n");
if(rec_info[0].message[0] == '0')
printf("暂无历史记录\n");
else{
while(rec_info[i].message[0] != '0'){
printf("%s: %s\n",rec_info[i].name1, rec_info[i].message);
i++;
}
}
}
pthread_cond_signal(&cond);
break;
case SEND_FILE:
flag = recv_pack.data.mes[0] - '0';
if(flag == 0){
printf("该用户不是你的好友!\n");
signal = 1;
pthread_cond_signal(&cond);
}
if(flag == 1)
pthread_cond_signal(&cond);
break;
case RECV_FILE:
if(strcmp(recv_pack.data.mes, "5") == 0)
{
sign_ive[sign] = PASSIVE;
sprintf(name[sign], "%s", recv_pack.data.send_name);
mes_box_inc[sign] = RECV_FILE;
sprintf(mes_box[sign], "%s给你发来了一个文件,是否接收(y/n): ", recv_pack.data.send_name);
sign++;
}
else if(strcmp(recv_pack.data.mes, "4") == 0)
{
memset(mes_file, 0, sizeof(mes_file));
mes_file[0] = '_';
strcat(mes_file, recv_pack.data.send_name);
fd = creat(mes_file, S_IRWXU);
close(fd);
}
else if(strcmp(recv_pack.data.mes, "0") == 0)
printf("\n%s拒绝接收文件!\n", recv_pack.data.recv_name);
else if(strcmp(recv_pack.data.mes, "1") == 0)
printf("\n%s确认接收文件!\n", recv_pack.data.recv_name);
else if(strcmp(recv_pack.data.mes, "2") == 0)
printf("%s接收完毕\n", recv_pack.data.recv_name);
else if(strcmp(recv_pack.data.mes, "3") == 0)
printf("接收完毕!\n");
else
{
recv_file(&recv_pack);
}
break;
default:
break;
}
if(ret == 0){
printf("\n无法连接服务器!\n");
exit(1);
}
}
}
//登陆菜单
int login_menu()
{
int flag;
int choice;
do
{
printf("------------------------\n");
printf("|\t1.登陆\t\t|\n");
printf("------------------------\n");
printf("|\t2.注册\t\t|\n");
printf("------------------------\n");
printf("|\t0.退出\t\t|\n");
printf("------------------------\n");
printf("请选择: ");
scanf("%d",&choice);
switch(choice)
{
case 1:
if(login() == 1)
return 1;
break;
case 2:
registe();
break;
default:
break;
}
}while(choice != 0);
flag = EXIT;
send_pack(flag, user, "server", " ");
return 0;
}
//注册
void registe()
{
int flag = REGISTE;
char registe_name[MAX_CHAR];
char registe_passwd[MAX_CHAR];
PACK recv_registe;
int registe_flag;
printf("请输入用户名:");
scanf("%s",registe_name);
printf("请输入用户密码:");
scanf("%s",registe_passwd);
send_pack(flag, registe_name, "server", registe_passwd);
printf("请稍等...\n");
sleep(1);
if(recv(confd, &recv_registe, sizeof(PACK), MSG_WAITALL) < 0)
my_err("recv", __LINE__);
registe_flag = recv_registe.data.mes[0] - '0';
if(registe_flag == 1)
printf("注册成功!\n");
else if(registe_flag == 0)
printf("该用户名已存在,请重新选择!\n");
}
//登陆
int login()
{
int flag = LOGIN;
char login_name[MAX_CHAR];
char login_passwd[MAX_CHAR];
PACK recv_login;
int login_flag;
int i = 0;
printf("请输入用户名称:");
scanf("%s",login_name);
getchar();
printf("请输入用户密码:");
do{
login_passwd[i]=getch();
if(login_passwd[i]=='\r'){
printf("\n");
break;
}
if(login_passwd[i]=='\b'){
//为什么不行????
if(i==0){
printf("\a");
continue;
}
i--;
printf("'\b' '\b'");
}
else{
i++;
printf("*");
}
}while(login_passwd[i]!='\n' && i<18);
login_passwd[i]='\0';
system("clear");
send_pack(flag, login_name, "server", login_passwd);
if(recv(confd, &recv_login, sizeof(PACK), MSG_WAITALL) < 0)
my_err("recv", __LINE__);
login_flag = recv_login.data.mes[0] - '0';
if(login_flag == 1)
{
printf("登陆成功!\n");
strncpy(user, login_name, strlen(login_name));
return 1;
}
else if(login_flag == 0)
printf("登陆失败!\n");
else if(login_flag == 2)
printf("该用户已在线!\n");
return 0;
}
//主菜单
void Menu()
{
int choice;
int flag;
do
{
printf("---------------------------------\n");
printf("|\t 1.好友管理 \t|\n");
printf("---------------------------------\n");
printf("|\t 2.群管理 \t|\n");
printf("---------------------------------\n");
printf("|\t 3.发送文件 \t|\n");
printf("---------------------------------\n");
printf("|\t 4.聊天通讯 \t|\n");
printf("---------------------------------\n");
printf("|\t 5.通知中心 \t|\n");
printf("---------------------------------\n");
printf("|\t 0.退出 \t|\n");
printf("---------------------------------\n");
printf("请选择:");
scanf("%d",&choice);
switch(choice)
{
case 1:
Menu_friends();
break;
case 2:
Menu_groups();
break;
case 3:
send_file();
break;
case 4:
Menu_chat();
break;
case 5:
Menu_mes_box();
break;
default:
break;
}
}while(choice != 0);
flag = EXIT;
send_pack(flag, user, "server", " ");
}
//好友管理
void Menu_friends()
{
int choice;
do
{
printf("---------------------------\n");
printf("|\t1.查看好友列表 |\n");
printf("---------------------------\n");
printf("|\t2.添加好友\t |\n");
printf("---------------------------\n");
printf("|\t3.删除好友\t |\n");
printf("---------------------------\n");
printf("|\t4.屏蔽好友\t |\n");
printf("---------------------------\n");
printf("|\t0.返回 \t |\n");
printf("---------------------------\n");
printf("请选择:");
scanf("%d",&choice);
switch(choice)
{
case 1:
check_fri();
break;
case 2:
add_fri();
break;
case 3:
del_fri();
break;
case 4:
shi_fri();
break;
default:
break;
}
}while(choice != 0);
}
//查看好友列表
void check_fri()
{
int flag = CHECK_FRI;
char mes[MAX_CHAR];
bzero(mes, MAX_CHAR);
memset(&fri_info, 0, sizeof(fri_info));
int i;
pthread_mutex_lock(&mutex);
send_pack(flag, user, "server", "1");
pthread_cond_wait(&cond, &mutex);
printf("\n-----------好友列表-----------\n");
if(fri_info.friends_num == 0)
printf("暂无好友!\n");
else{
for(i = 0; i < fri_info.friends_num; i++){
if(fri_info.friends_status[i] == 1){
flag = GET_FRI_STA;
send_pack(flag, fri_info.friends[i], "server", mes);
pthread_cond_wait(&cond, &mutex);
}
else if(fri_info.friends_status[i] == 2)
printf("%s---黑名单\n",fri_info.friends[i]);
}
}
pthread_mutex_unlock(&mutex);
}
//添加好友
void add_fri()
{
int i;
int flag = ADD_FRI;
pthread_mutex_lock(&mutex);
char friend_add[MAX_CHAR];
printf("你想要添加的用户名:");
scanf("%s",friend_add);
send_pack(flag, user, friend_add, "0");
pthread_mutex_unlock(&mutex);
}
//删除好友
void del_fri()
{
int flag = DEL_FRI;
char friend_del[MAX_CHAR];
pthread_mutex_lock(&mutex);
printf("你想要删除的用户名:");
scanf("%s",friend_del);
send_pack(flag, user, "server", friend_del);
pthread_cond_wait(&cond, &mutex);
pthread_mutex_unlock(&mutex);
}
//屏蔽好友
void shi_fri()
{
int flag = SHI_FRI;
char friend_shi[MAX_CHAR];
pthread_mutex_lock(&mutex);
printf("你想要屏蔽的用户名:");
scanf("%s",friend_shi);
send_pack(flag, user, "server", friend_shi);
pthread_cond_wait(&cond, &mutex);
pthread_mutex_unlock(&mutex);
}
//群管理
void Menu_groups()
{
int choice;
do
{
printf("-----------------------------\n");
printf("| 1.查看群 |\n");
printf("-----------------------------\n");
printf("| 2.创建群 |\n");
printf("-----------------------------\n");
printf("| 3.加入群 |\n");
printf("-----------------------------\n");
printf("| 4.退出群 |\n");
printf("-----------------------------\n");
printf("| 5.管理群 |\n");
printf("-----------------------------\n");
printf("| 0.返回 |\n");
printf("-----------------------------\n");
printf("请选择:");
scanf("%d",&choice);
switch(choice)
{
case 1:
check_grp_menu();
break;
case 2:
cre_grp();
break;
case 3:
add_grp();
break;
case 4:
out_grp();
break;
case 5:
power_grp_menu();
break;
default:
break;
}
}while(choice != 0);
}
//查看群
void check_grp_menu()
{
int choice;
do
{
printf("-----------------------------\n");
printf("| 1.查看所加群 |\n");
printf("-----------------------------\n");
printf("| 2.查看群中成员 |\n");
printf("-----------------------------\n");
printf("| 0.返回 |\n");
printf("-----------------------------\n");
printf("请选择:");
scanf("%d",&choice);
switch(choice)
{
case 1:
check_grp();
break;
case 2:
check_mem_grp();
break;
default:
break;
}
}while(choice != 0);
}
//查看所加群
void check_grp()
{
int flag = CHECK_GRP;
char mes[MAX_CHAR];
memset(mes, 0, sizeof(mes));
memset(&grp_info, 0, sizeof(grp_info));
int i;
pthread_mutex_lock(&mutex);
send_pack(flag, user, "server", mes);
pthread_cond_wait(&cond, &mutex);
printf("\n-----------群聊列表-----------\n");
if(grp_info.grp_num == 0)
printf("暂无加入群聊!\n");
else{
for(i = 0; i < grp_info.grp_num; i++){
printf("%s\n",grp_info.groups[i]);
}
}
pthread_mutex_unlock(&mutex);
}
//查看群中成员
void check_mem_grp()
{
int flag = CHECK_MEM_GRP;
char mes[MAX_CHAR];
int i;
pthread_mutex_lock(&mutex);
printf("\n你想要查看那个群中的成员信息:");
scanf("%s",mes);
for(i = 0; i < grp_info.grp_num; i++){
if(strcmp(grp_info.groups[i], mes) == 0)
break;
}
if(i > grp_info.grp_num)
printf("你没有加入此群!\n");
else{
memset(&fri_info, 0, sizeof(fri_info));
send_pack(flag, user, "server", mes);
pthread_cond_wait(&cond, &mutex);
printf("\n-----------%s-----------\n",mes);
if(fri_info.friends_num == 0)
printf("该群中暂无成员!\n");
else
{
for(i = 0; i < fri_info.friends_num; i++)
printf("%s\n", fri_info.friends[i]);
}
}
pthread_mutex_unlock(&mutex);
}
//创建群
void cre_grp()
{
int flag = CRE_GRP;
char grp_cre[MAX_CHAR];
pthread_mutex_lock(&mutex);
printf("你想要创建的群名称:");
scanf("%s",grp_cre);
send_pack(flag, user, "server", grp_cre);
pthread_cond_wait(&cond, &mutex);
pthread_mutex_unlock(&mutex);
}
//加群
void add_grp()
{
int flag = ADD_GRP;
char grp_add[MAX_CHAR];
pthread_mutex_lock(&mutex);
printf("你想要加入的群名称:");
scanf("%s",grp_add);
send_pack(flag, user, "server", grp_add);
pthread_mutex_unlock(&mutex);
}
//退群
void out_grp()
{
int flag = OUT_GRP;
char grp_out[MAX_CHAR];
pthread_mutex_lock(&mutex);
printf("你想要退出的群名称:");
scanf("%s",grp_out);
send_pack(flag, user, "server", grp_out);
pthread_cond_wait(&cond, &mutex);
pthread_mutex_unlock(&mutex);
}
//群管理权限
void power_grp_menu()
{
int choice;
do
{
printf("-----------------------------\n");
printf("| 1.解散群 |\n");
printf("-----------------------------\n");
printf("| 2.设置管理员 |\n");
printf("-----------------------------\n");
printf("| 3.踢人(管) |\n");
printf("-----------------------------\n");
printf("| 0.返回 |\n");
printf("-----------------------------\n");
printf("请选择:");
scanf("%d",&choice);
switch(choice)
{
case 1:
del_grp();
break;
case 2:
set_grp_adm();
break;
case 3:
kick_grp();
break;
default:
break;
}
}while(choice != 0);
}
//解散群
void del_grp()
{
int flag = DEL_GRP;
char grp_del[MAX_CHAR];
pthread_mutex_lock(&mutex);
printf("你想要解散的群名称:");
scanf("%s",grp_del);
send_pack(flag, user, "server", grp_del);
pthread_cond_wait(&cond, &mutex);
pthread_mutex_unlock(&mutex);
}
//设置管理员
void set_grp_adm()
{
int flag = SET_GRP_ADM;
char grp_set_1[MAX_CHAR];
char grp_set_2[MAX_CHAR];
pthread_mutex_lock(&mutex);
printf("你想要在那个群中设置谁为管理员:");
scanf("%s",grp_set_1);
scanf("%s",grp_set_2);
send_pack(flag, user, grp_set_1, grp_set_2);
pthread_cond_wait(&cond, &mutex);
pthread_mutex_unlock(&mutex);
}
//踢人
void kick_grp()
{
int flag = KICK_GRP;
char grp_set_1[MAX_CHAR];
char grp_set_2[MAX_CHAR];
pthread_mutex_lock(&mutex);
printf("你想要在那个群将谁踢出:");
scanf("%s",grp_set_1);
scanf("%s",grp_set_2);
send_pack(flag, user, grp_set_1, grp_set_2);
pthread_cond_wait(&cond, &mutex);
pthread_mutex_unlock(&mutex);
}
void Menu_chat()
{
int choice;
do
{
printf("----------------------------\n");
printf("| 1.私聊 |\n");
printf("----------------------------\n");
printf("| 2.群聊 |\n");
printf("----------------------------\n");
printf("| 3.聊天记录 |\n");
printf("----------------------------\n");
printf("| 0.返回 |\n");
printf("----------------------------\n");
printf("请选择:");
scanf("%d",&choice);
switch(choice)
{
case 1:
chat_one();
break;
case 2:
chat_many();
break;
case 3:
Menu_message();
break;
default:
break;
}
}while(choice != 0);
}
//私聊
void chat_one()
{
int flag = CHAT_ONE;
char chat_name[MAX_CHAR];
char mes[MAX_CHAR];
int i = 0;
memset(mes, 0, sizeof(mes));
memset(&rec_info, 0, sizeof(rec_info));
rec_info[0].message[0] = '0';
pthread_mutex_lock(&mutex);
printf("\n你想要和谁聊天呢? ");
scanf("%s",chat_name);
mes[0] = '1';
send_pack(flag, user, chat_name, mes);
pthread_cond_wait(&cond, &mutex);
if(signal == 1){
signal = 0;
pthread_mutex_unlock(&mutex);
return;
}
printf("\n-----------%s-----------\n",rec_info[i].name2);
while(rec_info[i].message[0] != '0'){
printf("%s: %s\n",rec_info[i].name1,rec_info[i].message);
i++;
}
printf("\n按q退出聊天\n");
getchar();
do
{
memset(mes, 0, sizeof(mes));
printf("%s: ", user);
scanf("%[^\n]", mes);
getchar();
send_pack(flag, user, chat_name, mes);
}while(strcmp(mes, "q") != 0);
pthread_mutex_unlock(&mutex);
}
//群聊
void chat_many()
{
int flag = CHAT_MANY;
char chat_name[MAX_CHAR];
char mes[MAX_CHAR];
int i = 0;
memset(mes, 0, sizeof(mes));
memset(&rec_info, 0, sizeof(rec_info));
rec_info[0].message[0] = '0';
pthread_mutex_lock(&mutex);
printf("\n你想要在那个群中聊天呢? ");
scanf("%s",chat_name);
mes[0] = '1';
send_pack(flag, user, chat_name, mes);
pthread_cond_wait(&cond, &mutex);
if(signal == 1)//群不存在
{
signal = 0;
pthread_mutex_unlock(&mutex);
return;
}
printf("\n-----------%s-----------\n",rec_info[i].name2);
while(rec_info[i].message[0] != '0')
{
printf("%s: %s\n",rec_info[i].name1, rec_info[i].message);
i++;
}
printf("\n按q退出群聊\n");
getchar();
do
{
memset(mes, 0, sizeof(mes));
//scanf("%s", mes);
scanf("%[^\n]", mes);
getchar();
send_pack(flag, user, chat_name, mes);
}while(strcmp(mes, "q") != 0);
pthread_mutex_unlock(&mutex);
}
//得到文件大小
int get_file_size(char *send_file_name)
{
FILE *fd;
int len;
if((fd = fopen(send_file_name,"rb")) == NULL){
printf("\n该文件不存在!\n");
return -1;
}
fseek(fd, 0, SEEK_END);
len=ftell(fd);
fclose(fd);
return len;
}
//发文件
void send_file()
{
int flag = SEND_FILE;
int fd;
int length = 0;
int sum, n, m = 0;
char file_name[MAX_CHAR];
char send_file_name[MAX_CHAR];
PACK send_file;
send_file.type = flag;
printf("你想要给谁发送文件: ");
scanf("%s", file_name);
printf("你想要发送的文件名称:");
scanf("%s",send_file_name);
sum = get_file_size(send_file_name);
if(sum == -1){
pthread_mutex_unlock(&mutex);
return;
}
printf("总大小:%d\n", sum);
send_pack(flag, send_file_name, file_name, "send");
pthread_cond_wait(&cond, &mutex);
if(signal == 1){
signal = 0;
pthread_mutex_unlock(&mutex);
return;
}
strcpy(send_file.data.send_name, user);
strcpy(send_file.data.recv_name, file_name);
//printf("总大小:%d\n", sum);
fd = open(send_file_name, O_RDONLY);
if(fd == -1)
printf("没有找到文件:%s\n", send_file_name);
else{
while((length = read(fd, send_file.file.mes, MAX_FILE - 1)) > 0){
send_file.file.size = length;
if(send(confd, &send_file, sizeof(PACK), 0) < 0)
my_err("send",__LINE__);
bzero(send_file.file.mes, MAX_FILE);
printf("发送中...\n");
}
}
printf("发送成功!\n");
send_pack(flag, user, file_name, "success");
close(fd);
}
//接收文件
void recv_file(PACK *recv_pack)
{
int fd;
int length;
char mes[MAX_CHAR * 3 + 1];
bzero(mes, MAX_CHAR * 3 + 1);
fd = open(mes_file, O_WRONLY | O_APPEND);
if(fd == -1)
printf("未找到文件%s!\n", mes_file);
if(write(fd, recv_pack->file.mes, recv_pack->file.size) < 0)
my_err("write", __LINE__);
printf("\n接收中...\n");
close(fd);
}
//聊天记录
void Menu_message()
{
int choice;
do
{
printf("-----------------------------\n");
printf("| 1.好友聊天记录 |\n");
printf("-----------------------------\n");
printf("| 2.群聊记录 |\n");
printf("-----------------------------\n");
printf("| 0.返回 |\n");
printf("-----------------------------\n");
printf("请选择:");
scanf("%d",&choice);
switch(choice)
{
case 1:
check_mes_fri();
break;
case 2:
check_mes_grp();
break;
default:
break;
}
}while(choice != 0);
}
//与好友聊天记录
void check_mes_fri()
{
int i = 0;
int flag = CHECK_MES_FRI;
char mes_fri[MAX_CHAR];
memset(&rec_info, 0, sizeof(rec_info));
rec_info[0].message[0] = '0';
pthread_mutex_lock(&mutex);
printf("\n你想要查看与谁的聊天记录? ");
scanf("%s",mes_fri);
send_pack(flag, user, "server", mes_fri);
pthread_cond_wait(&cond, &mutex);
pthread_mutex_unlock(&mutex);
}
//群组聊天记录
void check_mes_grp()
{
int i = 0;
int flag = CHECK_MES_GRP;
char mes_grp[MAX_CHAR];
memset(&rec_info, 0, sizeof(rec_info));
rec_info[0].message[0] = '0';
pthread_mutex_lock(&mutex);
printf("\n你想要查看那个群的聊天记录? ");
scanf("%s",mes_grp);
send_pack(flag, user, "server", mes_grp);
pthread_cond_wait(&cond, &mutex);
pthread_mutex_unlock(&mutex);
}
// //接收文件
//消息盒子
void Menu_mes_box()
{
int i;
char ch[5];
pthread_mutex_lock(&mutex);
printf("\n您有%d条消息未读\n", sign);
for(i = 0; i < sign; i++){
if(sign_ive[i] == PASSIVE){
printf("NO.%d: %s", i + 1, mes_box[i]);
scanf("%s", ch);
if(mes_box_inc[i] == ADD_GRP)
send_pack(mes_box_inc[i], grp_name, name[i], ch);
else
send_pack(mes_box_inc[i], user, name[i], ch);
}
else if(sign_ive[i] == ACTIVE)
printf("NO.%d: %s\n", i + 1, mes_box[i]);
}
sign = 0;
pthread_mutex_unlock(&mutex);
}
//发包
void send_pack(int type, char *send_name, char *recv_name, char *mes)
{
PACK pack_send;
memset(&pack_send, 0, sizeof(PACK));
pack_send.type = type;
pack_send.data.recv_fd = confd;
strcpy(pack_send.data.send_name, send_name);
strcpy(pack_send.data.recv_name, recv_name);
strcpy(pack_send.data.mes, mes);
if(send(confd, &pack_send, sizeof(PACK), 0) < 0)
my_err("send",__LINE__);
}
四、总结
在写聊天室之前,我只是简单了解了网络与MYSQL的一些API,所以在最开始并没有整体的思路和架构。所以我又在网上看了一些视频加深理解,并且借鉴和学习了其他人的思路和具体实现。随着写的越来越多,我发现一个大的项目,整体思路远比具体细节重要的多,在写好友管理时,我将每个任务分开写,而后发现有很多可以优化的地方,从而重新进行了改进。还有很重要的一点是,写完一个函数一定就要开始测试,而不能等到写了好多再开始,各种各样不同的错误让我根部无法精确定位,浪费了很多时间。在快要写完的现在,我并没有想象中的如释重负,而是发现了很多自己还存在的问题,并且那些额外要求功能都没有实现(但是对于这方面实在没有什么兴趣,以后应该不会完善了吧…)。
最后 。我还是好好学JavaWeb吧!