“随心所语”

该项目使用的技术:
1.C++STL
2.生产者消费者模型
3.多线程技术,线程的同步与互斥
4.网络编程
5.开源jsoncpp库
6.ncurses库
7.自定义协议,登录注册认证
实现的基本想法:项目分可分为3个模块:
1.登录、注册和退出 2.用户发送消息,服务器接收 3.服务端的数据转发

1.登录和注册(TCP)
注册:将自己的注册信息通过TCP发给服务器,服务器接收下来并保存该用户的信息在用户信息管理的容器中,并且返回给用户的一个登录ID。
登录:输入ID和密码,然后将其发送给服务器,经过服务器验证并通过后,将用户的ID和地址信息保存在用户列表容器中,否则重新登录。
请求中的协议:当使用登录和注册功能的时候,向用户发送一个类似于简单HTTP协议的一个数据报,由服务器来判断是登录还是注册。包的组成:第一行为使用的方法(登录还是注册),第二行记录正文的长度,第三行为空行,区分报头和正文,第四行是正文。

2.发送数据(UDP)
(1)客户端将用户输入的数据发送给服务器
(2)服务器接收消息之后放入数据池中
3.数据转发
(1)服务器从数据池中取出数据
(2)取出用户在线列表,通过遍历将数据发送给所有在线洪湖
(3)客户端接收到服务器发送的数据,将其输出到屏幕上
注:当输入“ESC“的时候,服务器会在用户在线列表中删除这个用户,这个用户不会在收到消息,并向其他用户发送一条下线消息提醒。

ChatClient.hpp

#pragma once

#include <iostream>
#include <string>
#include <vector>
#include "ProtocolUtil.hpp"
#include "Message.hpp"
#include "Window.hpp"
#include <pthread.h>
#define TCP_PORT 8080
#define UDP_PORT 8888
class ChatClient;
struct ParamPair{
    Window *wp;
    ChatClient *cp;
};
class ChatClient{
    private:
	int tcp_sock;//tcp套接字
	int udp_sock;//udp套接字
	std::string peer_ip;
	
	std::string passwd;
	
