越野车自定义聊天客户端

时间:2013-11-06 03:29:31

标签: javascript php html ajax json

HackThisSite论坛上有一个主题详细说明了网站(omegle.com上的匿名聊天客户端)的工作原理:https://www.hackthissite.org/forums/viewtopic.php?f=76&t=3783

这有点过时了,但它仍然是最准确的。使用它作为起点,我一直在研究自定义的聊天客户端。起初我在Game Maker中对它进行了编程,但之后我切换到Javascript / AJAX(使用一些PHP后端来解决一些XSS问题),我觉得它更适合Web应用程序服务。

基本上,Google的工作方式是您继续轮询服务器,当您这样做时,它会发回自上次轮询以来发生的事件列表。这些事件类似于“等待”(用于配对),“连接”(对于陌生人),“gotMessage”(包含接收到的消息的事件),“strangerDisconnected”(当其他用户断开连接时)等等

就像我说的那样,这个链接有点过时了,而且新添加的东西之一是一个名为statusInfo的事件,它包含一个带有一些服务器信息的JSON对象(包括当前正在运行的服务器列表)。我们的想法是,每次检查新事件时,您还会获得更新的工作服务器列表,以便在服务器发生故障时进行服务器跳转。

这一切都很好,花花公子,我的自定义客户端在某些时候工作正常......但是有一个错误。每隔一段时间,当它轮询服务器以查找事件时,服务器决定不响应。它甚至没有发回任何类型的确认或状态代码,因此AJAX请求只是坐在那里等待永远不会发生的响应。奇怪的是,当发生这种情况时,如果我服务器跳,它通常没有帮助。无论服务器如何,它都会挂在下一个请求上,直到它随机决定再次开始工作。所有这一切看起来都是完全随意的 - 它在某些时候完美运行,并在剩下的时间内完成,据我所知,这两个类别之间没有任何共同点。

即使更奇怪,如果我在发生此类挂起时尝试​​断开连接(这只是向server.omegle.com/disconnect发送请求并发布了用户的ID),则发送回“内部服务器错误”消息;如果在事件请求中没有挂起,我断开连接时就不会这样做。

我很乐意将您链接到我的客户端,但我目前正处于我无法控制的防火墙后面,因此我必须在此处发布代码...它只有2个小文件和1个但是,很有希望有人可以测试一下吗?

不用多说,这里是我用于客户端的整个HTML / Javascript(没有使用库;所有都是从头开始编写的)。我刚进去为你评论一切;希望很清楚。

