以下是一些问题:
我已经遇到过两次这样的情况(尽管它似乎更像是一个不太可能发生的事件,而不是在执行特定操作后发生的事情),即聊天系统会加载已读消息并将其显示出来。
为了保持聊天系统的简洁性,我编写了以下代码:
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>
您可以看到,我放置了一个占位符li元素,供jQuery使用作为片段来创建具有实际消息的新li元素,并将它们prepend在ul元素内部。
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);
所以我向客户端发送了一个JSON编码的数组,其中包含最后已知消息之后插入的数据库中所有记录,并且作者不是查询客户端。
我的怀疑:
我得出结论,在执行消息接收(服务器端)时,每个消息都从数据库中取出一段时间,如果同时进行刷新,则找不到该消息,如果该消息是我们正在寻找的作为最后一条红色消息,则服务器将只选择表中的所有消息并将它们发送回来。
结果是您会看到一堆您已经阅读过的消息,而您的消息不在其中(因为它们是在视图客户端中添加的,并且服务器脚本不会将您的消息发送回来)
声明如下:
- 我不在意消息是否按实际插入顺序排列:假设A和B正在聊天,实际的真实消息顺序是BAB,但A可能会看到ABB的顺序,因为他的视图在输入时立即更新(这有助于保持“快速实时”感觉)
- 我不在意某些消息是否丢失(例如,如果它在某人阅读之前跌落到固定的DB表边缘)
- 此时,我不太关心实际效率,速度和优化
- 我知道我应该以不同的方式处理消息插入,先添加新记录,然后仅更新ID并删除最后一条记录。但如果可能,我想保持这种仅更新的方式。
您认为我对问题的解释正确吗? 如果不是:那么原因是什么?/我该如何修复? 如果是:我该如何轻松解决?
如果实际修复相当复杂:在10-20个用户聊天中出现这种怪癖的可能性有多大?
谢谢
mysql_query
在PHP 7中被淘汰了,所以现在是时候转变了。我强烈建议至少使用PDO,或者像Doctrine或Propel这样的ORM,如果你想要做得正确。更好的选择是使用开发框架,比如Laravel,这将使第一次正确地完成变得更加容易。 - tadman