workermen+php 聊天室(二)

workermen (二)

(一)实现注册

user表

字段名称 类型 注释
id int 自增id
username varchar 名字
password varchar 密码

注册

register.html


<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>注册title>
    
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
head>

<body>
    <div style="width:600px;height:500px;margin: 30px auto;border:1px solid rgb(51, 23, 13);">
        <h1 style="text-align: center">注册h1>
        <form action="register.php" method="POST">
            <div class="form-group">
                <label for="exampleInputEmail1">用户名label>
                <input type="username" name="username" class="form-control" id="exampleInputEmail1" placeholder="username">
            div>
            <div class="form-group">
                <label for="exampleInputPassword1">密码label>
                <input type="password" name="password" class="form-control" id="exampleInputPassword1" placeholder="Password">
            div>
            <button type="submit" class="btn btn-primary" style="margin: 30px 270px;">注册button>
        form>
    div>
body>

html>

register.php

    $pdo = new \PDO('mysql:host=127.0.0.1;dbname=chat', '用户名', '密码');
    $pdo->exec('SET NAMES utf8');   //编码格式
	//接收值
    $username = $_POST['username'];  
    $password = md5($_POST['password']);
	//插入
    $sql = "insert into user(username,password) values('$username','$password')";
    $c = $pdo->exec($sql);
    // 判断是否成功
    if($c){
        echo "";
        exit;
       }

演示:

1542112916995

(二)、登录及首页

示例代码:


<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>聊天室title>
    <link rel="stylesheet" type="text/css" href="css/chat.css" />
    <style>
        span {
            color: #999;
            margin-left: 10px;
        }
    style>
head>

<body class="keBody">
    <div id="app">
        <div class="kePublic">
            
            <div class="content">
                <div class="chatBox">
                    <div class="chatLeft">
                        <div class="chat01">
                            <div class="chat01_title">
                                <ul class="talkTo">
                                    <li>
                                        <a href="javascript:;">{{ messageList.username }}a>
                                        <a @click="logout" href="javascript:;">退出a>
                                    li>
                                ul>
                                <a class="close_btn" href="javascript:;">a>
                            div>
                            <div class="chat01_content" style="padding: 10px;" id="chat01_content">
                                <dl v-for="(v,k) in messageList" :key="k">
                                        <dt><strong>{{v.username}}strong><time>{{ v.datetime }}time> 说:dt>
                                        <dd>{{ v.content }}dd>
                                dl>
                            div>
                        div>
                        <div class="chat02">
                            <div class="chat02_title">
                                <label class="chat02_title_t">
                                    <a target="_blank">聊天记录a>
                                label>
                                <div class="wl_faces_box">
                                    <div class="wl_faces_content">
                                        <div class="title">
                                            <ul>
                                                <li class="title_name">常用表情li>
                                                <li class="wl_faces_close">
                                                    <span> span>
                                                li>
                                            ul>
                                        div>
                                        <div class="wl_faces_main">
                                            <ul>
                                                <li>
                                                    <a href="javascript:;">
                                                        <img src="img/emo_01.gif" />
                                                    a>
                                                li>
                                                <li>
                                                    <a href="javascript:;">
                                                        <img src="img/emo_02.gif" />
                                                    a>
                                                li>
                                                <li>
                                                    <a href="javascript:;">
                                                        <img src="img/emo_03.gif" />
                                                    a>
                                                li>

                                            ul>
                                        div>
                                    div>
                                    <div class="wlf_icon">
                                    div>
                                div>
                            div>
                            <div class="chat02_content">
                                <textarea id="textarea" v-model="content" placeholder="请输入内容按enter键快速发消息">textarea>
                            div>
                            <div class="chat02_bar">
                                <ul>
                                    <li style="left: 20px; top: 10px; padding-left: 30px;">
                                        apppws创建li>
                                    <li style="right: 5px; top: 5px;">
                                        <img @click="send" src="img/send_btn.jpg" id="send_btn">
                                    li>
                                ul>
                            div>
                        div>
                    div>
                    <div class="chatRight">
                        <div class="chat03">
                            <div class="chat03_title">
                                <label class="chat03_title_t">成员列表label>
                            div>
                            <div class="chat03_content">
                                
                                <select v-model="to">
                                    <option value="">发给所有用户option>
                                    <option :value="k" v-for="(v,k) in userList">{{v}}option>
                                select>
                            div>
                        div>
                    div>
                    <div style="clear: both;">
                    div>
                div>
            div>
            
            
            <div :class="{'login':true,'hide':layerHide}">
                <h1>登录h1>
                <div><input v-model="username" type="text" placeholder="输入用户名">div>
                <div><input v-model="password" type="password" placeholder="输入密码">div>
                <div><input @click="dologin" type="button" value="登录">div>
            div>
            
            <div :class="{'layer':true,'hide':layerHide}">div>
        div>
    div>

