質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
Node.js

Node.jsとはGoogleのV8 JavaScriptエンジンを使用しているサーバーサイドのイベント駆動型プログラムです。

Socket.IO

Socket.IOはNode.js上で動くライブラリであり、すべてのブラウザとモバイルデバイスでリアルタイムのアプリを作動させる事を目的としています。

Q&A

解決済

1回答

4038閲覧

socket.ioのイベントの処理を1度だけ行われるようにしたい

mussi425

総合スコア11

Node.js

Node.jsとはGoogleのV8 JavaScriptエンジンを使用しているサーバーサイドのイベント駆動型プログラムです。

Socket.IO

Socket.IOはNode.js上で動くライブラリであり、すべてのブラウザとモバイルデバイスでリアルタイムのアプリを作動させる事を目的としています。

0グッド

0クリップ

投稿2020/06/21 00:57

編集2020/06/21 10:20

お世話になっております。
node.jsのsocket.ioを使用し、WEBアプリを実装しようと考えおります。
あるイベントを受け取ったときに1度だけ処理を実現させたいです。
そこで、フラグで処理を管理しようとしております。
ただ、イベントがほぼ同時に2回以上起こった場合、フラグを操作する前にそれらの処理がすり抜けてしまい、処理が2度以上行われることがあるのではないかと思い、質問させていただきました。
そこで、お伺いしたいのですが、

  • イベントがほぼ同時に2回以上起こった場合、処理が2度以上行われることがあるかどうか。
  • 上記のことが起こる場合、回避策があるかどうか

をご教授いただけると幸いです。
大変お手数ですがよろしくお願いいたします。

node

1'use strict'; 2 3// モジュール 4const express = require( 'express' ); 5const http = require( 'http' ); 6const socketIO = require( 'socket.io' ); 7 8// オブジェクト 9const app = express(); 10const server = http.Server( app ); 11const io = socketIO( server ); 12 13// 定数 14const PORT = process.env.PORT || 8080; 15 16/* 処理を管理するためのフラグ */ 17let onceFlag = true; 18 19io.on( 20 socket.on( 21 'once', 22 () => 23 { 24 if(onceFlag) { 25 onceFlag = false; 26 /* ここに一度しか行わせたくない処理を書く */ 27 } 28 } ); 29);

試したソースコードを追記いたします。
最初に記述したソースコードがエラーになってしまい、申し訳ございませんでした。

node

1'use strict'; 2 3// モジュール 4const express = require( 'express' ); 5const http = require( 'http' ); 6const socketIO = require( 'socket.io' ); 7 8// オブジェクト 9const app = express(); 10const server = http.Server( app ); 11const io = socketIO( server ); 12 13// 定数 14const PORT = process.env.PORT || 8080; 15const SYSTEMNICKNAME = '**system**'; 16 17// 関数 18// 数字を2桁の文字列に変換 19const toDoubleDigitString = 20 ( num ) => 21 { 22 return ( "0" + num ).slice( -2 ); // slice( -2 )で後ろから2文字取り出す。 23 }; 24 25// 時刻文字列の作成(書式は「YY/DD/MM hh:mm ss」) 26const makeTimeString = 27 ( time ) => 28 { 29 return toDoubleDigitString( time.getFullYear() ) + '/' + toDoubleDigitString( time.getMonth() + 1 ) + '/' + toDoubleDigitString( time.getDate() ) 30 + ' ' + toDoubleDigitString( time.getHours() ) + ':' + toDoubleDigitString( time.getMinutes() ) + ' ' + toDoubleDigitString( time.getSeconds() ); 31 } 32 33// グローバル変数 34let iCountUser = 0; // ユーザー数 35 36/* 処理を管理するためのフラグ */ 37let onceFlag = true; // ボタンの状態 38 39// 接続時の処理 40// ・サーバーとクライアントの接続が確立すると、 41//  サーバー側で、'connection'イベント 42//  クライアント側で、'connect'イベントが発生する 43io.on( 44 'connection', 45 ( socket ) => 46 { 47 console.log( 'connection' ); 48 49 let strNickname = ''; // コネクションごとで固有のニックネーム。イベントをまたいで使用される。 50 51 // 切断時の処理 52 // ・クライアントが切断したら、サーバー側では'disconnect'イベントが発生する 53 socket.on( 54 'disconnect', 55 () => 56 { 57 console.log( 'disconnect' ); 58 59 if( strNickname ) 60 { 61 // ユーザー数の更新 62 iCountUser--; 63 64 // メッセージオブジェクトに現在時刻を追加 65 const strNow = makeTimeString( new Date() ); 66 67 // システムメッセージの作成 68 const objMessage = { 69 strNickname: SYSTEMNICKNAME, 70 strMessage: strNickname + ' left.' + " there are " + iCountUser + " participants", 71 strDate: strNow 72 } 73 74 // 送信元含む全員に送信 75 io.emit( 'spread message', objMessage ); 76 } 77 } ); 78 79 // 入室時の処理 80 // ・クライアント側のメッセージ送信時の「socket.emit( 'join', strNickname );」に対する処理 81 socket.on( 82 'join', 83 ( strNickname_ ) => 84 { 85 console.log( 'joined :', strNickname_ ); 86 87 // コネクションごとで固有のニックネームに設定 88 strNickname = strNickname_; 89 90 // ユーザー数の更新 91 iCountUser++; 92 93 // メッセージオブジェクトに現在時刻を追加 94 const strNow = makeTimeString( new Date() ); 95 96 // システムメッセージの作成 97 const objMessage = { 98 strNickname: SYSTEMNICKNAME, 99 strMessage: strNickname + ' joined.' + " there are " + iCountUser + " participants", 100 strDate: strNow 101 } 102 103 // 送信元含む全員に送信 104 io.emit( 'spread message', objMessage ); 105 } ); 106 107 // 新しいメッセージ受信時の処理 108 // ・クライアント側のメッセージ送信時の「socket.emit( 'new message', $( '#input_message' ).val() );」に対する処理 109 socket.on( 110 'new message', 111 ( strMessage ) => 112 { 113 console.log( 'new message', strMessage ); 114 115 // 現在時刻の文字列の作成 116 const strNow = makeTimeString( new Date() ); 117 118 // メッセージオブジェクトの作成 119 const objMessage = { 120 strNickname: socket.id, 121 strMessage: strMessage, 122 strDate: strNow 123 } 124 125 // 送信元含む全員に送信 126 //io.emit( 'spread message', strMessage ); 127 io.emit( 'spread message', objMessage ); 128 } ); 129 130 /* 一度しか行わせたくない */ 131 socket.on( 132 'once', 133 () => 134 { 135 if(onceFlag) { 136 console.log('once'); 137 } 138 } ); 139 } ); 140 141// 公開フォルダの指定 142app.use( express.static( __dirname + '/public' ) ); 143 144// サーバーの起動 145server.listen( 146 PORT, 147 () => 148 { 149 console.log( 'Server on port %d', PORT ); 150 } );