	struct sockaddr_in server;
    public:
	std::string nick_name;
	std::string school;
	unsigned int id;
    public:
	ChatClient(std::string ip_):peer_ip(ip_)
	{
	    id = 0;
	    tcp_sock = -1;
	    udp_sock = -1;
	    server.sin_family = AF_INET;
	    server.sin_port = htons(UDP_PORT);
	    server.sin_addr.s_addr = inet_addr(peer_ip.c_str());
	}
	void InitClient()
	{
	    udp_sock = SocketApi::Socket(SOCK_DGRAM);
	}
	bool ConnectServer()
	{
	    tcp_sock = SocketApi::Socket(SOCK_STREAM);
	    return SocketApi::Connect(tcp_sock,peer_ip,TCP_PORT);
	}
	bool Register()//依据自定义协议和json串的序列化和反序列化
	{	//注册完成以后连接服务器  发送请求 
	    if( Util::RegisterEnter(nick_name,school,passwd) && ConnectServer()){
		Request rq;
		rq.method = "REGISTER\n";
		Json::Value value;
		value["name"] = nick_name;
		value["school"] = school;
		value["passwd"] = passwd;

		Util::Seralize(value,rq.text);//序列化
	
		rq.content_length = "Content_Length: ";
		rq.content_length += Util::IntToString((rq.text).size());
		rq.content_length += "\n";
		//向TCP发送请求
	   	Util::SendRequest(tcp_sock,rq);
		//接收请求
	        recv(tcp_sock,&id,sizeof(id),0);//返回注册成功后的id
		bool res = false; 
	        if(id >= 10000){//验证id是否符合标准
		    res = true;
		    std::cout<<"Register Success! Your Login ID Is: "<<id<<std::endl;
		}
		else{
		    std::cout<< "Register Failed! Code is : "<<id<<std::endl;
		}
		close(tcp_sock); 
	        return res;
	     }
	}
	bool Login()
	{    //登陆成功后 连接服务器 发送请求
	    if( Util::LoginEnter(id,passwd) && ConnectServer()){
		Request rq;
		rq.method = "LOGIN\n";
		Json::Value value;
		value["id"] = id;
		value["passwd"] = passwd;
	
		Util::Seralize(value,rq.text);//序列化
	
		rq.content_length = "Content_Length: ";
		rq.content_length += Util::IntToString((rq.text).size());
		rq.content_length += "\n";
		//向TCP发送请求
	   	Util::SendRequest(tcp_sock,rq);
		//接收请求
		unsigned int ret = 0;
		bool res = false;
	        recv(tcp_sock,&ret,sizeof(ret),0); 
	        if(ret >= 10000){//验证id是否符合标准
		     res = true;
		     std::string name_ = "None";
		     std::string school_ = "None";
		     std::string text_ = "I am Login! talk with me...";
		     unsigned int type_ = LOGIN_TYPE;
		     unsigned int id_ = ret;
		     Message m(name_,school_,text_,id_,type_);
		     std::string sendString;
		     m.ToSendString(sendString);
		     UdpSend(sendString);
		     std::cout<<"Login Success! Your Login ID Is: "<<ret<<std::endl;  
		}
		else{
		    std::cout<< "Login  Failed! Code is : "<<ret<<std::endl;
		}
		close(tcp_sock);
		return res; 
	    }
	}
	void UdpSend(const std::string &message)
	{
	    Util::SendMessage(udp_sock,message,server);
	}
	void UdpRecv(std::string &message)
	{
	    struct sockaddr_in peer;
	    Util::RecvMessage(udp_sock,message,peer);
	}
	static void *Welcome(void *arg)
	{
	    pthread_detach(pthread_self());//进行线程分离
	    Window *wp = (Window*)arg;
	    wp->Welcome();//调用欢迎条目的函数
	}
	static void *Input(void *arg)
	{
	    pthread_detach(pthread_self());
	    struct ParamPair *pptr = (struct ParamPair*)arg;
	    Window *wp = pptr->wp;
	    ChatClient *cp = pptr->cp;

	    wp->DrawInput();

	    std::string text;
	    for(;;){
	   	wp->GetStringFromInput(text);//从input窗口中获得字符串
	 			
		Message msg(cp->nick_name,cp->school,text,cp->id);
		std::string sendString;
		msg.ToSendString(sendString);
		cp->UdpSend(sendString);//发送字符串
	    }
	
	}
	void Chat()
	{
	    Window w;
	    pthread_t h,m,l;
	    
	    struct ParamPair pp = {&w,this};
	    pthread_create(&h,NULL,Welcome,&w);
	    pthread_create(&l,NULL,Input,&pp);
	
	    w.DrawOutput();
	    w.DrawOnline();
	    std::string recvString;
	    std::string showString;
	    std::vector<std::string> online;
	    for(;;){
		Message msg;
		UdpRecv(recvString);

		msg.ToRecvValue(recvString);//将收到的消息反序列化
		
		if( msg.Id() == id && msg.Type() == LOGIN_TYPE)
		{
		    nick_name = msg.NickName();
		    school = msg.School();
		}		
		showString = msg.NickName();
		showString += "-";
	    	showString += msg.School();

		std::string f = showString;//张三-北大
		
		if(msg.Type() == LOGINOUT_TYPE)
		{
		Util::delUser(online,f);
		}
		else	
		Util::addUser(online,f);
	    	showString +="# ";
	 	showString += msg.Text();
		w.PutMessageToOutput(showString);//向output窗口放数据
		
		w.PutUserToOnline(online);
		
	    }
	}
	~ChatClient()
	{
	}
};

ChatClient.cc

#include <iostream>
#include "ChatClient.hpp"