<style>
.error { color:#ff0000; }
.them { color: #ff0000; }
.you { color:#0000ff; }
.typer { color:#555555; font-weight:bold; font-size:11pt; }
</style>

<script>

/* Cross-platform XMLHttpRequest function */
function Request() {
  if (window.XMLHttpRequest ) { return new XMLHttpRequest(); }
  else if (window.ActiveXObject) {
    try {
      return new ActiveXObject("Msxml2.XMLHTTP");
    }
    catch (e) {
      try {
        return new ActiveXObject("Microsoft.XMLHTTP");
      }
      catch (e) {
        return false;
      }
    }
  }
}

/* Common array shuffling function used to shuffle the list of servers */
function shuffle(a) {
  var m = a.length, t, i;

  // While there remain elements to shuffle...
  while (m) {

    // Pick a remaining element...
    i = Math.floor(Math.random() * m--);

    // And swap it with the current element.
    t = a[m];
    a[m] = a[i];
    a[i] = t;
  }

  return a;
}

/* A general-purpose handler for the XMLHttpRequests, which simply checks for a "completed" state and then calls the associated handler. I plan on making this more
   robust once the overall system is working at all. */
function HandleXHR() {
  if (this.readyState==4) {
    this.handler(this.responseText);
  }
}

server=null;
servs=null;

/* Whenever a statusInfo message is received, it includes a list of working servers. This code, almost identical to Omegle's own, modifies our own list of servers
   to include all of those (and remove no-longer-working ones) without changing the relative order of the current servers on the list */
function updateServers(list) {
  list=shuffle(list);
  for (i=0; i<list.length; ++i) {
    if (servs.indexOf(list[i])<0) {
      servs.unshift(list[i]);
    }
  }

  for (i=0; i<servs.length; ++i) {
    if (list.indexOf(servs[i])<0) {
      servs.splice(i--, 1);
    }
  }

  server=servs[0];

}

typing=false;

/* Initiate looking for a connection; this requests a user ID from the server, which itself is randomly chosen from the list of servers. This is actually what Omegle's
   own code does--it shuffles the server list around for uniform usage. */
function Connect(what) {
  typing=false;
  what=JSON.parse(what);
  servs=shuffle(what.servers);
  server=servs[0];

  req=Request();
  where="http://"+server+"/start?rcs=1&spid=";
  req.open("GET", "getpage.php?url="+escape(where));
  req.handler=GotID;
  req.onreadystatechange=HandleXHR;
  req.send(null);
}

id=null;
eventwatch=null;

/* When a connection is made and we have a user ID, start polling for events immediately */
function GotID(what) {
  id=what.split('"')[1];
  eventwatch=setTimeout(GetEvents, 1);
}

/* Initiate the poll to the server for any recent events */
function GetEvents() {
  if (id==null) { return false; }

  where="http://"+server+"/events";  
  req=Request();
  req.open("POST", "getposted.php?url="+escape(where));
  req.setRequestHeader("Content-type", "application/x-www-form-urlencoded");

  req.handler=ParseEvents;
  req.onreadystatechange=HandleXHR;

  req.send("id="+escape(id));
}

/* The function that parses all the events when they've been received from a poll */
attempts=0;
function ParseEvents(what) {

  spot=document.getElementById("codespot");

  try {
    what=JSON.parse(what);
    attempts=0;
  }

  /* If the messages couldn't be parsed, i.e. the server didn't return anything or returned malformed JSON (or an error),
     hop servers and try again, up to 3 times before giving up */
  catch (e) {
    attempts++;

    /* Move the first server on the list to the end and pick the next server */
    temp=servs.shift();
    servs.push(temp);
    server=servs[0];

    if (attempts>=3) {
      spot.innerHTML+="<b class='error'>Error: "+e.message+"</b><br />";
      Disconnect();
      return false;
    }

    eventwatch=setTimeout(GetEvents, 2500);
    return false;
  }

  /* Process each message */
  for (p in what) {
    code=what[p][0];

    /* Connected event */
    if (code=="connected") {
      spot.innerHTML+="<b>Connected!</b><br />";
      document.getElementById("waiter").innerHTML="";
    }

    /* Message reception */
    else if (code=="gotMessage") { spot.innerHTML+="<b class='them'>Stranger:</b> "+what[p][1]+"<br />"; }

    /* The other user disconnected, so stop checking for events and set your user ID to null (meaning no connection) */
    else if (code=="strangerDisconnected") { typing=false; id=null; spot.innerHTML+="<b>Stranger disconnected</b><br />"; window.clearTimeout(eventwatch); }

    /* Process the statusInfo events by updating the server list */
    else if (code=="statusInfo") {
      updateServers(what[p][1].servers);
    }

    /* These are only used for Omegle logs, which I'm not implementing, so ignore them */
    else if (code=="identDigests") { /* Ignore these for now */ }

    /* Change stranger-typing status */
    else if (code=="typing") { typing=!typing; }
    else if (code=="stoppedTyping") { typing=false; }

    /* Before a connection is made, let the user know you're waiting for one */
    else if (code=="waiting") {
      document.getElementById("waiter").innerHTML="Looking for a stranger...";
    }

    /* If all else fails, we don't know what this message is, so output it for debugging purposes--hasn't happened in all my tests yet */
    else { spot.innerHTML+="Didn't understand: "+code+"<br />"; }
  }

  /* Update the "is typing" display and set a timeout for the next event poll */
  document.getElementById("typer").innerHTML=typing ? "Stranger is typing..." : "";
  eventwatch=setTimeout(GetEvents, 2500);
}

/* The function that attempts to disconnect from the conversation */
function Disconnect() {
  where="http://"+server+"/disconnect?id="+id;

  req=Request();
  req.open("POST", "getposted.php?url="+escape(where));
  req.setRequestHeader("Content-type", "application/x-www-form-urlencoded");

  req.handler=Disconnected;
  req.onreadystatechange=HandleXHR;

  req.send("id="+escape(id));
}

/* The function to send a message */
function Send(place) {
  if (id==null) { return false; }
  what=place.value;
  place.disabled=true;

  where="http://"+server+"/send";

  req=Request();
  req.open("POST", "getposted.php?url="+escape(where));
  req.setRequestHeader("Content-type", "application/x-www-form-urlencoded");

  req.handler=Sent;
  req.onreadystatechange=HandleXHR;

  req.send("id="+escape(id)+"&msg="+escape(what));
}

/* The function to handle the display when a message you've typed has been sent */
function Sent(what) {
  if (id==null) { return false; }
  document.getElementById("codespot").innerHTML+="<b class='you'>You:</b> "+document.main.mess.value+"<br />";
  document.main.mess.disabled=false;
  document.main.mess.value="";
}

/* The function to handle cleanup once you've disconnected */
function Disconnected(what) {
  typing=false;
  id=null;
  window.clearTimeout(eventwatch);
  document.getElementById("codespot").innerHTML+="<b>Disconnected";
  if (what.substr(0, 3)!="win") { document.getElementById("codespot").innerHTML+=" -- "+what; }
  document.getElementById("codespot").innerHTML+="</b><br />";
}

/* The function to initiate the requests to get the list of active Omegle servers */
function GetServer() {
  req=Request();
  where="http://omegle.com/status";
  req.open("GET", "getpage.php?url="+escape(where));
  req.handler=Connect;
  req.onreadystatechange=HandleXHR;
  req.send(null);
}

</script>

<!-- The chat area -->
<div id="waiter" class="typer"></div>
<div id="codespot"></div>
<div id="typer" class="typer"></div><br />

<!-- The form where you connect, disconnect, and send messages from -->
<form name="main" onSubmit="Send(document.main.mess); return false"><input type="button" value="Connect" onClick="GetServer()" /><input type='text' name='mess' /><input type='submit' value='Send' />
<input type="button" value="Disconnect" onClick="Disconnect()" />

后端PHP脚本getpage.php和getposted.php只是使用cURL来获取来自Google的响应(尽管位于不同的域中)并直接回显它们,允许XHR访问域外页面。 / p>

任何人都可以帮我弄清楚为什么有时会发生拖延?

如果你想要getposted.php和getpage.php代码的简单代码,就是这样:

getposted.php:

<?php
  set_time_limit(60);
  $curl=curl_init();
  curl_setopt($curl, CURLOPT_URL, $_GET["url"]);
  curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); // Return value instead of outputting
  curl_setopt($curl,CURLOPT_POST, count($_POST));
  curl_setopt($curl,CURLOPT_POSTFIELDS, http_build_query($_POST, '', '&'));

  $all=curl_exec($curl);
  curl_close($curl);
  echo $all;
?>

getpage.php

<?php
  set_time_limit(60);
  $curl=curl_init();
  curl_setopt($curl, CURLOPT_URL, $_GET["url"]);
  curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); // Return value instead of outputting

  $all=curl_exec($curl);
  curl_close($curl);
  echo $all;
?>

0 个答案:

没有答案