socket.ioサンプルプログラム


socket.ioはWeb applicationにおいて、双方向通信を可能にする便利なツールです。 色々なサイトでも紹介されいますが、 チャットアプリを例に、ここでは、apache2のリバースプロキシに対応した例を紹介します。

package.json

{
   "name": "chat",
   "version": "1.0.0",
   "description": "",
   "main": "server.js",
   "scripts": {
      "server": "node server.js"
   },
   "author": "",
   "license": "",
   "dependencies": {
      "express": "^4.18.1",
      "socket.io": "^4.5.1"
   }
}
	  

server.js

const app = express();
const PORT = 3000;
const http = require('http').Server(app);

http.listen(PORT, ()=>{ console.log('server listening. Port:' + PORT); });

let messages=[];

app.use(
    (req,res,next)=>{
        console.log({
            url:req.url,
            headers:req.headers
        });
        next();
    }
);

//
// client code
//
app.get('/index.html',
        (req,res)=>{  res.sendFile(__dirname+`/html/client.html` )}
       );

//
// soket communication
//
const io = require('socket.io')(http,{
    path:"/socket/"  // change path name to socket io
});
io.on('connection',socket=>{
    const room=process.argv[2] ? process.argv[2] : "Roomhogehoge"; //auth
    const remoteIP=socket.request.headers["x-remote-addr"]? socket.request.headers["x-remote-addr"].split(",")[0]: "undef";
    const from=`${decodeURI(socket.request.headers.from)}[${remoteIP}]`;
    if(decodeURI(socket.request.headers.room)===room){
        //room entry 
        (()=>{
            const msg={
                from,
                at    :(new Date()).toString(),
                message:`${from} enters the room.`
            };
            messages.map( msg=>{
                socket.emit("message",msg);
            });
            messages.push(msg);
            io.emit("message",msg);
        })();

        //room exit
        socket.on("disconnect",()=>{
            const msg={
                from,
                at  :(new Date()).toString(),
                message : `${from} exits from the room.`
            };
            messages.push(msg);
            io.emit("message",msg);
        })
        
        // message receive
        socket.on("message", msg=>{
            try{
                const _msg={
                    from,
                    at:(new Date()).toString(),
                    message:msg.message
                };
                messages.push(_msg);
                io.emit("message",_msg)
            }catch(e){
                console.log(e);
            }
        })
    }else{ // auth fail
        socket.emit("message",{
            from,
            at  :(new Date()).toString(),
            message : "Please specify the room id you want to enter like https://...../index.html?room=hoge&name=yourname"
        });
        socket.disconnect();
    }
});

	  

html/client.html

<html>
    <head>
        <meta charset=utf-8>
        <style>
         pre{
             margin:0px;
             font-size:10pt;
         }
         h3{
             margin:3px;
         }
        </style>
    </head>
    <html> 
        <body style="font-size:20pt">
            <h3>soket.ioを使ったチャットサンプル</h3>
            <div style="font-size:0.6em">(apache2の多段リバースプロキシ経由でnode.jsに接続)</div>
            <hr>
            <div style="width:90%; margin:auto">
                <textarea id="inputText" type="text" style="width:90%;height:100px; margin-bottom:5px; overflow:auto"></textarea>
                <button id="sendButton">送信 </button>
            </div>
            <div  id="messageList" style="width:90%; margin:auto;" />

            <script src="https://cdn.socket.io/4.1.2/socket.io.min.js"
                    integrity="sha384-toS6mmwu70G0fw54EGlWWeA4z3dyJ+dlXBtSURSKN4vyRFOcxd3Bzjj/AoOwY+Rg"
                    crossorigin="anonymous">
            </script>

            <script>

             function getParam(key){
                 try{
                     return window.location.search
                                  .replace("?","")
                                  .split("&")
                                  .reduce( (prev,param) =>{
                                      const [key,value]=param.split("=")
                                      prev[key]=value; // URI encoded value
                                      return prev;
                                  },{})[key];
                 }catch(e){
                     console.log(e);
                     return null
                 }
             }
             getParam();
             
             const room=getParam("room");
             const from=getParam("name");

           </script>
            
            <script>
             const path=window.location.href
                              .replace(window.location.origin,"")
                              .replace(/.index.html.*$/,"/socket/"); //socket path
             const socket = io(
                 {
                     forceNew : true,
                     path ,
                     extraHeaders:{ room, from }
                 });

             const addMessageList = (message) => {
                 const div   = document.createElement('div');
                 try{
                     const msgJson=JSON.parse(message);
                     div.innerHTML=`<div style="font-size:0.5em;color:green">${msgJson.from}@${msgJson.at}</div>`+
                                   `<div style="border:1px solid black;background-color:silver;padding:3px; width:100%; overflow:auto; padding:3px">`+
                                   `  <pre>${msgJson.message}</pre>`+
                                   `</div>`;
                 }catch(err){
                     div.append(message);
                 }
                 document.getElementById('messageList').prepend(div);
             };

             const sendMessage=(message)=>{
                 socket.emit('message', {from, message});
             };

             document.getElementById('sendButton').addEventListener('click', () => {
                 sendMessage(document.getElementById('inputText').value);
                 document.getElementById('inputText').value = '';
             });

             socket.on("message",msg=>{
                 addMessageList(typeof msg=="object" ? JSON.stringify(msg,null," "):msg);
             })
             
            </script>
        </body>
    </html>
      

.htaccess

RewriteEngine On
RewriteRule  .* - [env=remoteaddr:%{REMOTE_ADDR}]
RequestHeader add X-Remote-Addr %{remoteaddr}e
RewriteRule ^(.*)$  http://localhost:3000/$1   [P,L]
      

追加情報

バックヤードにmongoDBを使った例はこちら