static void Usage(std::string proc)
{
    std::cout<<"Usage: "<<proc<<" peer_ip"<<std::endl;

}
static void Menu(int &s)
{

    std::cout<<"################################################"<<std::endl;
    std::cout<<"####  1. Register                  2.Login #####"<<std::endl;
    std::cout<<"####                               3.Exit  #####"<<std::endl;
    std::cout<<"################################################"<<std::endl;
    std::cout<<"Please Select:>";
    std::cin>>s;
}
// ./ChatClient ip
int main(int argc, char *argv[])
{
    if(argc != 2){
	Usage(argv[0]);
	exit(1);
    }
    ChatClient *cp = new ChatClient(argv[1]);
    cp->InitClient();//初始化客户端
    int select = 0;
    while(1){
    Menu(select);
    switch(select){
	case 1://Register
	    cp->Register();
	    break;
	case 2://Login
	      if(cp->Login()){
		cp->Chat();
		    
	    }else{
		std::cout<<"Login Failed!"<<std::endl;
	    }
	    break;
	case 3://Exit
	    exit(0);
	    break;
	default:
	    exit(1);
	    break;
	}
    }
    if(cp->ConnectServer()){
 	std::cout<<"connect success"<<std::endl;	
    }	

}

ChatServer.hpp

#pragma once
#include <iostream>
#include <pthread.h>
#include "ProtocolUtil.hpp"
#include "UserManager.hpp"
#include "Log.hpp"
#include "DataPool.hpp"
#include "Message.hpp"
class ChatServer;
class Param {
    public:
       ChatServer *sp;
       int sock;
       std::string ip;
       int port;
    public:
	Param(ChatServer *sp_,int &sock_,const std::string &ip_,const int &port_):
		sp(sp_),
		sock(sock_),
		ip(ip_),
		port(port_)
	{}
	~Param()
	{}
    
};
class ChatServer{
    private:
	int tcp_listen_sock;
    	int tcp_port;

	int udp_work_sock;
	int udp_port;

	UserManager um;
	DataPool pool;
    public:
	ChatServer(int tcp_port_ = 8080,int udp_port_ = 8888):
	    tcp_port(tcp_port_),
	    tcp_listen_sock(-1),
	    udp_port(udp_port_),
	    udp_work_sock(-1)
	{}
	void InitServer()
	{
  	    tcp_listen_sock = SocketApi::Socket(SOCK_STREAM);//创建套接字
  	    udp_work_sock = SocketApi::Socket(SOCK_DGRAM);
	    SocketApi::Bind(tcp_listen_sock,tcp_port);//绑定
	    SocketApi::Bind(udp_work_sock,udp_port);

	    SocketApi::Listen(tcp_listen_sock);
	    
	}
	unsigned int RegisterUser(const std::string &name,const std::string &school,const std::string &passwd)
	{
	    return um.Insert(name,school,passwd);//注册的用户的基本信息    
	}
	unsigned int LoginUser(const unsigned int &id, const std::string &passwd,const std::string &ip,int port)
	{
	    return um.Check(id,passwd);
	}
	//UDP
	void Product()
	{
	    std::string message;
	    struct sockaddr_in peer;
	    Util::RecvMessage(udp_work_sock,message,peer);//通过udp接收一个消息
	    std::cout<< "debug: recv message: "<<message<<std::endl;
	    if(!message.empty()){
			
		Message m;
		m.ToRecvValue(message);
		if(m.Type() == LOGIN_TYPE)
		{
	            um.AddOnLineUser(m.Id(),peer);//将该用户加入到用户列表中
		    std::string name_,school_;
		    um.GetUserInfo(m.Id(),name_,school_);//得到name school
		    Message new_msg(name_,school_,m.Text(),m.Id(),m.Type());//构建一个新的信息
		    new_msg.ToSendString(message); //序列化 		   
		}
		std::string logout = "ESC";
		if(m.Text() == logout)
		{
		    std::string text = "I have getting off line";
		    Message new_msg(m.NickName(),m.School(),text,m.Id(),LOGINOUT_TYPE);
		    
		    new_msg.ToSendString(message);
		    um.DelOnLineUser(m.Id());
		}
	 	pool.PutMessage(message);//假如消息不为空 向数据池中放入信息
	    }
	   
	}
	void Consume()
	{
	    std::string message;
	    pool.GetMessage(message);//从数据池中获得数据
	    std::cout<<"debug: send massage: "<<message<<std::endl;
	    auto online = um.OnLineUser();//获取用户在线列表
	    for(auto it = online.begin(); it != online.end(); it++){
		Util::SendMessage(udp_work_sock,message,it->second);//通过udp向在线列表中的用户发送信息
	    }
	}
	static void *HandlerRequest(void* arg)
	{
	    Param *p = (Param*)arg;
	    int sock = p->sock;
	    ChatServer *sp = p->sp;
	    std::string ip = p->ip;
	    int port = p->port;
	    delete p;
	    pthread_detach(pthread_self());
	    
            Request rq;
            Util::RecvRequest(sock,rq);//读请求 
            Json::Value root;
	    
	    LOG(rq.text,NORMAL);
	   
	    Util::UnSeralize(rq.text,root);// 将收到的字符串逆序列化
	    if(rq.method == "REGISTER"){
		std::string name = root["name"].asString();//作为字符串 asInt 作为整形
		std::string school = root["school"].asString();
		std::string passwd = root["passwd"].asString();
		unsigned int id = sp->RegisterUser(name,school,passwd);//注册的id
	        send(sock,&id,sizeof(id),0);//返回注册的id
	    }else if(rq.method == "LOGIN"){
		unsigned int id = root["id"].asInt();//取出id
		std::string passwd = root["passwd"].asString();//取出密码
		//检验,将用户放入在线列表中
		unsigned int ret = sp->LoginUser(id,passwd,ip,port);
		send(sock,&ret,sizeof(ret),0);
	    }       
	    close(sock);
	}
	void Start()
	{
	    std::string ip;
	    int port;
	    for(;;){
	        int sock = SocketApi::Accept(tcp_listen_sock,ip,port);
	        if(sock > 0){
		    std::cout <<"get a new client"<<ip<<":"<<port<<std::endl;
		   
		    Param *p = new Param(this,sock,ip,port); 
		    pthread_t tid;
		    pthread_create(&tid,NULL,HandlerRequest,p);
	        }
	    }
	}
	~ChatServer()
	{}

};

