局域网聊天

服务器端:
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);
}

完结
测试

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值