3

私は、訪問者が通信できるように Web サイトに配置する、すばやく簡単な jQuery/PHP チャットに取り組んでいます。私は 200 人の同時 Web サイト ユーザー (接続ユーザー) のピークを推定しましたが、実際にチャットしているのはせいぜい 10 ~ 20 人でした。

ここに癖があります:

私がすでに2回経験したように(何か特定のことを実行した後に何かが起こるというよりは、かなりありそうにないイベントのように思えます)、チャットはすでに赤くなっている複数のメッセージを読み込んで表示します.

チャット システムを可能な限りシンプルに保つために、次のコードを思いつきました。


HTML コード:

<div class="chat">

    <ul class="chat">

        <li class="chat" >

            <h5 class="chat">Date</h5>
            <h6 class="chat">Time</h6>
            <h4 class="chat">User</h4>
            <br/>
            <q class="chat">Message</q>

        </li>

    </ul>

    <input class="chat" placeholder="write something..."/>

</div>

ご覧のとおり、jQueryが実際のメッセージを含む新しいli要素を作成し、それらを ul 要素内に追加するためのスニペットとして使用するプレースホルダーのli要素を配置します。


jQuery コード:

メッセージの送信:

$(document).ready(function(){

    chatSnippet = $('ul.chat').html(); // here chatSnippet is a global variable
    $('ul.chat').html('');

    $('input.chat').change(function(event){// Send your message

    message = $(this).attr('value');

// first thing I perform an asynchronous POST to the receiving php script

    $.post(

        'php/chatRec.php',

        {

            user : currentUser,
            message: message,

        }

    );

// meanwhile I add a new li element to the chat html with the content just submitted


    date.setTime(event.timeStamp);

    hours = ''+date.getHours();

    if(hours.length < 2) hours = '0'+hours;

    minutes = ''+date.getMinutes();

    if(minutes.length < 2) minutes = '0'+minutes;

    day = ''+date.getDate();

    if(day.length < 2) day = '0'+day;

    newChatMessage = chatSnippet.replace('Date', ''+day+' '+months[date.getMonth()]);
    // here months is an array with the months names (in italian)
    newChatMessage = newChatMessage.replace('Time', ''+hours+':'+minutes);

    newChatMessage = newChatMessage.replace('User', connectedUser);

    newChatMessage = newChatMessage.replace('Message', message);

    $mess = $(newChatMessage);

    $mess.hide().prependTo('ul.chat').fadeIn(500);

    $(this).attr('value','');

});

refreshChat(''); // this function retrives new messages from the DB

// Here I perform a void refreshChat call so I'll get all the messages in the DB regardless from the currentUser (at page refresh)

});

メッセージの受信:

// This code is placed outside (before) the .ready function

function refreshChat(user){// Receiving messages

$.post(

    'php/chatInv.php',

    {

        user : user,
        token: lastMessage // this variable contains the token of the last red message

    },

    function(data){

        receivedMessages = jQuery.parseJSON(data);

        for(message in receivedMessages){

            message = receivedMessages[message].Message;

            date = receivedMessages[message].Day.split('-');
            time = receivedMessages[message].Time.split(':');

            newChatMessage = chatSnippet.replace('Date', ''+date[2]+' '+months[parseInt(date[1])-1]);

            newChatMessage = newChatMessage.replace('Time', ''+time[0]+':'+time[1]);

            newChatMessage = newChatMessage.replace('User', receivedMessages[message].Sender);

            newChatMessage = newChatMessage.replace('Message', message);

            $mess = $(newChatMessage);

            $mess.hide().prependTo('ul.chat').fadeIn(500);

            lastMessage = receivedMessages[messages].token;

        }

        nextRefresh = setTimeout("refreshChat('"+currentUser+"')",2000);

// When I'm done I set a timeout of 2 secs and then perform another refresh

    }

);

}

PHP コード:

新しいメッセージを受け取ります (問題はここにあると思います):

    mysql_connect("localhost", "root", "root") or die(mysql_error());
    mysql_select_db("chat") or die(mysql_error());

    $characters = array('0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z');

    $token = $characters[rand(0,61)].$characters[rand(0,61)].$characters[rand(0,61)].$characters[rand(0,61)].$characters[rand(0,61)];

    $all_Msgs = mysql_query("SELECT * FROM Messages ORDER BY ID");

    $prev_Msg = array('ID' => 1 , 'Sender' => $_POST['user'], 'Message' => $_POST['message'], 'Day' => date("Y-m-d"), 'Time' => date("H:i:s"), 'token' => $token);

    while($Msg = mysql_fetch_array($all_Msgs)){

        $update_success = mysql_query("UPDATE Messages SET Sender='".$prev_Msg['Sender']."', Message='".$prev_Msg['Message']."', Day='".$prev_Msg['Day']."', Time='".$prev_Msg['Time']."', token = '".$prev_Msg['token']."' WHERE ID=".$Msg['ID']);

        $prev_Msg = $Msg;

    }