ChatServer.cc

#include <iostream>
#include "ChatServer.hpp"
static void Usage(std::string proc)
{
    std::cout<<"Usage: "<<proc<<" tcp_port udp_port"<<std::endl;

}
void *RunProduct(void *arg)
{
    pthread_detach(pthread_self());//线程分离
    ChatServer *sp = (ChatServer*)arg;
    for(;;){
	sp->Product();//生产	
    }
}
void *RunConsume(void *arg)
{
    pthread_detach(pthread_self());
    ChatServer *sp = (ChatServer*)arg;
    for(;;){
	sp->Consume();//消费
    }
}

int main(int argc, char *argv[])
{
    if(argc != 3){
	Usage(argv[0]);
	exit(1);
    }
    int tcp_port = atoi(argv[1]);
    int udp_port = atoi(argv[2]);

    ChatServer *sp = new ChatServer(tcp_port,udp_port);
    sp->InitServer();
    
    pthread_t c,p;
    pthread_create(&p,NULL,RunProduct,(void*)sp);
    pthread_create(&c,NULL,RunConsume,(void*)sp);
    sp->Start();
    
    return 0;
}

ProtocolUtil.hpp

#pragma once

#include <iostream>
#include <string>
#include <sstream>
#include <vector>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include "json/json.h"
#include "Log.hpp"
#define BACKLOG 5
#define MESSAGE_SIZE 1024 
class Request{
    public:
	std::string method;// REGISTER, LOGIN, LOGOUT
	std::string content_length;//报文的长度
	std::string blank;//空行
	std::string text;//正文
    public:
	Request():blank("\n")
	{}
	~Request()
	{}
};//定制一个简单的http报文
class Util{
    public:
    static bool RegisterEnter(std::string &n_,std::string &s_,std::string &passwd)
    {
	std::cout<<"Please Enter Nick Name: ";
	std::cin >>n_;
	std::cout<<"Please Enter School: ";
	std::cin >>s_;
	std::cout<<"Please Enter Passwd: ";
	std::cin >>passwd;
	std::string again;
	std::cout<<"Please Enter Passwd Again: ";
	std::cin >> again;
	if(passwd == again){
	    return true;
	}
	return false;
    }
    static bool LoginEnter(unsigned int &id,std::string &passwd)
    {
	std::cout<< "Please Enter Your ID: ";
	std::cin>>id;
	std::cout<< "Please Enter Your Passwd: ";
	std::cin>>passwd;
        return true;
    }
    static void Seralize(Json::Value &value,std::string &outString)
    {
	Json::FastWriter w;
	outString = w.write(value);//序列化
    }
    static void UnSeralize(std::string &inString,Json::Value &value)
    {
	Json::Reader r;
	r.parse(inString,value,false);//反序列化
    }
    static std::string IntToString(int x)
    {
	std::stringstream ss;
	ss << x;
	return ss.str();
    }
    static int StringToInt(std::string &str)
    {
 	int x;
	std::stringstream ss(str);
	ss >> x;
	return x;
    }
    static void RecvOneLine(int sock,std::string &outString)
    {
  	char c = 'x';
	while(c != '\n'){
	    ssize_t s = recv(sock,&c,1,0);
	    if(s > 0){
		if(c == '\n'){
		    break;
		}
		outString.push_back(c);
	}
	else{
	    break;
    	}
        }
    }
 	//TCP	
    static void RecvRequest(int sock,Request &rq)
    {
	RecvOneLine(sock,rq.method);
	RecvOneLine(sock,rq.content_length);
	RecvOneLine(sock,rq.blank);

	std::string &cl = rq.content_length;//获得这一行字符串 content_length: 55
	std::size_t pos = cl.find(": ");//找到“:”的位置准备获得后面的长度 
 	if(std::string::npos == pos){
	    return;//std::string::npos是一个常数 它等于size_type 类型
                   //可表示的最大数字,表示一个不存在的位置
	} 
	std::string sub = cl.substr(pos+2);//找到表示长度的字符串
	int size = StringToInt(sub);//将长度字符串转换成整形
	char c;//用作接受字符
	for(auto i = 0;i < size;i++)
	{
	    recv(sock,&c,1,0);//一次接受一个字符
	    (rq.text).push_back(c);//插入正文中
	}
	
    }
	static void SendRequest(int sock,Request &rq)
	{
	    std::string &method_ = rq.method;
	    std::string &c_l = rq.content_length;
	    std::string &b = rq.blank;
	    std::string &text = rq.text;
	    send(sock,method_.c_str(),method_.size(),0);
	    send(sock,c_l.c_str(),c_l.size(),0);
	    send(sock,b.c_str(),b.size(),0);
	    send(sock,text.c_str(),text.size(),0);
	}
	static void RecvMessage(int sock, std::string &message,struct sockaddr_in &peer)
	{
	    char msg[MESSAGE_SIZE];//定长的报文
	    socklen_t len = sizeof(peer);
	    ssize_t s = recvfrom(sock,msg,sizeof(msg)-1,0,\
		    (struct sockaddr*)&peer,&len);//接受报文
	    if(s <= 0){
		LOG("recvfrom message error",WARNING);
	    }
	    else{
		message = msg;
	    }
	}
	static void SendMessage(int sock, const std::string &message,struct sockaddr_in &peer)
	{
	    sendto(sock,message.c_str(),message.size(),0,\
		    (struct sockaddr*)&peer,sizeof(peer));//发送报文
	}
	
