目次
socket.io の概要
サーバー側プログラムを実行します
index.html 内
client.js 内
ホームページ バックエンド開発 PHPチュートリアル socket.io を使用して複数人チャット ルームを実装する (Nodejs に基づく)

socket.io を使用して複数人チャット ルームを実装する (Nodejs に基づく)

Jun 20, 2016 pm 01:00 PM
Socket

socket.io を使用して複数人チャット ルームを実装します (Nodejs ベース)

socket.io の概要

WebSocket を導入する新しい機能があります。WebSocket の内部実装原理については、この記事を参照してください。この記事では、プロトコルに従って、データのヘッダーを最初から作成する方法について説明します。フレームが解析され、WebSocket が構築されます。コードは短いですが、WebSocket の原理をよく反映しています。

この機能は、ブラウザとサーバー間の TCP 接続に基づいた双方向チャネルを提供します。ただし、すべてのブラウザが WebSocket 機能をサポートしているわけではないため、ブラウザ間の差異を解消し、開発者に統一されたインターフェイスを提供するために、socket.io モジュールが導入されました。 WebSocket をサポートしていないブラウザでは、socket.io が AJAX ロング ポーリング、JSONP ポーリングなどの他の通信方法にダウングレードされる可能性があります。

モジュールのインストール

新しい package.json ファイルを作成し、ファイルに次の内容を書き込みます:

{
  "name": "socketiochatroom",
  "version": "0.0.1",
  "dependencies": {
    "socket.io": "*",
    "express":"*"
  }
}
ログイン後にコピー
npm install 
ログイン後にコピー

この文を実行すると、ノードはnpmからsocket.ioとexpressモジュールをダウンロードします。

サーバー側の実装

index.js ファイルをフォルダーに追加し、ファイルに次の内容を書き込みます:

/**
 * Created by bamboo on 2016/3/31.
 */

var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);
app.get('/', function (req, res) {
    "use strict";
    res.end("<h1>socket server</h1>")
});

/*在线人员*/
var onLineUsers = {};
/* 在线人数*/
var onLineCounts = 0;

/*io监听到存在链接,此时回调一个socket进行socket监听*/
io.on('connection', function (socket) {
    console.log('a user connected');
    /*监听新用户加入*/
    socket.on('login', function (user) {
        "use strict";
        //暂存socket.name 为user.userId;在用户退出时候将会用到
        socket.name = user.userId;
        /*不存在则加入 */
        if (!onLineUsers.hasOwnProperty(user.userId)) {
            //不存在则加入
            onLineUsers[user.userId] = user.userName;
            onLineCounts++;
        }
        /*一个用户新加入,向所有客户端监听login的socket的实例发送响应,响应内容为一个对象*/
        io.emit('login', {onLineUsers: onLineUsers, onLineCounts: onLineCounts, user: user});
        console.log(user.userName, "加入了聊天室");//在服务器控制台中打印么么么用户加入到了聊天室
    });
    /*监听用户退出聊天室*/
    socket.on('disconnect', function () {
        "use strict";
        if (onLineUsers.hasOwnProperty(socket.name)) {
            var user = {userId: socket.name, userName: onLineUsers[socket.name]};
            delete onLineUsers[socket.name];
            onLineCounts--;

            /*向所有客户端广播该用户退出群聊*/
            io.emit('logout', {onLineUsers: onLineUsers, onLineCounts: onLineCounts, user: user});
            console.log(user.userName, "退出群聊");
        }
    })
    /*监听到用户发送了消息,就使用io广播信息,信息被所有客户端接收并显示。注意,如果客户端自己发送的也会接收到这个消息,故在客户端应当存在这的判断,是否收到的消息是自己发送的,故在emit时,应该将用户的id和信息封装成一个对象进行广播*/
    socket.on('message', function (obj) {
        "use strict";
        /*监听到有用户发消息,将该消息广播给所有客户端*/
        io.emit('message', obj);
        console.log(obj.userName, "说了:", obj.content);
    });
});
/*监听3000*/
http.listen(3000, function () {
    "use strict";
    console.log('listening 3000');
});
ログイン後にコピー

