PHP使用swoole实现多人在线聊天室

centos7,PHP7.3 ,swoole4.4,redis,扩展自行安装;

服务器买的腾讯云,配置了免费的证书

以下是前端代码,。。。非正吖八斤的前端,代码水平有限,

<html>
<head>
<meta charset="utf-8"/>
<link rel="stylesheet" type="text/css" href="./public/css/client.css">
<title>NetChat</title>
</head>
<body>
<div id="wrap">
    <!-- 个人信息 -->
	<div id="login">
	    <div id="login_user_img"></div>
		<div id="login_user"></div>
		<div style="width:100%;height:20px;color:#fff;position:relative;">
			<span id="qunliao">广场</span>
			<span class="red_cicle" id="red_0"></span>
		</div>
	</div>
     <!--用户列表 -->
	<div id="user_list">

	</div>

	<!--聊天框 -->
	<div id="content_box">
		<div id="ct_top">广场</div>
		<div id="content_0" class="content">
		</div>
		<div id="ct_file">
			<div id="emoji_box"></div>
			<span class="file_img" title="表情"></span>
			<span class="file_img" title="文件">
				<input type="file" name="sendFile" id="sendFile">
			</span>
			<span class="file_img" title="聊天记录"></span>
			<span class="file_img" title="截图"></span>
			<span class="file_img" title="视频"></span>
			<div id="msgnotice"></div>
		</div>
		<div contentEditable="true" id="input_box"></div>
		<!-- <textarea id="input_box"></textarea> -->
		<div id="sb_box">
			<input type="button" value="发送" id="sb">
		</div>
	</div>
</div>
<div class="mouseright">
	<div class="mouselist" data-index="0">@召唤他</div>
	<div class="mouselist" data-index="0">发送消息</div>
</div>
</body>
</html>

界面丑哭,想写的时候和朋友微信聊天,就懒得想了,照着画吧。。。

线上体验地址:https://yechunlin.com/NetChat/index.php,最近加了简陋的用户登录,可酌情考虑是否注册 :),配有简单的校验

下面是服务端配置;原生写的

<?php
class WebSocketServer
{
	public  $ws;
	static  $ssl = true;
	private $connectConf = array('ip'=>'', 'port'=> 8888);

	public function __construct($conf = array()){
		$conf = array_merge($this->connectConf, $conf);
		$tcp = SWOOLE_SOCK_TCP;
		if($this::$ssl){
			$tcp = SWOOLE_SOCK_TCP | SWOOLE_SSL;
		}
		$this->ws = new swoole_websocket_server($conf['ip'],$conf['port'],SWOOLE_PROCESS,$tcp);

		$this->ws->table = $this->setTable();//设置内置表
		$this->ws->redis = $this->setRedis();//设置Redis
		//配置
		$setConf = array(
                                'task_worker_num' => 2,
                                'worker_num'      => 2,
                                'daemonize'       => 1,
                                'heartbeat_check_interval' => 300,
                                'heartbeat_idle_time'      => 600
		);
		if($this::$ssl){
			$setConf['ssl_cert_file'] = '/usr/local/ssl/Nginx/*.crt';
			$setConf['ssl_key_file'] = '/usr/local/ssl/Nginx/*.key';
		}
		$this->ws->set($setConf);		

		$this->ws->on('start', [$this,'onStart']);
		$this->ws->on('open', [$this,'onOpen']);
		$this->ws->on('message', [$this,'onMessage']);
		$this->ws->on('task', [$this,'onTask']);
		$this->ws->on('finish', [$this,'onFinish']);
		$this->ws->on('close', [$this,'onClose']);

		$this->ws->start();
	}

	private function setTable(){
		$table  = new swoole_table(4096);
		$table->column('fd', swoole_table::TYPE_INT);
		$table->column('userid', swoole_table::TYPE_INT);
		$table->column('nickname', swoole_table::TYPE_STRING,64);
		$table->column('img', swoole_table::TYPE_STRING,128);
		$table->create();
		return $table;
	}
	private function setRedis(){
		$redis = new Redis;
		$redis->connect('127.0.0.1', 6379);
		return $redis;
	}