body>

html>
<script src="./axios.min.js">script>
<script src="./vue.min.js">script>
<script>
    new Vue({
        el: '#app',
        data: {
            messageList: [],  //消息列表
            userList: [],       // 在线用户列表  
            message: '',       // 消息框中的内容
            ws: null,           // websocket 对象
            layerHide: false,   // 是否隐藏登录框
            host: '127.0.0.1:8484',    // 服务器地址
            username: '',    // 当前用户名
            password: '',
            to: '',
            content: ''
        },
        methods: {
            // 登录
            dologin: function () {
                axios.post('http://localhost:9999/login.php', {
                    username: this.username,
                    password: this.password
                }).then(function (res) {
                    console.log(res.data);
                    if (res.data.code == 200) {
                        localStorage.setItem('jwt_token', res.data.jwt)
                        this.layerHide = true; // 隐藏登陆框
                        location.href = "index.html"
                    }
                    else {
                        alert(res.data.error)
                    }
                })

            },
            // 退出
            logout: function () {
                // 断开连接
                this.ws.close()
                localStorage.removeItem('jwt_token')
                location.href = "index.html"
            },
            // 发送消息
            send: function () {
                // 判断消息是发给谁的
                if (this.to == '') {
                    // 群发:
                    this.ws.send('all:' + this.content);
                } else {
                    // 发给某个人
                    this.ws.send(this.to + ':' + this.content);
                }
                this.content = ''
            },
            open: function () {
                alert('连接成功');
            },
            // 收到消息时调用
            ws_message: function (e) {
                // 解析JSON
                let data = JSON.parse(e.data)
                // 根据消息的类型发处理消息
                if (data.type == 'users'){
                    this.userList = data.users
                }
                else{
                    this.message=data.ws_message
                }
                this.messageList.push(data) 
                  

            },
        },

        // 页面初始化
        created: function () {
            var token = localStorage.getItem('jwt_token')
            if (token == undefined)
                alert('请登录');
            else {
                this.layerHide = true; // 隐藏登陆框
                // 连接聊天服务器
                this.ws = new WebSocket('ws://127.0.0.1:8484?token=' + token)
                this.ws.onopen = this.open
                this.ws.onmessage = this.ws_message
                this.ws.onerror = this.error
            }
        },
    })

script>

显示:

1542113240859

登录服务的代码:

login.php

 
// 引入自动加载的 扩展包
require('./vendor/autoload.php');
// 生成令牌
use \Firebase\JWT\JWT;

// 连接数据库
$pdo = new \PDO('mysql:host=127.0.0.1;dbname=chat', 'root', '');
$pdo->exec('SET NAMES utf8');
// 接收原始数据
$post = file_get_contents('php://input');
// 把JSON转成数组
$_POST = json_decode($post, TRUE);
// 查询数据库
$stmt = $pdo->prepare("select * from user where username=? and password=?");
$stmt->execute([
    $_POST['username'],
    md5($_POST['password'])
]);
// 取出来所有信息
$user = $stmt->fetch(PDO::FETCH_ASSOC);
// var_dump($user);exit;
if($user)
{
    $key = 'abcd1234';
    $now = time();
    $data = [
        'id' => $user['id'],
        'name' => $user['username'],
    ];
    // var_dump($data);exit;
    // 为这个数据生成令牌
    $jwt = JWT::encode($data, $key);
    // 返回 JSON 数据
    echo json_encode([
        'code'=>'200',
        'jwt'=>$jwt,
    ]);
}
else
{
    // 返回 JSON 数据
    echo json_encode([
        'code'=>'403',
        'error'=>'用户名或者密码错误!',
    ]);
}