クライアント側ではjqueryを用いてソースコードを用意して、onceのidを付けたdivタグを用意しておりました。

javascript

1$("#once").on( 2 'click', 3 () => 4 { 5 socket.emit('once'); 6 } 7);

上のイベントが発火したときに「once」のログが1度だけ残り、以後はクリックしてもログが残らないことは確認しております。
しかし、ほぼ同時に起こった場合はあくまで推測でしかなく、試せてない状況です。申し訳ございません。

すみません、よろしくお願いいたします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

AkitoshiManabe

2020/06/21 07:48

試したことを追記してください(ご提示のコードはサーバープログラムを起動しようとした時点で、io.on()の箇所でエラーになるはずです)。構想だけで socket.io の特徴や実装を確認されていないように思います。 github) https://github.com/socketio/socket.io の「Simple and convenient API」セクションに、ブラウザ-サーバー間のコネクション確立させるサンプルコードが示されています。 docs/ で詳細なドキュメント(サンプルコード有り)を、lib/ で実装(ソースコード)を確認できます。
guest

回答1

0

ベストアンサー

  1. イベントがほぼ同時に2回以上起こった場合、処理が2度以上行われることがあるかどうか。
  2. 上記のことが起こる場合、回避策があるかどうか
  1. クライアント側のチャタリングや通信状況によるユーザ操作の繰り返しは起こりうると考えた方が良いと思います。
  2. サーバー側で socket.id と ユーザ情報を対にしたキーにして連想配列的なオブジェクトやMapを使いステート管理することで回避できそうに思います。

socket.io のリアルタイム通信は、@IT :チャットアプリ開発に見る、Socket.IOの基本ライブラリの使い方 が参考になります。
特に記事の3ページ目まで読み進めると、io.on("connect", socket=>{ }) のイベントリスナに渡される socket オブジェクトから socket.id を接続ごとのユニークな値として活用している事例を確認できたり、リアルタイム通信に存在する3つのステップの後処理まで説明されています。

  1. 接続確立
  2. 接続中の通信
  3. 接続解除 (後処理) ... @IT記事3ページ目の「クライアント切断時の処理」セクションを参照

投稿2020/06/21 10:48

編集2020/06/21 10:49
AkitoshiManabe

総合スコア5434

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

mussi425

2020/06/24 12:38

ご解答ありがとうございます! 起こりうるということで、リンクを参照しながら回避できるようにしてきます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問