基本的にここで行うことは、新しい投稿メッセージを受信し、トークンと、新しく入力されたデータを含む配列要素 (それ自体が配列) を生成することです。これを行うと、固定サイズの SQL テーブルで一連の UPDATE ステートメントを実行し、新しいものをオーバーライドします。最初のレコードのデータを削除し、各レコードを前のレコードでオーバーライドします (最後のレコードが最終的に失われるように)。

メッセージの送信:

    mysql_connect("localhost", "root", "root") or die(mysql_error());
    mysql_select_db("chat") or die(mysql_error());

    $receiver = $_POST['user'];
    $token = $_POST['token'];

    $all_Msgs = mysql_query("SELECT * FROM Messages ORDER BY ID");

    $newMessages = array();

    while($Msg = mysql_fetch_array($all_Msgs)){

        if($Msg['token'] == $token) break;

        if($Msg['Sender'] != $receiver) array_unshift($newMessages,$Msg);

    }

    echo json_encode($newMessages);

そのため、最後の既知のメッセージの後に挿入された DB 内のすべてのレコードの配列の JSON エンコードをクライアントに送信し、その作成者はクエリを実行したクライアントではありませんでした。


私の容疑者:

私は、メッセージ受信 (サーバー側) が実行されているときに、各メッセージが DB から取得される時間帯があるという結論に達しました。その間に更新が実行されている場合、メッセージが見つからず、そのメッセージが最後の赤いメッセージとして探していたメッセージの場合、サーバーはテーブル内のすべてのメッセージを選択して送り返します。

その結果、間にメッセージがなくても既に赤くなっているメッセージがたくさん表示されます (これらはビュー クライアント側に追加され、サーバー スクリプトは独自のメッセージを送り返しません)。

述べています:

  • メッセージが実際の挿入順序と正確に一致していなくても構いません。たとえば、A と B がチャットしているとします。実際のメッセージの順序は BAB ですが、A は入力時にビューが即座に更新されるため、ABB の順序を使用する場合があります。 (これにより、「高速リアルタイム」の感覚を保つことができます)
  • 一部のメッセージが失われても気にしません (誰かが読む前に、固定された DB テーブルの端に落ちた場合など)
  • 現時点では、実際の効率、速度、最適化についてはあまり気にしません。
  • メッセージの挿入を別の方法で処理し、新しいレコードを追加してから ID のみを更新し、最後のレコードを削除する必要があることはわかっています。でもできればこのUPDATEだけのファッションは続けていきたいです。

問題の私の解釈は正しいと思いますか? そうでない場合:何が原因でしょうか?/どうすれば修正できますか?はいの場合: どうすれば簡単に修正できますか?

実際の修正がかなり複雑な場合: 10 ~ 20 人のユーザーのチャットでこの癖が実際に発生する可能性はどれくらいですか?

ありがとう

4

1 に答える 1

1

私もチャットコードに取り組んだときにこれに気付きました。解決策は、最後のメッセージ ID (MySQL の自動インクリメントフィールドとして設定) をセッションに保存し、ID がそれよりも大きいメッセージをデータベースで検索することです。 time() 関数を使用します。

if (!$_SESSION['message_id']]) {
// if there isn't a message_id, select the last seven entries in the message list
    $sql = "SELECT messages.message_id, messages.message, users.username FROM (SELECT * FROM messages, users user.user_id = messages.user_id ORDER BY message_id DESC LIMIT 7) as new_tbl ORDER BY message_id ASC";
} else {
// if there is a message_id, select the messages sent since the last entry
    $sql = sprintf("SELECT messages.message_id, messages.message, users.username FROM messages, users WHERE user.user_id = messages.user_id message_id > '%d'", $_SESSION['message_id']);
}

$data = array();
$query = mysql_query($sql);
while ($row = mysql_fetch_array($query)) {
// build the data array from the mysql result and set the message_id session to the id of the last message
    $data[$i] = array('user' => $row['username'], 'message' => $row['message']);
    $_SESSION['message_id'] = $row['message_id'] > $_SESSION['message_id'] ? $row['message_id'] : $_SESSION['message_id'];
    $i++;
}

明らかに、セッションをエスケープする必要があります。

message_id セッションがない場合は、テーブルから最後の 7 つのメッセージを読み込みます (降順で並べた後、それらのメッセージを昇順で並べ替えます)。message_id セッションがある場合、新しいメッセージをロードします。

while ループでは、データ配列を作成し (JSON としてスクリプトに送信します)、message_id セッションを message_id 行として設定します。

SQL は、user_id と username を持つユーザーのテーブルと、user_id、message_id、およびメッセージを持つメッセージのテーブルがあることを意味します。

于 2012-05-13T07:57:58.227 に答える