*里面包含lwt令牌

下载:composer require firebase/php-jwt

*vue.js的下载

查看及安装:https://cn.vuejs.org/

*axios.js的使用

安装及下载:https://www.kancloud.cn/yunye/axios/234845

(三)、实现服务器

start.php


use Workerman\Worker;
use Firebase\JWT\JWT;
// 引入workerman 自动加载
require_once __DIR__ . '/Workerman-master/Autoloader.php';
require('./vendor/autoload.php');

//保存所有用户
$allUsers = [];
// 客户端用户数据
$userConn = [];
// 有连接时调用
function connect($connection)
{
    $connection->onWebSocketConnect = function ($connection, $http_header) {
        global $allUsers, $userConn, $worker;

        // 解析jwt令牌
        try {
            $key = 'abcd1234';
            $data = JWT::decode($_GET['token'], $key, array('HS256'));
            // 把id和name保存到这个连接上
            $connection->uid = $data->id;
            $connection->uname = $data->name;
            // 保存当前连接到所有用户的数组中
            $allUsers[$data->id] = $data->name;
            $userConn[$data->id] = $connection;
            // 如果用户连接成功  就通知所有其他客户端有新的客户端连接
            foreach ($worker->connections as $v) {
                $v->send(json_encode([
                    'username' => $data->name,
                    'content' => '加入了聊天室',
                    'datetime' => date('Y-m-d H:i'),
                    'type' => 'users',
                    'users' => $allUsers
                ]));
            }
        } catch (\Firebase\JWT\ExpiredException $e) {
            // 关闭连接
            $connection->close();
        } catch (\Exception $e) {
            // 关闭连接
            $connection->close();
        }

    };
}

// 当收到数据时调用
function message($connection, $data)
{
    // var_dump($data);
    global $worker, $allUsers;
    
    // 从消息中解析出第一个 :前面的内容  判断是单发还是群发
    // 将字符串转为数组
    $ret = explode(':', $data);
    // 取出第一个元素 并去掉:前面的内容
    $code = $ret[0];
    unset($ret[0]);
    // 再把数组拼成字符串
    $rawData = implode(':', $ret);
    // 判断第一个元素
    if ($code == "all") {
        // 群发
        foreach ($worker->connections as $v) {
            $v->send(json_encode([
                'username' => $connection->uname,
                'content' => $rawData,
                'datetime' => date('Y-m-d H:i'),
                'type' => 'users',
                'users' => $allUsers
            ]));
        }
    } else {
        // 引进保存客户端与对应用户id的数组
        global $userConn;
        $userConn[$code]->send(json_encode([
            'username' => $connection->uname,
            'datetime' => date('Y-m-d H:i'),
            'type' => 'message',
            'content' => $rawData,
            'message' => $rawData
        ]));
    }
}
// 当有客户端断开连接时调用
function close($connection, $data)
{
    global $allUsers, $worker; 
    // 从用户列表数组中删除当前退出的用户
    unset($allUsers[$connection->id]);
    // 给所有用户发消息
    foreach ($worker->connections as $v) {
        $v->send(json_encode([
            'username' => $data->name,
            'content' => '退出了聊天室',
            'datetime' => date('Y-m-d H:i'),
            'type' => 'users',
            'users' => $allUsers
        ]));
    }
}


//创建一个workerman 的监听端口号
$worker = new Worker('websocket://0.0.0.0:8484');

//进程 
$worker->count = 1;

// 设置回调函数
$worker->onConnect = 'connect';
$worker->onMessage = 'message';
$worker->onClose = 'close';
// 运行
$worker->runAll();

*启动:php start.php start

1542114062772

最终结果: 可以互相通信

1542114106189

1542114147608

源码:https://github.com/apppws/chatroom

*温馨提示:有什么问题或者有好的建议请发评论。

你可能感兴趣的:(workermen)