サーバー側プログラムを実行します

node index.js
ログイン後にコピー

出力

listening 3000
ログイン後にコピー

この時点で、ブラウザで localhost:3000 を開くと、次の結果が表示されます:

その理由は、コード内でルーティングのみが次のように設定されているためです

app.get('/', function (req, res) {
    "use strict";
    res.end("<h1>socket server</h1>")
});
ログイン後にコピー

サーバー側は主にsocketioサービスを提供しており、ルーティングの設定は行いません。

クライアント実装

クライアント上に次のディレクトリとファイルを作成します。この中の json3.min.js はインターネットからダウンロードできます。
クライアント
- - - client.js
- - -index.html
- - - json3.min.js
- - - style.css

index.html 内

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="format-detection" content="telephone=no"/>
    <meta name="format-detection" content="email=no"/>
    <title>1301群聊</title>
    <link rel="stylesheet" type="text/css" href="./style.css"/>
    <script src="http://realtime.plhwin.com:3000/socket.io/socket.io.js"></script>
    <script src="./json3.min.js"></script>
</head>
<body>
<div id="loginbox">
    <div style="width: 260px;margin: 200px auto;">
        输入你在群聊中的昵称
        <br/>
        <br/>
        <input type="text" style="width:180px;" placeholder="请输入用户名" id="userName" name="userName"/>
        <input type="button" style="width: 50px;" value="提交" onclick="CHAT.userNameSubmit();"/>
    </div>
</div>

<div id="chatbox" style="display: none;">
    <div style="background: #3d3d3d;height: 28px;width: 100%;font-size: 12px">
        <div style="line-height: 28px;color:#fff;">
            <span style="text-align: left;margin-left: 10px;">1301群聊</span>
            <span style="float: right;margin-right: 10px"><span id="showUserName"></span>|
            <a href="javascript:;" onclick="CHAT.logout()" style="color: #fff;">退出</a></span>
        </div>
    </div>
    <div id="doc">
        <div id="chat">
            <div id="message" class="message">
                <div id="onLineCounts"
                     style="background: #EFEFF4; font-size: 12px;margin-top: 10px;margin-left: 10px;color: #666;">
                </div>
            </div>
            <div class="input-box">
                <div class="input">
                    <input type="text" maxlength="140" placeholder="输入聊天内容 " id="content" name="content" >
                </div>
                <div class="action">
                    <button type="button" id="mjr_send" onclick="CHAT.submit();">提交</button>
                </div>
            </div>
        </div>
    </div>
</div>
<script type="text/javascript" src="./client.js"></script>
</body>
</html>
ログイン後にコピー

client.js 内

/**
 * Created by bamboo on 2016/3/31.
 */
 /*即时运行函数*/
