实现原理
只有当客户端先对服务器发送online消息的时候,服务器才会把客户端加入到在线列表。当在线列表的用户发消息的时候,服务器会把消息广播给在线列表中的所有用户。而当用户输入offline时,表明自己要下线了,此时服务器把该用户踢出在线列表。此时的用户看不到公屏的信息也无法在发送信息。
上线步骤:
通信步骤:
下线步骤
只要把用户踢出在线列表,那么它就是离线了,因为服务器只关心在线列表中的客户。
服务器要做的事
1. 判断收到的消息是否是online或者offline
2. 收到online则把用户添加进在线列表,offline则移除在线列表。
3. 如果发送的消息不是offline,切用户在线,则对发送的消息进行广播,广播给在线列表的所有用户
客户端要做的事
1. 向服务器发送online申请上线
2. 主线程负责发送消息,不发也可以
3. 创建一个线程时时刻刻接收消息,收到消息即显示到自己的公屏上
server服务端代码实现
服务端需要有一个UserManage类,来管理在线用户,这也是我们的在线列表。这个类只有一个哈希表成员,用来管理在线的用户。还要提供四个成员函数,分别有上线,下线,判断是否在线,以及广播功能。
server.cc代码:
#include "server.hpp"
#include <memory>
#include <unistd.h>
#include <fcntl.h>
#include <vector>
#include <sys/wait.h>
#include <cstring>
#include "User.hpp"
UserManage um;
void ChatRoomMessage(int _sock,std::string ip,uint16_t port,std::string message)
{
//如果用户输入online,那么就把用户添加到在线列表
if(message == "online") um.online(port,ip);
//如果用户输入offline,那么把用户移除在线列表
if(message == "offline") um.offline(port,ip);
//用户在线才能广播消息
if(um.isonline(port,ip))
um.broadcastMessage(message,_sock,ip,port); //广播消息
}
int main(int argc , char* argv[])
{
if(argc != 2) //命令行参数不为2就退出
{
std::cout << "Usage : " << argv[0] << " bindport" << std::endl; //打印使用手册
exit(1);
}
uint16_t port = atoi(argv[1]); //命令行传的端口转换成16位整形
std::unique_ptr<UdpServer> s(new UdpServer(port,ChatRoomMessage)); //创建UDP服务器
s->init(); //初始化服务器,创建 + 绑定
s->start(); //运行服务器
}
server.hpp代码:
这个类主要是对服务器的封装,在收到消息后通过用户传入的callback函数进行回调处理。
#pragma once
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <iostream>
#include <unistd.h>
#include <arpa/inet.h>
#include <functional>
typedef std::function<void(int,std::string,uint16_t,std::string)> func_t;
class UdpServer
{
private:
int _sock;
uint16_t _port;
func_t _callback;
public:
UdpServer(