	static void addUser(std::vector<std::string> &online,std::string &f)
	{
	    for (auto it = online.begin();it != online.end(); it++)
	    {
	        if(*it == f){
		    return;
	        }
	    }
		online.push_back(f);
	}	
	static void delUser(std::vector<std::string> &online,std::string &f)
	{
	    for (auto it = online.begin();it != online.end();)
	    {
	        if(*it == f){
		    it = online.erase(it);
	        }
		else
		++it;
	    }
		return;
	}	
};

class SocketApi{
    public:
	static int Socket(int type)
	{
	   int sock = socket(AF_INET,type,0);
	   if(sock < 0){
	       LOG("socket error!",ERROR);
		exit(2);    
            }
	   
	}
	static void Bind(int sock,int port)
	{
	    struct sockaddr_in local;
	    local.sin_family = AF_INET;
	    local.sin_addr.s_addr = htonl(INADDR_ANY);
	    local.sin_port = htons(port);
	    
  	    if(bind(sock,(struct sockaddr*)&local,sizeof(local)) < 0)
		{
			LOG("socket error",ERROR);
			exit(3);
		
		}
	}
 	 static void Listen(int sock)
	{
	  if(listen(sock,BACKLOG) < 0){
	     LOG("Listen error",ERROR);
	     exit(4);   
	  }
	}
	static int Accept(int listen_sock,std::string &out_ip,int &out_port)
	{
	   struct sockaddr_in peer;
	   socklen_t len = sizeof(peer);
	   int sock = accept(listen_sock,(struct sockaddr*)&peer,&len);
	   if(sock < 0){
	       LOG("accept error",WARNING);
	       return -1;
   	   }
	   out_ip = inet_ntoa(peer.sin_addr);
	   out_port = htons(peer.sin_port);
	   return sock;
	}
	static bool Connect(const int &sock, std::string peer_ip,const int port)
	{
	    struct sockaddr_in peer;
	    peer.sin_family = AF_INET;
	    peer.sin_addr.s_addr = inet_addr(peer_ip.c_str());
	    peer.sin_port = htons(port);

	    if(connect(sock, (struct sockaddr*)&peer,sizeof(peer)) < 0 ){
		LOG("connect error",WARNING);
		return false;
	    }
	    return true;
	}

};

