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;
?>