服务器端:
main.cpp//运行服务器
#include<iostream>
#include"tcpsever.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
using namespace std;
int main(int argc,char *argv[])
{
if(argc < 4)
{
cout<<"error"<<endl;
return 0;
}
//分离参数
int port = atoi(argv[2]);//端口号
char *ip = argv[1];//ip
short pth_num = atoi(argv[3]);//线程个数
Tcpsever sever(ip,port,pth_num);
sever.run();
}
tcpsever.h
#include <iostream>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <vector>
#include "pthread.h"
#include <map>
#ifndef TCPSEVER_H
#define TCPSEVER_H
using namespace std;
class MVEC
{
public:
MVEC(int brr[2])
{
arr[0] = brr[0];
arr[1] = brr[1];
}
int arr[2];
};
class Tcpsever
{
public:
Tcpsever(char *ip,short port,int pth_num);
~Tcpsever();
void run();
private:
int _listen_fd;//监听套接字
int _pth_num;//启动的线程的个数
struct event_base *_base;//libevent
vector<MVEC> _socket_pair;//socket pair vector
vector<Pthread*> _pthread;//pthread vector
map<int,int> _pth_work_num;//用于和子线程交流的fd+对应子线程监听的个数
void get_sock_pair();//获取主线程和子线程交流的套接字
void get_pthread();//获取线程
friend void listen_cb(int fd,short event,void* arg);
friend void sock_pair_cb(int fd,short event,void* arg);
};
#endif
tcpsever.cpp
#include <stdio.h>
#include <event.h>
#include <string>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <assert.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <errno.h>
#include"tcpsever.h"
void listen_cb(int fd,short event,void *arg)
{
Tcpsever *ser = (Tcpsever*)arg;
//接受用户链接
struct sockaddr_in cli;
socklen_t len = sizeof(cli);
int cli_fd = accept(fd,(struct sockaddr*)&cli,&len);
assert(cli_fd != -1);
cout<<"one cli linked!"<<endl;
//查找当前监听数量最少的子线程
map<int,int>::iterator it = ser->_pth_work_num.begin();
int min_num = it->second; //最小个数
int min_fd;//监听最少的对应的fd
for(;it != ser->_pth_work_num.end();++it)
{
if(it->second <= min_num)
{
min_num = it->second;
min_fd = it->first;
}
}
//将客户端套接子通过socktpair发给子线程
char sendbuff[128] = {0};
sprintf(sendbuff,"%d",cli_fd);
send(min_fd,sendbuff,strlen(sendbuff),0);
}
void sock_pair_cb(int fd,short event,void *arg)
{
Tcpsever *ser = (Tcpsever*)arg;
//读取管道内容
char pairbuff[128] = {0};
recv(fd,pairbuff,127,0);
//更新到map表_pth_work_num ----->fd
map<int,int>::iterator it = ser->_pth_work_num.find(fd);
it->second = atoi(pairbuff);
}
Tcpsever::Tcpsever(char *ip,short port,int pth_num)
{
///创建服务器
int _listen_fd = socket(AF_INET,SOCK_STREAM,0);
if(-1 == _listen_fd)
{
cerr<<"socket fail;error:"<<errno<<endl;
return;
}
struct sockaddr_in ser;
ser.sin_family = AF_INET;
ser.sin_port = htons(port);
ser.sin_addr.s_addr = inet_addr(ip);
_pth_num = pth_num;
if(-1 == bind(_listen_fd,(struct sockaddr*)&ser,sizeof(ser)))
{
cerr<<"bind fail;errno:"<<errno<<endl;
throw "";
}
if(-1 == listen(_listen_fd,20))
{
cerr<<"listen fail;errno:"<<errno<<endl;
throw "";
}
//给libevent申请空间
_base = event_base_new();
//创建事件,绑定监听套接子的回调函数(listen_cb)
struct event *listen_event = event_new(_base,_listen_fd,EV_READ|EV_PERSIST,listen_cb,this);
if(NULL == listen_event)
{
cerr<<"event new fail;errno:"<<errno<<endl;
throw "";
}
//添加到事件列表
event_add(listen_event,NULL);
}
void Tcpsever::run()
{
//申请socketpair(函数自查)
get_sock_pair();
//创建线程//规定 int arr[2] arr[0]<=>主线程占用 arr[1]<=>子线程占用
get_pthread();
//为主线程的socktpair创建事件,绑定回调函数(sock_pair_cb)
int i;
for(i=0; i<_pth_num; i++)
{
struct event* sock_event = event_new(_base,_socket_pair[i].arr[0],EV_READ|EV_PERSIST,sock_pair_cb,this);
event_add(sock_event,NULL);
}
event_base_dispatch(_base);
}
void Tcpsever::get_sock_pair()
{
int i = 0;
for(i = 0;i < _pth_num;i++ )
{
//申请双向管道
int arr[2];
if(-1 == socketpair(AF_UNIX,SOCK_STREAM,0,arr))
{
cerr<<"socketpair fail;errno:"<<errno<<endl;
return;
}
//将双向管道加入到_sock_pair.push_back();
_socket_pair.push_back(MVEC(arr));
_pth_work_num.insert(make_pair(arr[0],0));
}
}
void Tcpsever::get_pthread()
{
//开辟线程
for(int i = 0; i< _pth_num; i++)
{
_pthread.push_back(new Pthread(_socket_pair[i].arr[1]));
}
}
Tcpsever::~Tcpsever()
{
}
pthread.h
#include <iostream>
#include <map>
using namespace std;
#ifndef PTHREAD_H
#define PTHREAD_H
class Pthread
{
public:
Pthread(int sock_fd);
~Pthread();
private:
int _sock_fd;//sock_pair (1)
struct event_base* _base;//libevent
map<int,struct event*> _event_map;//存放事件的map表
pthread_t _pthread;//线程描述符
friend void sock_pair_1_cb(int fd,short event,void *arg);
friend void client_cb(int fd,short event,void *arg);
friend void *pthread_run(void *arg);
};
#endif
pthread.cpp
#include"pthread.h"
#include <string.h>
#include "public.h"
#include <json/json.h>
#include <stdlib.h>
#include <iostream>
#include "control.h"
#include <event.h>
#include <errno.h>
#include <string>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <map>
using namespace std;
extern Control control_sever;
void *pthread_run(void *arg);
void sock_pair_1_cb(int fd,short event,void *arg);
void client_cb(int fd,short int event,void *arg);
Pthread::Pthread(int sock_fd)
{
_sock_fd = sock_fd;
_base = event_base_new();
//启动线程
pthread_create(&_pthread,NULL,pthread_run,this);
}
void* pthread_run(void *arg)
{
Pthread *pth = (Pthread *)arg;
//将sock_pair_1加入到libevent sock_pair_1_cb()
struct event* _event = event_new(pth->_base,pth->_sock_fd,EV_READ|EV_PERSIST,sock_pair_1_cb,arg);
event_add(_event,NULL);
pth->_event_map.insert(make_pair(pth->_sock_fd,_event));
event_base_dispatch(pth->_base);
}
void sock_pair_1_cb(int fd,short int event,void *arg)
{
Pthread *pth = (Pthread *)arg;
//recv -> clien_fd
char buff[128] = {0};
if(0 >recv(fd,buff,127,0))
{
cout<<"recv fail;errno:"<<errno<<endl;
exit(1);
}
int cli_fd = atoi(buff);
//将client_fd加入到libevent client_cb()
struct event* cli_event = event_new(pth->_base,cli_fd,EV_READ|EV_PERSIST,client_cb,arg);
if(NULL == cli_event)
{
cerr<<"client create fail;errno:"<<errno<<endl;
exit(1);
}
event_add(cli_event,NULL);
//给主线程回复当前监听的客户端数量
//插入到map表中
pth->_event_map.insert(make_pair(cli_fd,cli_event));
int cli_fd_num = pth->_event_map.size();
char buf[128] = {0};
sprintf(buf,"%d",cli_fd_num);
send(fd,buff,strlen(buff),0);
}
void client_cb(int fd,short event,void *arg)
{
Pthread* pth = (Pthread*)arg;
//recv ->buff
char buff[128] = {0};
if(0 > recv(fd,buff,127,0))
{
cout<<"revc buff fail;errno:"<<errno<<endl;
return;
}
//将buff发给control
//control_sever.process(fd,buff);
control_sever.process(fd,buff);
Json::Value val;
Json::Reader read;
if(-1 == read.parse(buff,val))
{
cerr<<"pthread::read fail;errno:"<<errno<<endl;
return;
}
if(val["reason_type"] == REASON_TYPE_EXIT)
{
map<int,struct event*>::iterator it =pth->_event_map.find(fd);
if(pth->_event_map.end() == it)
{
cerr<<"pthread::read map fail;errno:"<<errno<<endl;
return;
}
close(fd);
event_del(it->second);
pth->_event_map.erase(it);
}
}
Pthread::~Pthread()
{
}
view.h
#include <iostream>
#include <string>
using namespace std;
#ifndef VIEW_H
#define VIEW_H
class View
{
public:
virtual void process(int fd,char* json){}
virtual void response(){}
private:
int _fd;
string _str;
};
#endif
control.h
#include <iostream>
#include "View.h"
#include <map>
#include <string>
using namespace std;
#ifndef CONTROL_H
#define CONTROL_H
class Control
{
public:
Control();
~Control(){}
void process(int fd,char* json);
private:
map<int,View*> _map;
};
#endif
control.cpp
#include "View.h"
#include "register.h"
#include "login.h"
#include "public.h"
#include "talk_one.h"
#include "talk_group.h"
#include "getlist.h"
#include "exit.h"
#include "control.h"
#include <json/json.h>
#include <stdio.h>
#include <string>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/socket.h>
Control::Control()
{
cout<<"control begin:"<<endl;
_map.insert(make_pair(REASON_TYPE_REGISTER,new Register()));
_map.insert(make_pair(REASON_TYPE_LOGIN,new Login()));
_map.insert(make_pair(REASON_TYPE_LIST,new Get_list()));
_map.insert(make_pair(REASON_TYPE_EXIT,new Exit()));
_map.insert(make_pair(REASON_TYPE_TALK,new Talk_one()));
_map.insert(make_pair(REASON_TYPE_GROUP,new Talk_group()));
}
void Control::process(int fd,char *json)
{
Json::Value val;
Json::Reader read;
if(-1 == read.parse(json,val))
{
cerr<<"Control process json parse fail;errno:"<<errno<<endl;
return;
}
map<int,View*>::iterator it = _map.find(val["reason_type"].asInt());
if(it == _map.end())
{
cout<<"reason type not find!"<<endl;
}
else
{
it->second->process(fd,json);
it->second->response();
}
}
Control control_sever;
mysql.h
#ifndef MYSQL_H
#define MYSQL_H
#include<mysql/mysql.h>
class Mysql
{
public:
Mysql();
~Mysql();
MYSQL* _mpcon;
MYSQL_RES* _mp_res;
MYSQL_ROW _mp_row;
};
#endif
mysql.cpp
#include"mysql.h"
#include <iostream>
#include <stdlib.h>
#include <errno.h>
using namespace std;
Mysql::Mysql()
{
_mpcon = mysql_init((MYSQL*)0);
if(NULL == _mpcon)
{
cerr<<"_mpcon NULL;errno:"<<errno<<endl;
exit(0);
}
//链接数据库
if(!mysql_real_connect(_mpcon,"127.0.0.1","root","123456",NULL,3306,NULL,0))
{
cerr<<"mysql connect fail;errno:"<<errno<<endl;
exit(0);
}
//选择数据库
if(mysql_select_db(_mpcon,"chat"))
{
cerr<<"database select fail;errno:"<<errno<<endl;
exit(0);
}
}
Mysql::~Mysql()
{
if(NULL != _mp_res)
{
mysql_free_result(_mp_res);
}
mysql_close(_mpcon);
}
Mysql Mysql_sever;
register.h
#ifndef REGISTER
#define REGISTER
#include <iostream>
#include <string>
#include "View.h"
using namespace std;
class Register:public View
{
public:
void process(int fd,char* json);
void response();
private:
int _fd;
string _str;
};
#endif
register.cpp
#include "register.h"
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <json/json.h>
#include <string.h>
#include <iostream>
#include "mysql.h"
#include <errno.h>
#include "register.h"
#include "control.h"
#include <string>
using namespace std;
extern Mysql Mysql_sever;
void Register::process(int fd,char* json)
{
cout<<"register::begin"<<endl;
if(NULL == json)
{
cerr<<"json is null;errno:"<<errno<<endl;
return;
}
cout<<"register::begin"<<endl;
_fd = fd;
//解析json
Json::Value val;
Json::Reader read;
if(-1 == read.parse(json,val))
{
cerr<<"read fail;errno:"<<errno<<endl;
return;
}
//name pw
//在数据库中查找name有没有重复
char cmd[100] = "SELECT *FROM user WHERE name='";
strcat(cmd,val["name"].asString().c_str());
strcat(cmd,"';");
if(mysql_real_query(Mysql_sever._mpcon,cmd,strlen(cmd)))
{
cerr<<" select fail ;errno:"<<errno<<endl;
return;
}
Mysql_sever._mp_res = mysql_store_result(Mysql_sever._mpcon);
if(!(Mysql_sever._mp_row = mysql_fetch_row(Mysql_sever._mp_res)))
{
//将name pw加入到数据库的user
char cmd1[100] = "INSERT INTO user VALUE('";
cout<<"register insert :"<<cmd1<<endl;
strcat(cmd1,val["name"].asString().c_str());
strcat(cmd1,"','");
strcat(cmd1,val["pw"].asString().c_str());
strcat(cmd1,"');");
cout<<"register::strcat::"<<cmd1<<endl;
if(mysql_real_query(Mysql_sever._mpcon,cmd1,strlen(cmd1)))
{
cerr<<"insert fail;errno:"<<errno<<endl;
return;
}
_str = "register success";
}
else
{
_str = "register repeat";
}
}
void Register::response()
{
//用json将消息打包,发送给客户端
Json::Value root;
root["reason"] = _str;
if(-1 == send(_fd,root.toStyledString().c_str(),strlen(root.toStyledString().c_str()),0))
{
cerr<<"register send reason fail;errno:"<<errno<<endl;
return;
}
}
login.h
#ifndef LOGIN
#define LOGIN
#include "View.h"
class Login:public View
{
public:
void process(int fd,char *json);
void response();
private:
int _fd;
string _str;
};
#endif
login.cpp
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <json/json.h>
#include <errno.h>
#include <string.h>
#include <string>
#include <iostream>
#include "login.h"
#include "mysql.h"
using namespace std;
extern Mysql Mysql_sever;
void Login::process(int fd,char *json)
{
if(NULL == json)
{
cerr<<"json is null;errno:"<<errno<<endl;
return;
}
cout<<"login::begin"<<endl;
_fd = fd;
//解析json
Json::Value val;
Json::Reader read;
if(-1 == read.parse(json,val))
{
cerr<<"read fail;errno:"<<errno<<endl;
return;
}
//name pw
//在数据库中查找name所对应的pw都是否正确
char cmd[100] = "SELECT *FROM user WHERE name='";
strcat(cmd,val["name"].asString().c_str());
strcat(cmd,"' AND ");
strcat(cmd,"pw='");
strcat(cmd,val["pw"].asString().c_str());
strcat(cmd,"';");
cout<<cmd<<endl;
if(mysql_real_query(Mysql_sever._mpcon,cmd,strlen(cmd)))
{
_str = "login fail";
Json::Value root;
root["reason"] = _str;
if(-1 == send(_fd,root.toStyledString().c_str(),strlen(root.toStyledString().c_str()),0))
{
cerr<<"login::send reason fail;errno:"<<errno<<endl;
return;
}
cerr<<"select fail;errno:"<<errno<<endl;
return;
}
Mysql_sever._mp_res = mysql_store_result(Mysql_sever._mpcon);
if((Mysql_sever._mp_row = mysql_fetch_row(Mysql_sever._mp_res)))
{
char ccmd[128] = "SELECT *FROM online WHERE name='";
strcat(ccmd,val["name"].asString().c_str());
strcat(ccmd,"';");
if(mysql_real_query(Mysql_sever._mpcon,ccmd,strlen(ccmd)))
{
cerr<<"login::select fail;errno:"<<errno<<endl;
return;
}
Mysql_sever._mp_res = mysql_store_result(Mysql_sever._mpcon);
if(Mysql_sever._mp_row = mysql_fetch_row(Mysql_sever._mp_res))
{ //判断是否重复登录
_str = "login repeat";
Json::Value root;
root["reason"] = _str;
if(-1 == send(_fd,root.toStyledString().c_str(),strlen(root.toStyledString().c_str()),0))
{
cerr<<"login::repeat;errno:"<<errno<<endl;
return;
}
return;
}
//将name pw加入到数据库online中
char cmd1[100] = "INSERT INTO online VALUE('";
char buff[128] = {0};;
sprintf(buff,"%d",_fd);
strcat(cmd1,buff);
strcat(cmd1,"','");
strcat(cmd1,val["name"].asString().c_str());
strcat(cmd1,"');");
cout<<cmd1<<endl;
if(mysql_real_query(Mysql_sever._mpcon,cmd1,strlen(cmd1)))
{
cerr<<"onine::insert fail;errno:"<<errno<<endl;
return;
}
Mysql_sever._mp_res = mysql_store_result(Mysql_sever._mpcon);
//在离线列表查找此人是否存在
char cmd_outline[128] = "SELECT *from outline where des_name='";
strcat(cmd_outline,val["name"].asString().c_str());
strcat(cmd_outline,"';");
cout<<cmd_outline<<endl;
_str = "login success";
if(mysql_real_query(Mysql_sever._mpcon,cmd_outline,strlen(cmd_outline)))
{
cerr<<"outline select fail;errno:"<<errno<<endl;
return;
}
//若存在将离线消息发送给他
Mysql_sever._mp_res = mysql_store_result(Mysql_sever._mpcon);
while(Mysql_sever._mp_row = mysql_fetch_row(Mysql_sever._mp_res))
{
val["content"] = Mysql_sever._mp_row[2];
char buf[128];
strcpy(buf,_str.c_str());
strcat(buf," ");
strcat(buf,Mysql_sever._mp_row[0]);
strcat(buf,":");
strcat(buf,val["content"].asString().c_str());
strcat(buf," ");
_str = buf;
}
}
else
{
_str = "login fail";
}
Json::Value root;
root["reason"] = _str;
if(-1 == send(_fd,root.toStyledString().c_str(),strlen(root.toStyledString().c_str()),0))
{
cerr<<"login::send reason fail;errno:"<<errno<<endl;
return;
}
//发送完离线消息再将他从离线列表中删除
char del_cmd[128] = "DELETE FROM outline WHERE des_name='";
strcat(del_cmd,val["name"].asString().c_str());
strcat(del_cmd,"';");
cout<<del_cmd<<endl;
if(mysql_real_query(Mysql_sever._mpcon,del_cmd,strlen(del_cmd)))
{
cerr<<"outline del fail;errno:"<<errno<<endl;
return;
}
Mysql_sever._mp_res = mysql_store_result(Mysql_sever._mpcon);
}
void Login::response()
{}
getlist.h
#ifndef GETLIST
#define GETLIST
#include <iostream>
#include "View.h"
#include <string>
using namespace std;
class Get_list:public View
{
public:
void process(int fd,char *json);
void response();
private:
int _fd;
string _str;
};
#endif
getlist.cpp
#include <iostream>
#include <memory.h>
#include <arpa/inet.h>
#include "View.h"
#include "control.h"
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <json/json.h>
#include <errno.h>
#include <string.h>
#include <string>
#include "getlist.h"
#include "mysql.h"
using namespace std;
extern Mysql Mysql_sever;
char buff[128] = {0};
void Get_list::process(int fd,char *json)
{
if(NULL == json)
{
cerr<<"json is null;errno:"<<errno<<endl;
return;
}
cout<<"Get_list begin"<<endl;
_fd = fd;
//解析json
Json::Value val;
Json::Reader read;
if(-1 == read.parse(json,val))
{
cerr<<"Get_list::read fail;errno:"<<errno<<endl;
return;
}
//查找在线名单
char cmd[100] = "SELECT name FROM online;";
if(mysql_real_query(Mysql_sever._mpcon,cmd,strlen(cmd)))
{
cerr<<"select fail;errno:"<<errno<<endl;
return ;
}
Mysql_sever._mp_res = mysql_store_result(Mysql_sever._mpcon);
Json::Value root;
memset(buff,0,strlen(buff));
while(Mysql_sever._mp_row = mysql_fetch_row(Mysql_sever._mp_res))
{
strcat(buff,Mysql_sever._mp_row[0]);
strcat(buff," ");
}
root["reason"] = buff;
//发送在线列表
if(-1 == send(_fd,root.toStyledString().c_str(),strlen(root.toStyledString().c_str()),0))
{
cerr<<"list::send reason fail;errno:"<<errno<<endl;
return;
}
}
void Get_list::response()
{
}
talk_one.h
#ifndef TALK_ONE
#define TALK_ONE
#include "View.h"
class Talk_one:public View
{
public:
void process(int fd,char *json);
void response();
private:
int _fd;
string _str;
};
#endif
talk_one.cpp
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <json/json.h>
#include <errno.h>
#include <string.h>
#include <string>
#include <iostream>
#include "login.h"
#include "mysql.h"
#include "talk_one.h"
using namespace std;
extern Mysql Mysql_sever;
void Talk_one::process(int fd,char *json)
{
if(NULL == json)
{
cerr<<"json is null;errno:"<<errno<<endl;
return;
}
cout<<"Talk_one::begin"<<endl;
_fd = fd;
//解析json
Json::Value val;
Json::Reader read;
if(-1 == read.parse(json,val))
{
cerr<<"read fail;errno:"<<errno<<endl;
return;
}
//name
//在user表中查找name
char user_cmd[128] = "SELECT * FROM user WHERE name='";
strcat(user_cmd,val["name"].asString().c_str());
strcat(user_cmd,"';");
if(mysql_real_query(Mysql_sever._mpcon,user_cmd,strlen(user_cmd)))
{
cerr<<"talk_one::user select fail;errno:"<<errno<<endl;
return;
}
Mysql_sever._mp_res = mysql_store_result(Mysql_sever._mpcon);
if(!(Mysql_sever._mp_row = mysql_fetch_row(Mysql_sever._mp_res)))
{
//如果好友不存在,则发送出错
Json::Value root;
_str = "someone not in user";
root["reason"] = _str;
if(-1 == send(_fd,root.toStyledString().c_str(),strlen(root.toStyledString().c_str()),0))
{
cerr<<"talk_one::::send reason fail;errno:"<<errno<<endl;
return;
}
return;
}
char cmd[100] = "SELECT *FROM online WHERE name='";
strcat(cmd,val["name"].asString().c_str());
strcat(cmd,"'; ");
cout<<cmd<<endl;
if(mysql_real_query(Mysql_sever._mpcon,cmd,strlen(cmd)))
{
cerr<<"select fail;errno:"<<errno<<endl;
return;
}
//在登录列表中根据fd查找自己的名字
Mysql_sever._mp_res = mysql_store_result(Mysql_sever._mpcon);
if((Mysql_sever._mp_row = mysql_fetch_row(Mysql_sever._mp_res)))
{
int online_fd = atoi(Mysql_sever._mp_row[0]);
char on_cmd[128] = "SELECT * FROM online WHERE fd='";
char cuff[128] = {0};
sprintf(cuff,"%d",_fd);
strcat(on_cmd,cuff);
strcat(on_cmd,"';");
if(mysql_real_query(Mysql_sever._mpcon,on_cmd,strlen(on_cmd)))
{
cerr<<"talk_one::fd in online fail;errno:"<<errno<<endl;
return;
}
Mysql_sever._mp_res = mysql_store_result(Mysql_sever._mpcon);
if(Mysql_sever._mp_row = mysql_fetch_row(Mysql_sever._mp_res))
{
//如果这个人存在在在线列表中,则发送在线消息
Json::Value root;
char eurr[128] = {0};
strcat(eurr,Mysql_sever._mp_row[1]);
strcat(eurr,":");
strcat(eurr,val["content"].asString().c_str());
root["reason"] = eurr;
if(-1 == send(online_fd,root.toStyledString().c_str(),strlen(root.toStyledString().c_str()),0))
{
cerr<<"oneline::send fail;errno:"<<errno<<endl;
return;
}
}
}
else
{
//将name_src name_des,message加入到数据库outline中
char buff0[128];
sprintf(buff0,"%d",_fd);
char online_cmd[100] = "SELECT *FROM online WHERE fd='";
strcat(online_cmd,buff0);
strcat(online_cmd,"';");
cout<<online_cmd<<endl;
if(mysql_real_query(Mysql_sever._mpcon,online_cmd,strlen(online_cmd)))
{
cerr<<"select fail;errno:"<<errno<<endl;
return;
}
Mysql_sever._mp_res = mysql_store_result(Mysql_sever._mpcon);
if((Mysql_sever._mp_row = mysql_fetch_row(Mysql_sever._mp_res)))
{
char cmd1[100] = "INSERT INTO outline VALUE('";
// cout<<"insert outline:::"<<cmd1<<endl;
strcat(cmd1,Mysql_sever._mp_row[1]);
strcat(cmd1,"','");
char buff[128] = {0};
strcat(cmd1,val["name"].asString().c_str());
strcat(cmd1,"','");
strcat(cmd1,val["content"].asString().c_str());
strcat(cmd1,"');");
cout<<cmd1<<endl;
if(mysql_real_query(Mysql_sever._mpcon,cmd1,strlen(cmd1)))
{
cerr<<"select fail;errno:"<<errno<<endl;
return;
}
Mysql_sever._mp_res = mysql_store_result(Mysql_sever._mpcon);
}
}
}
void Talk_one::response()
{
//用json将消息打包,发送给客户端
Json::Value root;
root["reason"] = _str;
if(-1 == send(_fd,root.toStyledString().c_str(),strlen(root.toStyledString().c_str()),0))
{
cerr<<"login::send reason fail;errno:"<<errno<<endl;
return;
}
}
talk_group.h
#ifndef TALK_GROUP
#define TALK_GROUP
#include "View.h"
class Talk_group:public View
{
public:
void process(int fd,char *json);
void response();
private:
int _fd;
string _str;
};
#endif
talk_group.cpp
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <json/json.h>
#include <errno.h>
#include <string.h>
#include <string>
#include <iostream>
#include "login.h"
#include "mysql.h"
#include "talk_group.h"
using namespace std;
extern Mysql Mysql_sever;
void Talk_group::process(int fd,char *json)
{
if(NULL == json)
{
cerr<<"json is null;errno:"<<errno<<endl;
return;
}
cout<<"Talk_group::begin"<<endl;
_fd = fd;
//解析json
Json::Value val;
Json::Reader read;
if(-1 == read.parse(json,val))
{
cerr<<"read fail;errno:"<<errno<<endl;
return;
}
char str[128];
strcpy(str,val["name"].asString().c_str());
char *p = strtok(str,",");
char pp[128] = {0};
while(p)
{
memset(pp,0,128);
strcpy(pp,p);
p = strtok(NULL,",");
val["name"] = pp;
//user select
char user_cmd[100] = "SELECT *FROM user WHERE name='";
strcat(user_cmd,val["name"].asString().c_str());
strcat(user_cmd,"'; ");
if(mysql_real_query(Mysql_sever._mpcon,user_cmd,strlen(user_cmd)))
{
cerr<<"select fail;errno:"<<errno<<endl;
return;
}
Mysql_sever._mp_res = mysql_store_result(Mysql_sever._mpcon);
if((Mysql_sever._mp_row = mysql_fetch_row(Mysql_sever._mp_res)))
{
char cmd[100] = "SELECT *FROM online WHERE name='";
strcat(cmd,val["name"].asString().c_str());
strcat(cmd,"'; ");
cout<<cmd<<endl;
if(mysql_real_query(Mysql_sever._mpcon,cmd,strlen(cmd)))
{
cerr<<"select fail;errno:"<<errno<<endl;
return;
}
Mysql_sever._mp_res = mysql_store_result(Mysql_sever._mpcon);
if((Mysql_sever._mp_row = mysql_fetch_row(Mysql_sever._mp_res)))
{
//strcat(eurr,root["content"].asString().c_str());
int online_fd = atoi(Mysql_sever._mp_row[0]);
char on_cmd[128] = "SELECT * FROM online WHERE fd='";
char cuff[128] = {0};
sprintf(cuff,"%d",_fd);
strcat(on_cmd,cuff);
strcat(on_cmd,"';");
if(mysql_real_query(Mysql_sever._mpcon,on_cmd,strlen(on_cmd)))
{
cerr<<"talk_one::fd in online fail;errno:"<<errno<<endl;
return;
}
Mysql_sever._mp_res = mysql_store_result(Mysql_sever._mpcon);
if(Mysql_sever._mp_row = mysql_fetch_row(Mysql_sever._mp_res))
{
Json::Value root;
char eurr[128] = {0};
strcat(eurr,Mysql_sever._mp_row[1]);
strcat(eurr,":");
strcat(eurr,val["content"].asString().c_str());
root["reason"] = eurr;
if(-1 == send(online_fd,root.toStyledString().c_str(),strlen(root.toStyledString().c_str()),0))
{
cerr<<"oneline::send fail;errno:"<<errno<<endl;
return;
}
}
}
else
{
//将name_src name_des,message加入到数据库outline中
char buff0[128];
sprintf(buff0,"%d",_fd);
char online_cmd[100] = "SELECT *FROM online WHERE fd='";
strcat(online_cmd,buff0);
strcat(online_cmd,"';");
if(mysql_real_query(Mysql_sever._mpcon,online_cmd,strlen(online_cmd)))
{
cerr<<"select fail;errno:"<<errno<<endl;
return;
}
Mysql_sever._mp_res = mysql_store_result(Mysql_sever._mpcon);
if((Mysql_sever._mp_row = mysql_fetch_row(Mysql_sever._mp_res)))
{
char cmd1[100] = "INSERT INTO outline VALUE('";
// cout<<"insert outline:::"<<cmd1<<endl;
strcat(cmd1,Mysql_sever._mp_row[1]);
strcat(cmd1,"','");
char buff[128] = {0};
strcat(cmd1,val["name"].asString().c_str());
strcat(cmd1,"','");
strcat(cmd1,val["content"].asString().c_str());
strcat(cmd1,"');");
if(mysql_real_query(Mysql_sever._mpcon,cmd1,strlen(cmd1)))
{
cerr<<"select fail;errno:"<<errno<<endl;
return;
}
Mysql_sever._mp_res = mysql_store_result(Mysql_sever._mpcon);
}
}
}
else
{
Json::Value root;
char cu[128] = {0};
strcat(cu,val["name"].asString().c_str());
strcat(cu," is not in user");
_str = cu;
root["reason"] = _str;
if(-1 == send(_fd,root.toStyledString().c_str(),strlen(root.toStyledString().c_str()),0))
{
cerr<<"login::send reason fail;errno:"<<errno<<endl;
return;
}
}
}
}
void Talk_group::response()
{
}
exit.h
#ifndef EXIT
#define EXIT
#include "View.h"
class Exit:public View
{
public:
void process(int fd,char *json);
void response();
private:
int _fd;
string _str;
};
#endif
exit.cpp
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <json/json.h>
#include <errno.h>
#include <string.h>
#include <string>
#include <iostream>
#include "login.h"
#include "mysql.h"
#include "exit.h"
using namespace std;
extern Mysql Mysql_sever;
void Exit::process(int fd,char *json)
{
if(NULL == json)
{
cerr<<"json is null;errno:"<<errno<<endl;
return;
}
cout<<"exit::begin"<<endl;
_fd = fd;
//解析json
Json::Value val;
Json::Reader read;
if(-1 == read.parse(json,val))
{
cerr<<"read fail;errno:"<<errno<<endl;
return;
}
//name pw
//在数据库中查找name所对应的pw都是否正确
char buff[128] ={0};
sprintf(buff,"%d",_fd);
char cmd[100] = "DELETE FROM online WHERE fd='";
strcat(cmd,buff);
strcat(cmd,"';");
cout<<cmd<<endl;
if(mysql_real_query(Mysql_sever._mpcon,cmd,strlen(cmd)))
{
cerr<<"select fail;errno:"<<errno<<endl;
return;
}
Mysql_sever._mp_res = mysql_store_result(Mysql_sever._mpcon);
}
void Exit::response()
{
}
public.h
#ifndef PUBLIC_H
#define PUBLIC_H
enum MSG_TYPE
{
REASON_TYPE_REGISTER,
REASON_TYPE_LOGIN,
REASON_TYPE_LIST,
REASON_TYPE_TALK,
REASON_TYPE_GROUP,
REASON_TYPE_EXIT,
};
#endif
客户端:
main.cpp
#include<iostream>
#include <signal.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <json/json.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include "fun.h"
using namespace std;
int fd = -1;//定义全局fd
int main(int argc,char* argv[])
{
signal(SIGINT,do_exit);
//绑定信号处理函数(do_exit);
if(argc < 3)
{
cerr<<"cmd is not enough;errno:"<<errno<<endl;
return 0;
}
//分离ip地址和端口号
char* ip = argv[1];
short port = atoi(argv[2]);
//链接服务器
fd = socket(AF_INET, SOCK_STREAM, 0);
if(-1 == fd)
{
cerr<<"fd creat fail;errno:"<<errno<<endl;
return 0;
}
struct sockaddr_in cli;
cli.sin_family = AF_INET;
cli.sin_port = htons(port);
cli.sin_addr.s_addr = inet_addr(ip);
//连接服务器
if(-1 == connect(fd, (struct sockaddr*)&cli, sizeof(cli)))
{
cerr<<"clifd connect fail;errno:"<<errno<<endl;
return 0;
}
//用户登录文件
while(1)
{
//让用户选择服务
cout<<"请输入你要选择的选项:"<<endl;
cout<<"1.register 2.login 3.exit"<<endl;
int a;
cin>>a;
switch(a)
{
case 1:
do_register(fd);
break;
case 2:
do_login(fd);
break;
case 3:
do_exit(fd);
break;
default:
cout<<"error"<<endl;
break;
}
}
return 0;
}
fun.h
#ifndef FUN_H
#define FUN_H
void do_register(int sockfd);//注册函数
void do_login(int sockfd);//登录函数
void do_get_list(int sockfd);//获取好友列表函数
void do_talk_to_one(int sockfd);//一对一聊天
void do_talk_to_group(int sockfd);//群聊
void do_exit(int sockfd);//下线函数
#endif
fun.cpp
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <string>
#include <assert.h>
#include <json/json.h>
#include <errno.h>
#include <arpa/inet.h>
#include "fun.h"
#include "pub.h"
#include <pthread.h>
using namespace std;
extern int fd;
//用户注册
void do_register(int sockfd)
{
//让用户输入name pw
cout<<"请输入您的姓名:";
char name[128] = {0};
cin>>name;
cout<<"请输入您的密码:";
char pw[128] = {0};
cin>>pw;
//打包数据(类型,名字,密码)
Json::Value val;
val["reason_type"] = REASON_TYPE_REGISTER;
val["name"] = name;
val["pw"] = pw;
//发送到服务器
if(-1 == send(sockfd,val.toStyledString().c_str(),strlen(val.toStyledString().c_str()),0))
{
cerr<<"send reason fail;errno:"<<errno<<endl;
return ;
}
//接受服务器消息(判断success/error)
char arr[128] = {0};
if(0<recv(sockfd,arr,127,0))
{
//解析包
Json::Value root;
Json::Reader read;
if(-1 == read.parse(arr,root))
{
cerr<<"register fail;errno:"<<errno<<endl;
return;
}
cout<<"reason:"<<root["reason"].asString()<<endl;
}
}
//启动一个线程,专门接受服务器发来的所有消息
void *function(void *arg)
{
while(1)
{
int pth_fd = (int) arg;
char arr[128] = {0};
if(0<recv(pth_fd,arr,127,0))
{
//解析
Json::Value root;
Json::Reader read;
if(-1 == read.parse(arr,root))
{
cerr<<"register fail;errno:"<<errno<<endl;
exit(1);
}
else
{
cout<<root["reason"].asString()<<endl;
}
}
else
{
cerr<<"login:: recv fail;errno:"<<errno<<endl;
exit(1);
}
}
}
//用户登录
void do_login(int sockfd)
{
//用户输入name pw
cout<<"请输入您的姓名:"<<endl;
char name[128] = {0};
cin>>name;
cout<<"请输入您的密码:"<<endl;
char pw[128] = {0};
cin>>pw;
//Json打包数据
Json::Value val;
val["reason_type"] = REASON_TYPE_LOGIN;
val["name"] = name;
val["pw"] = pw;
//发送包
if(-1 == send(sockfd,val.toStyledString().c_str(),strlen(val.toStyledString().c_str()),0))
{
cerr<<"send reason fail;errno:"<<errno<<endl;
return ;
}
//接受服务器消息(判断success/error)
char arr[128] = {0};
if(0<recv(sockfd,arr,127,0))
{
//解析
Json::Value root;
Json::Reader read;
if(-1 == read.parse(arr,root))
{
cerr<<"register fail;errno:"<<errno<<endl;
return;
}
else
{
const char * back = root["reason"].asString().c_str();
cout<<root["reason"].asString()<<endl;
if(strncmp(back,"login success",13)==0)
{
//启动线程,接受服务器消息
pthread_t id;
int th = pthread_create(&id,NULL,function,(void*)sockfd);
while(1)
{
sleep(1);
//用户选择列表
cout<<"1.get list 2. talk to one 3.talk to group 4.exit"<<endl;
int ch;
cin>>ch;
switch(ch)
{
case 1:
do_get_list(sockfd);break;
case 2:
do_talk_to_one(sockfd);break;
case 3:
do_talk_to_group(sockfd);break;
case 4:
do_exit(sockfd);break;
default:
cout<<"errno"<<endl;break;
}
}
}
}
}
}
//用户获取好友在线列表
void do_get_list(int sockfd)
{
Json::Value val;
//将类型打包
val["reason_type"] = REASON_TYPE_LIST;
//发送到服务器
if(-1 == send(sockfd,val.toStyledString().c_str(),strlen(val.toStyledString().c_str()),0))
{
cerr<<"send reason fail;errno:"<<errno<<endl;
return;
}
}
//与好友一对一聊天
void do_talk_to_one(int sockfd)
{
cout<<" 请输入您将要聊天的对象:"<<endl;
char arr[128] = {0};
cin>>arr;
while(1)
{
cout<<"请输入您要发送的数据(结束输入“over”):"<<endl;
char brr[128] = {0};
cin>>brr;
if(strcmp(brr,"over") == 0)
{
break;
}
//将消息类型,名字,消息进行打包
Json::Value val;
val["reason_type"] = REASON_TYPE_TALK;
val["name"] = arr;
val["content"] = brr;
//发送到服务器
if(-1 == send(sockfd,val.toStyledString().c_str(),strlen(val.toStyledString().c_str()),0))
{
cerr<<"send reason fail;errno:"<<errno<<endl;
}
}
}
//与好友群聊
void do_talk_to_group(int sockfd)
{
cout<<" 请输入您将要聊天的对象:(以','隔开)"<<endl;
char arr[128] = {0};
cin>>arr;
while(1)
{
cout<<"请输入您要发送的数据(结束输入“end”):"<<endl;
char brr[128] = {0};
cin>>brr;
if(strcmp(brr,"end") == 0)
{
break;
}
//将类型,要聊天的对象,消息打包
Json::Value val;
val["reason_type"] = REASON_TYPE_GROUP;
val["name"] = arr;
val["content"] = brr;
//发送到服务器
if(-1 == send(sockfd,val.toStyledString().c_str(),strlen(val.toStyledString().c_str()),0))
{
cerr<<"send reason fail;errno:"<<errno<<endl;
}
}
}
//用户下线
void do_exit(int sockfd)
{
Json::Value val;
val["reason_type"] = REASON_TYPE_EXIT;
if(-1 == send(fd,val.toStyledString().c_str(),strlen(val.toStyledString().c_str()),0))
{
cerr<<"send reason fail;errno:"<<errno<<endl;
return;
}
close(fd);
exit(0);
}
完结
测试