UserManager.hpp

#pragma once
#include <iostream>
#include <string>
#include <unordered_map>
#include <pthread.h>
class User{
    private:
	std::string nick_name;
	std::string school;
	std::string passwd;
    public:
	User()
	{
	}
	User(const std::string &n,const std::string &s,\
	   	const std::string pwd):
	    nick_name(n),
	    school(s),
	    passwd(pwd)
	{}
	bool IsPasswdTrue(const std::string &passwd_)
	{
	    return passwd == passwd_? true : false; 
	}
	std::string &GetNickName()
	{
	    return nick_name;
	}
	std::string &GetSchool()
	{
	    return school;
	}
	~User()
	{}    
};
class UserManager{
    private:
	unsigned int assgin_id;//用户申请的id
	std::unordered_map<unsigned int,User> users;//用户
	std::unordered_map<unsigned int,struct sockaddr_in> online_users;
	pthread_mutex_t lock;
	void Lock()
	{
 	    pthread_mutex_lock(&lock);
	}
	void UnLock()
	{
	    pthread_mutex_unlock(&lock);
	}
    public:
	UserManager():assgin_id(10000)
	{
	    pthread_mutex_init(&lock,NULL);
	}
	unsigned int Insert(const std::string &n,\
		const std::string &s,const std::string &p)
	{
	    Lock();//加锁  防止多个用户同时进行注册操作导致出现错误 保持一致性
	    unsigned int id = assgin_id++;//注册的id模式
	    User u(n,s,p);
	    if(users.find(id) == users.end()){
		users.insert({id,u});//假如用户中没有对应的id 那么就将该用户数据插入到用户中
		UnLock();
		return id;
	    }
	    UnLock();
	    return 1;
	}
	unsigned int Check(const int &id, const std::string &passwd)
	{
	    Lock();
	    auto user = users.find(id);
	    if(user != users.end()){//是否能在存储的用户信息中找到相应id
	        User &u = user->second;//取出密码
	        if(u.IsPasswdTrue(passwd)){//判断密码时候正确
		    UnLock();
		    return id;
	        }
	    }
	    UnLock();
	    return 2;
	}
	void GetUserInfo(const unsigned int &id, std::string &name_, std::string &school_)
	{
	    Lock();
	    name_ = users[id].GetNickName();
	    school_ = users[id].GetSchool();
	    UnLock();
	}
	void AddOnLineUser(unsigned int id, struct sockaddr_in &peer)
	{
	    Lock();
	    auto it = online_users.find(id);
	    if(it == online_users.end()){
		online_users.insert({id,peer});//假如用户在线列表中没有该用户则将该用户加入到用户列表中
	    }
		UnLock();
	}
	void DelOnLineUser(unsigned int id)
	{
	    Lock();
		online_users.erase(id);
		UnLock();
	}
	