	public function onStart(){
		//启动触发
		echo "服务启动\r\n";
	}
	public function onOpen($ws, $request){
		//var_dump($request);
		$result = $this->checkSign($ws, $request->get['signature']);
		if($result){
			//echo $request->fd." Joined successfully\r\n";
		}else{
			echo $ws->close($request->fd);
		}
	}
	public function onMessage($ws, $frame){
		parse_str($frame->data, $data);//解析字符串为数组
		$data['id'] = $frame->fd;
		$task_id = $ws->task($data);//投递task异步任务
	}
	public function onTask($ws, $task_id, $from_id, $data){
		$this->workerFun($ws,$data);
		$ws->finish('ok');
	}
	public function onFinish($ws, $task_id, $data){
		//echo $data."\r\n";
	}
	public function onClose($ws, $fd){
		$client = $ws->table->get($fd);
		if($client){
			$data = array(
				'flag'=>'leave',
				'id'  =>$fd,
				'nickname'=>$client['nickname']
			);
			$ws->table->del($fd);
			$this->sendMsg($ws,$ws->table, $data);//通知其他人,某人下线
			//echo "client:{$fd} has closed\r\n";
		}
	}
	public function workerFun($ws,$data){
		$redis = $ws->redis;
		$old_clients = $ws->table;
		//新人
		if($data['flag'] == 'new'){
			$clients = array();
			foreach($ws->table as $key => $val){
				$clients[$key] = $val;
			}
			$old_clients = $clients;
			$clients[$data['id']] = array(
				'fd'       => $data['id'],
				'userid'   => $data['userId'],
				'nickname' => $data['nickname'],
				'img'      => $data['img']
			);
			$ws->table->set($data['id'],$clients[$data['id']]);
			$data['clients'] = $clients;
			$ws->push($data['id'], json_encode($data));//新人进来单独发送一份消息
			unset($data['clients']);
		}

		//@召唤
		if(isset($data['msg'])){
			preg_match_all('/data-to="(.*?)"/', $data['msg'], $arr_to);
			if(!empty($arr_to[1])){
				$data['at'] = $arr_to[1];
				$data['msg'] .= "&nbsp";
			}
		}
	
		$data['img'] = $ws->table->get($data['id'],'img');
		$data['nickname'] = $ws->table->get($data['id'],'nickname');

		//连续五分钟内无交互,显示一次时间
		if(!$redis->get('web_socket_time')){
			$redis->set('web_socket_time', 1, 300);
			$data['date'] = date('Y-m-d H:i:s');
		}
		$redis->set('web_socket_time', 1, 300);
		if(isset($data['private'])){
			//私聊
			$sl_arr[$data['id']] = $data['id'];
			$sl_arr[$data['for_id']] = $data['for_id'];
			$fd     = $ws->table->get($data['id'],'fd');
			$for_fd = $ws->table->get($data['for_id'],'fd');
			$this->sendMsg($ws,$sl_arr,$data);
			$this->savemsg($ws,$data, 2);
		}else{
			//群聊
			if($old_clients){	
				$this->sendMsg($ws,$old_clients,$data);
				$this->savemsg($ws,$data);
			}
		}
	}

	//发送数据
	public function sendMsg($ws,$clients,$data){
		foreach($clients as $fd => $name){
        		$ws->push($fd, json_encode($data));
		}	
	}

	//验证
	private function checkSign($ws, $token){
		$redis = $ws->redis;
		return $redis->get(base64_decode($token));
	}

	//消息记录
	function savemsg($ws,$data,$type=1){
		if(in_array($data['flag'],array('new','leave'))) return;
		$userId = $ws->table->get($data['id'],'userid');
		$for_userId = 0;
		$private_key = 0;
		$key = 'chat_log';//消息key
		if($type > 1){
			$for_userId = $ws->table->get($data['for_id'],'userid');
			$private_key = $userId + $for_userId;
		}
		//获取消息类型
		$msg_type = 1;
		if(isset($data['at'])){
			$msg_type = 2;
		}
		if($data['flag'] ==='file'){
			$msg_type = 3;
		}
		$msg = array(
			'type'      => $type,
			'private_key'=>$private_key,
			'msg_type'  => $msg_type,
			'time'      => time(),
			'user_id'   => $userId,
			'dated'     => date('Y-m-d H:i:s'),
			'text'      => $data['msg'],
			'to_user_id'=> $for_userId
		);
		$ws->redis->lPush($key, serialize($msg));
	}

}
new WebSocketServer();

启动 php webSocketServer.php;

功能比较少,emoji表情,文件发送(支持很多类型,大小没做限制,几个G都行,前端做了分片处理,有封装在js-upload.js里),音视频功能因为腾讯的产品过期了,比较尴尬。。。。,消息记录等

其他代码就不贴的,仅供参考,写个demo记一下,资源我上传了,需要的可自取

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值