(function () {
    "use strict";
    var d = document,
        w = window,
        dd = d.documentElement,
        db = d.body,
        dc = d.compatMode === "CSS1Compat",
        dx = dc ? dd : db,
        ec = encodeURIComponent,
        p = parseInt;
    w.CHAT = {
        msgObj: d.getElementById("message"),
        screenHeight: w.innerHeight ? w.innerHeight : dx.innerHeight,
        userName: null,
        userId: null,
        socket: null,
        /*滚动条始终在最底部*/
        scrollToBottom: function () {
            w.scrollTo(0, this.msgObj.clientHeight);
        },
        /*此处仅为简单的刷新页面,当然可以做复杂点*/
        logout: function () {
           // this.socket.disconnect();
            w.top.location.reload();
        },
        submit: function () {
            var content = d.getElementById('content').value;
            if (content != '') {
                var obj = {
                    userId: this.userId,
                    userName: this.userName,
                    content: content
                };
                //如在服务器端代码所说,此对象就行想要发送的信息和发送人组合成为对象一起发送。
                this.socket.emit('message', obj);
                d.getElementById('content').value = '';
            }
            return false;
        },
        /**客户端根据时间和随机数生成ID,聊天用户名称可以重复*/
        genUid: function () {
            return new Date().getTime() + "" + Math.floor(Math.random() * 889 + 100);
        },
        /*更新系统信息
        主要是在客户端显示当前在线人数,在线人列表等,当有新用户加入或者旧用户退出群聊的时候做出页面提示。*/
        updateSysMsg: function (o, action) {
            var onLineUsers = o.onLineUsers;
            var onLineCounts = o.onLineCounts;
            var user = o.user;
            //更新在线人数
            var userHtml = '';
            var separator = '';
            for (var key in onLineUsers) {
                if (onLineUsers.hasOwnProperty(key)) {
                    userHtml += separator + onLineUsers[key];
                    separator = '、';
                }
            }
            //插入在线人数和在线列表
            d.getElementById('onLineCounts').innerHTML = '当前共有' + onLineCounts + "在线列表: " + userHtml;

            //添加系统消息
            var html = '';
            html += '<div class="msg_system">';
            html += user.userName;
            html += (action === "login") ? "加入了群聊" : "退出了群聊";
            html += '</div>';
            var section = d.createElement('section');
            section.className = 'system J-mjrlinkWrap J-cutMsg';
            section.innerHTML = html;
            this.msgObj.appendChild(section);
            this.scrollToBottom();
        },

        /*用户提交用户名后,将loginbox设置为不显示,将chatbox设置为显示*/
        userNameSubmit: function () {
            var userName = d.getElementById('userName').value;
            if (userName != '') {
                d.getElementById('userName').value = '';
                d.getElementById('loginbox').style.display = 'none';
                d.getElementById('chatbox').style.display = 'block';
                this.init(userName);//调用init方法
            }
            return false;
        },
        //用户初始化
        init: function (userName) {
            //随机数生成uid
            this.userId = this.genUid();
            this.userName = userName;
            d.getElementById('showUserName').innerHTML = this.userName;//[newpidian]|[退出]
            this.scrollToBottom();
            //连接socketIO服务器,newpidian的IP地址
            this.socket = io.connect('192.168.3.155:3000');
            //向服务器发送某用户已经登录了
            this.socket.emit('login', {userId: this.userId, userName: this.userName});
            //监听来自服务器的login,即在客户端socket.emit('login ')发送后,客户端就会收到来自服务器的
            // io.emit('login', {onLineUsers: onLineUsers, onLineCounts: onLineCounts, user: user});
            /*监听到有用户login了,更新信息*/
            this.socket.on('login', function (o) {
                //更新系统信息
                CHAT.updateSysMsg(o, 'login');
            });
            /*监听到有用户logout了,更新信息*/
            this.socket.on('logout', function (o) {
                CHAT.updateSysMsg(o, 'logout');
            });
            //var obj = {
            //    userId: this.userId,
            //    userName: this.userName,
            //    content: content
            //};
            /*监听到有用户发送消息了*/
            this.socket.on("message", function (obj) {
                //判断消息是不是自己发送的
                var isMe = (obj.userId === CHAT.userId);
                var contentDiv = '<div>' + obj.content + '</div>';
                var userNameDiv = '<span>' + obj.userName + '</span>';
                var section = d.createElement('section');
                if (isMe) {
                    section.className = 'user';
                    section.innerHTML = contentDiv + userNameDiv;
                } else {
                    section.className = 'service';
                    section.innerHTML = userNameDiv + contentDiv;
                }
                CHAT.msgObj.appendChild(section);
                CHAT.scrollToBottom();
            });
        }
    }
    /*控制键键码值(keyCode)
     按键 键码  按键  键码  按键  键码  按键  键码
     BackSpace  8   Esc 27  Right Arrow 39  -_  189
     Tab    9   Spacebar    32  Dw Arrow    40  .>  190
     Clear  12  Page Up 33  Insert  45  /?  191
     Enter  13  Page Down   34  Delete  46  `~ 192
     Shift  16  End 35  Num Lock    144 [{  219
     Control    17  Home    36  ;:  186 \|  220
     Alt    18  Left Arrow  37  =+  187 ]}  221
     Cape Lock  20  Up Arrow    38  ,<  188 '"  222
     * */
    //通过“回车键”提交用户名
    d.getElementById('userName').onkeydown = function (e) {
        console.log(e);
        e = e || event;
        if (e.keyCode === 13) {
            CHAT.userNameSubmit();
        }
    };
    //通过“回车键”提交聊天内容
    d.getElementById('content').onkeydown = function (e) {
        e = e || event;
        if (e.keyCode === 13) {
            CHAT.submit();
        }
    };
})();
ログイン後にコピー


このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

AI Hentai Generator

AI Hentai Generator

AIヘンタイを無料で生成します。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

11ベストPHP URLショートナースクリプト(無料およびプレミアム) 11ベストPHP URLショートナースクリプト(無料およびプレミアム) Mar 03, 2025 am 10:49 AM

多くの場合、キーワードと追跡パラメーターで散らかった長いURLは、訪問者を阻止できます。 URL短縮スクリプトはソリューションを提供し、ソーシャルメディアやその他のプラットフォームに最適な簡潔なリンクを作成します。 これらのスクリプトは、個々のWebサイトにとって価値があります

Instagram APIの紹介 Instagram APIの紹介 Mar 02, 2025 am 09:32 AM

2012年のFacebookによる有名な買収に続いて、Instagramはサードパーティの使用のために2セットのAPIを採用しました。これらはInstagramグラフAPIとInstagram Basic Display APIです。

Laravelでフラッシュセッションデータを使用します Laravelでフラッシュセッションデータを使用します Mar 12, 2025 pm 05:08 PM

Laravelは、直感的なフラッシュメソッドを使用して、一時的なセッションデータの処理を簡素化します。これは、アプリケーション内に簡単なメッセージ、アラート、または通知を表示するのに最適です。 データは、デフォルトで次の要求のためにのみ持続します。 $リクエスト -

LaravelのバックエンドでReactアプリを構築する:パート2、React LaravelのバックエンドでReactアプリを構築する:パート2、React Mar 04, 2025 am 09:33 AM

これは、LaravelバックエンドとのReactアプリケーションの構築に関するシリーズの2番目と最終部分です。シリーズの最初の部分では、基本的な製品上場アプリケーションのためにLaravelを使用してRESTFUL APIを作成しました。このチュートリアルでは、開発者になります

Laravelテストでの簡略化されたHTTP応答のモッキング Laravelテストでの簡略化されたHTTP応答のモッキング Mar 12, 2025 pm 05:09 PM

Laravelは簡潔なHTTP応答シミュレーション構文を提供し、HTTP相互作用テストを簡素化します。このアプローチは、テストシミュレーションをより直感的にしながら、コード冗長性を大幅に削減します。 基本的な実装は、さまざまな応答タイプのショートカットを提供します。 Illuminate \ support \ facades \ httpを使用します。 http :: fake([[ 'google.com' => 'hello world'、 'github.com' => ['foo' => 'bar']、 'forge.laravel.com' =>

PHPのカール:REST APIでPHPカール拡張機能を使用する方法 PHPのカール:REST APIでPHPカール拡張機能を使用する方法 Mar 14, 2025 am 11:42 AM

PHPクライアントURL(CURL)拡張機能は、開発者にとって強力なツールであり、リモートサーバーやREST APIとのシームレスな対話を可能にします。尊敬されるマルチプロトコルファイル転送ライブラリであるLibcurlを活用することにより、PHP Curlは効率的なexecuを促進します

Codecanyonで12の最高のPHPチャットスクリプト Codecanyonで12の最高のPHPチャットスクリプト Mar 13, 2025 pm 12:08 PM

顧客の最も差し迫った問題にリアルタイムでインスタントソリューションを提供したいですか? ライブチャットを使用すると、顧客とのリアルタイムな会話を行い、すぐに問題を解決できます。それはあなたがあなたのカスタムにより速いサービスを提供することを可能にします

2025 PHP状況調査の発表 2025 PHP状況調査の発表 Mar 03, 2025 pm 04:20 PM

2025 PHP Landscape Surveyは、現在のPHP開発動向を調査しています。 開発者や企業に洞察を提供することを目的とした、フレームワークの使用、展開方法、および課題を調査します。 この調査では、現代のPHP Versioの成長が予想されています

See all articles