	std::unordered_map<unsigned int,struct sockaddr_in> OnLineUser()
	{
	    Lock();
	    auto online = online_users;
	    UnLock();
	    return online;
	}
	
	~UserManager()
	{
 	    pthread_mutex_destroy(&lock);
	}	    
	    
};

Message.hpp

#pragma once

#include <iostream>
#include <string>
#include "ProtocolUtil.hpp"
#include "json/json.h"

#define NORMAL_TYPE 0
#define LOGIN_TYPE 1
#define LOGINOUT_TYPE 2
class Message{
    private:
	std::string nick_name;
	std::string school;
	std::string text;
	unsigned int id;
	unsigned int type;
    public:
	Message()
	{}
	Message(const std::string &n,const std::string &s,const std::string &t,const unsigned int &id, unsigned int type_ = NORMAL_TYPE)
	   : nick_name(n),
	    school(s),
	    text(t),
	    id(id),
	    type(type_)
	{}
	void ToSendString(std::string &sendString)
	{
	    Json::Value root;
	    root["name"] = nick_name;
	    root["school"] = school;
	    root["text"] = text;
	    root["id"] = id;
	    root["type"] = type;
	    Util::Seralize(root,sendString);//将要发送的信息进行序列化
	}
	void ToRecvValue(std::string &recvString)
	{
	    Json::Value root;
	    Util::UnSeralize(recvString,root);//将接收到的信息进行反序列化
	    nick_name = root["name"].asString();
	    school = root["school"].asString();
	    text = root["text"].asString();
	    id = root["id"].asInt();
	    type = root["type"].asInt();
	}
	const std::string &NickName()
	{
	    return nick_name;
	}
	const std::string &School()
	{
	    return school;
	}
	const std::string &Text()
	{
	    return text;
	}
	const unsigned int &Id()
	{
	    return id;
	}
	const unsigned int &Type()
	{
	    return type;
	}
	~Message()
	{
	}
};

DataPool.hpp

#pragma once
#include <iostream>
#include <vector>
#include <semaphore.h>
#include <string>
//只有空 或者满的情况才能让生产者和消费者的下标一样
//消费者不能超过生产者
//生产者不能超过消费者一个圈
class DataPool{
    private:
	std::vector<std::string> pool;
	int cap;
	//信号量:用来描述临界资源当中资源数目多少的 本质是一个计数器
	sem_t data_sem;
	sem_t blank_sem;
	int product_step;
	int consume_step;
    public:
	DataPool(int cap_ = 512):
	    cap(cap_),
	    pool(cap_)
	{
	    sem_init(&data_sem,0,0);//初始化data_sem 这些数据是消费者需要关心的,所以初始化为0
	    sem_init(&blank_sem,0,cap);//初始化blank_sem 这些空格子是生产者需要关心的,所以设置成最大容量
	    product_step = 0;
	    consume_step = 0;
	}
	void PutMessage(const std::string &msg)
	{
	    sem_wait(&blank_sem);//对blank_sem进行P操作
	    pool[product_step] = msg;//向pool中放入数据
	    product_step++;	  //向后面走
	    product_step %= cap;//不能越界 进行循环
	    sem_post(&data_sem);//对data_sem进行V操作
	}
	void GetMessage(std::string &msg)
	{
	    sem_wait(&data_sem);//对data_sem进行P操作
	    msg = pool[consume_step];//从pool中获得数据
	    consume_step++;	
	    consume_step %= cap;
	    sem_post(&blank_sem);//对blank_sem进行V操作
	}
	~DataPool()
	{
	    sem_destroy(&data_sem);//释放信号量
	    sem_destroy(&blank_sem);
	}
};

Window.hpp

#pragma once

#include <iostream>
#include <string>
#include <ncurses.h>
#include <vector>
#include <unistd.h>
#include <cstring>
#include <pthread.h>
class Window{
    public:
	WINDOW *header;
	WINDOW *output;
	WINDOW *online;
	WINDOW *input;
	pthread_mutex_t lock;
    public:
	Window()
	{
	    initscr();
	    curs_set(0);//隐藏光标
	    pthread_mutex_init(&lock,NULL);
	}
	void SafeWrefresh(WINDOW *w)
	{
	    pthread_mutex_lock(&lock);//加锁
	    wrefresh(w);//刷新窗口
	    pthread_mutex_unlock(&lock);//解锁
	}
	void DrawHeader()
	{
	    int h = LINES*0.2;
	    int w = COLS;
	    int y = 0;
	    int x = 0;
	    header = newwin(h,w,y,x);
	    box(header,0,0);
	    SafeWrefresh(header);//因为显示器是一个临界资源 多个线程控制的多个窗口同时刷新到显示器上可能会导致窗口变花	
	}
	void DrawOutput()
	{
	    int h = LINES*0.6;
	    int w = COLS*0.75;
	    int y = LINES*0.2;
	    int x = 0;
	    output = newwin(h,w,y,x);
	    box(output,0,0);
	    SafeWrefresh(output);	
	}

	void DrawOnline()
	{
	    
	    int h = LINES*0.6;
	    int w = COLS*0.25;
	    int y = LINES*0.2;
	    int x = COLS*0.75;
	    online = newwin(h,w,y,x);
	    box(online,0,0);
	    SafeWrefresh(online);	
	}
	void DrawInput()
	{	    
	    int h = LINES*0.2;
	    int w = COLS;
	    int y = LINES*0.8;
	    int x = 0;
	    input = newwin(h,w,y,x);
	    box(input,0,0);
	    std::string tips = "Please Enter# ";
	    PutStringToWin(input,2,2,tips);
	    SafeWrefresh(input);	
	}
	void GetStringFromInput(std::string &message)
	{
 	    char buffer[1024];
	    memset(buffer,0,sizeof(buffer));
	    wgetnstr(input,buffer,sizeof(buffer));//在input窗口中输入
	    message = buffer;
	    delwin(input);//删除不要的窗口
	    DrawInput();//重新绘制窗口
	}	
	void PutMessageToOutput(const std::string &message)
	{
	    static int line = 1;
	    int y,x;
	    getmaxyx(output,y,x);//获取窗口的高度和宽度
	    if(line > y-2){
		delwin(output);
		DrawOutput();
		line = 1;
	    }
	    PutStringToWin(output,line++,2,message);

	}
	void PutStringToWin(WINDOW *w,int y,int x,const std::string &message)
	{
	    mvwaddstr(w,y,x,message.c_str());
	    SafeWrefresh(w);
	}
	
	void PutUserToOnline(std::vector<std::string> &online_user)
	{
	    int size = online_user.size();
	    delwin(online);
	    DrawOnline();
	    for(auto i = 0; i < size; i++)
	    {
		PutStringToWin(online,i+1,2,online_user[i]);
	    }
	}
	void Welcome()
	{
	    const std::string welcome = "welcome to my chat system!";
	    int num = 1;
	    int x,y;
	    int dir = 0;//从左往右 否则等于1
 	    for( ; ; )
	    {
		DrawHeader();
 		getmaxyx(header,y,x);
		PutStringToWin(header,y/2,num,welcome);
		if(num > x - welcome.size() - 3){
		    dir = 1;
		}
		if(num <= 1){
		    dir = 0;
		}
		if(dir == 0){
		    num++;
		}else{
		    num--;
		}
		usleep(100000);
		delwin(header);
	    }
	}
	~Window()
	{
	    endwin();//释放窗口
	    pthread_mutex_destroy(&lock);//销毁锁
	}
};

Log.hpp

#pragma once
#include <iostream>
#include <string>

#define NORMAL 0
#define WARNING 1
#define ERROR 2
const char* log_level[]={
    "Normal",
    "Warning",
    "Error",
    NULL,
};
void Log(std::string msg,int level,std::string file,int line)
{
    std::cout<<'['<<msg<<']'<<'['<<log_level[level]<<']'<<":"<<\
             file<<":"<<line<<std::endl;

}
#define LOG(msg,level) Log(msg,level,__FILE__,__LINE__)

展开阅读全文

没有更多推荐了,返回首页