mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-07-29 22:03:40 -06:00
Turtle: Server side improvements, reduced CPU load on idle state, and cleanup.
git-svn-id: svn://ultimatepp.org/upp/trunk@15007 f0d560ea-af0d-0410-9eb7-867de7ffcac7
This commit is contained in:
parent
501da534a1
commit
06b8ae8869
6 changed files with 110 additions and 102 deletions
|
|
@ -97,51 +97,56 @@ bool TurtleServer::ProcessEvent(bool *quit)
|
|||
void TurtleServer::WaitEvent(int ms)
|
||||
{
|
||||
websocket.Do();
|
||||
socket.Timeout(ms).WaitRead();
|
||||
socket.Timeout(0);
|
||||
SocketWaitEvent we;
|
||||
websocket.AddTo(we);
|
||||
we.Wait(ms);
|
||||
}
|
||||
|
||||
bool TurtleServer::IsWaitingEvent()
|
||||
{
|
||||
websocket.Do();
|
||||
for(;;) {
|
||||
String s = websocket.Receive();
|
||||
if(websocket.IsClosed()) {
|
||||
Ctrl::EndSession();
|
||||
sQuit = true; // Ugly...
|
||||
return false;
|
||||
}
|
||||
if(s.GetCount() == 0)
|
||||
break;
|
||||
LLOG("Received data " << s);
|
||||
StringStream ss(s);
|
||||
while(!ss.IsEof()) {
|
||||
String s = ss.GetLine();
|
||||
CParser p(s);
|
||||
try
|
||||
{
|
||||
if(p.Id("S")) {
|
||||
uint32 l = p.ReadNumber();
|
||||
uint32 h = p.ReadNumber();
|
||||
recieved_update_serial = MAKEQWORD(l, h);
|
||||
stat_client_ms = p.ReadNumber();
|
||||
}
|
||||
else
|
||||
sEventQueue.AddTail(s);
|
||||
}
|
||||
catch(const CParser::Error& e)
|
||||
{
|
||||
LLOG("IsWaitingEvent() -> Parser error. " << e);
|
||||
|
||||
String s = websocket.Receive();
|
||||
|
||||
if(websocket.IsClosed()) {
|
||||
Ctrl::EndSession();
|
||||
sQuit = true; // Ugly..
|
||||
return false;
|
||||
}
|
||||
|
||||
if(s.GetCount() == 0)
|
||||
return sEventQueue.GetCount();
|
||||
|
||||
LLOG("Received data " << s);
|
||||
|
||||
StringStream ss(s);
|
||||
while(!ss.IsEof()) {
|
||||
String s = ss.GetLine();
|
||||
CParser p(s);
|
||||
try
|
||||
{
|
||||
if(p.Id("S")) {
|
||||
uint32 l = p.ReadNumber();
|
||||
uint32 h = p.ReadNumber();
|
||||
recieved_update_serial = MAKEQWORD(l, h);
|
||||
stat_client_ms = p.ReadNumber();
|
||||
}
|
||||
else
|
||||
sEventQueue.AddTail(s);
|
||||
}
|
||||
if(recieved_update_serial == serial_0) {
|
||||
serial_0 = 0;
|
||||
stat_roundtrip_ms = msecs() - serial_time0;
|
||||
serial_time0 = Null;
|
||||
catch(const CParser::Error& e)
|
||||
{
|
||||
LLOG("IsWaitingEvent() -> Parser error. " << e);
|
||||
}
|
||||
}
|
||||
if(socket.IsError())
|
||||
LLOG("ERROR: " << socket.GetErrorDesc());
|
||||
if(recieved_update_serial == serial_0) {
|
||||
serial_0 = 0;
|
||||
stat_roundtrip_ms = msecs() - serial_time0;
|
||||
serial_time0 = Null;
|
||||
}
|
||||
|
||||
if(websocket.IsError())
|
||||
LLOG("ERROR: " << websocket.GetErrorDesc());
|
||||
|
||||
return sEventQueue.GetCount();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ int TurtleServer::port = 8888;
|
|||
String TurtleServer::ip = "0.0.0.0";
|
||||
int TurtleServer::connection_limit = 100;
|
||||
bool TurtleServer::debugmode;
|
||||
TcpSocket TurtleServer::socket;
|
||||
WebSocket TurtleServer::websocket;
|
||||
int TurtleServer::mainpid;
|
||||
bool TurtleServer::quit;
|
||||
|
|
|
|||
|
|
@ -11,10 +11,46 @@
|
|||
|
||||
namespace Upp {
|
||||
|
||||
static Vector<int> sProcessIds;
|
||||
static Vector<int> sChildPids;
|
||||
|
||||
static bool sSendTurtleHtml(TcpSocket& s, const String& host, int port)
|
||||
{
|
||||
HttpHeader h;
|
||||
if(!h.Read(s))
|
||||
return false;
|
||||
LLOG("Sending Turtle HTML");
|
||||
String html = String(turtle_html, turtle_html_length);
|
||||
html.Replace("%%host%%", Format("ws://%s:%d", host, port));
|
||||
return HttpResponse(s, h.scgi, 200, "OK", "text/html", html);
|
||||
}
|
||||
|
||||
static void sUpdateChildList()
|
||||
{
|
||||
#ifdef PLATFORM_POSIX
|
||||
int i = 0;
|
||||
while(i < sChildPids.GetCount()) {
|
||||
if(sChildPids[i] && waitpid(sChildPids[i], 0, WNOHANG | WUNTRACED) > 0) {
|
||||
TurtleServer::WhenTerminate(sChildPids[i]);
|
||||
sChildPids.Remove(i);
|
||||
}
|
||||
else ++i;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void TurtleServer::Broadcast(int signal)
|
||||
{
|
||||
#ifdef PLATFORM_POSIX
|
||||
if(getpid() == mainpid)
|
||||
for(int i = 0; i < sChildPids.GetCount(); i++)
|
||||
kill(sChildPids[i], signal);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool TurtleServer::StartSession()
|
||||
{
|
||||
// TODO: See if we can add secure websocket (wss://) support.
|
||||
|
||||
LLOG("Connect");
|
||||
|
||||
#ifdef PLATFORM_POSIX
|
||||
|
|
@ -27,11 +63,9 @@ bool TurtleServer::StartSession()
|
|||
TcpSocket server;
|
||||
|
||||
#ifdef _DEBUG
|
||||
int qq = 0;
|
||||
for(;;) {
|
||||
if(server.Listen(ipinfo, port, 5, false, true))
|
||||
break;
|
||||
Cout() << "Trying to start listening (other process using the same port?) " << ++qq << "\n";
|
||||
int cnt = 0;
|
||||
while(!server.Listen(ipinfo, port, 5, false, true)) {
|
||||
LLOG("Trying to start listening (other process using the same port?) " << ++cnt);
|
||||
Sleep(1000);
|
||||
}
|
||||
#else
|
||||
|
|
@ -42,67 +76,41 @@ bool TurtleServer::StartSession()
|
|||
#endif
|
||||
|
||||
LLOG("Starting to listen on " << port << ", pid: " << getpid());
|
||||
socket.Timeout(0); // TODO: Not quite ideal way to make quit work..
|
||||
|
||||
for(;;) {
|
||||
#ifdef PLATFORM_POSIX
|
||||
int i = 0;
|
||||
while(i < sProcessIds.GetCount())
|
||||
if(sProcessIds[i] && waitpid(sProcessIds[i], 0, WNOHANG | WUNTRACED) > 0) {
|
||||
WhenTerminate(sProcessIds[i]);
|
||||
sProcessIds.Remove(i);
|
||||
}
|
||||
else
|
||||
i++;
|
||||
#endif
|
||||
sUpdateChildList();
|
||||
if(server.IsError())
|
||||
server.ClearError();
|
||||
if(socket.Accept(server)) {
|
||||
HttpHeader http;
|
||||
if(http.Read(socket)) {
|
||||
RLOG("Accepted, header read");
|
||||
if(websocket.WebAccept(socket, http)) { // TODO: Connection limit, info
|
||||
if(sProcessIds.GetCount() >= connection_limit) {
|
||||
socket.Close();
|
||||
continue;
|
||||
}
|
||||
TcpSocket socket;
|
||||
if(!socket.Accept(server))
|
||||
continue;
|
||||
if(!sSendTurtleHtml(socket, host, port))
|
||||
continue;
|
||||
websocket.NonBlocking();
|
||||
while(!websocket.Accept(server))
|
||||
Sleep(20);
|
||||
LLOG("Websocket connection accepted. IP: " << websocket.GetPeerAddr());
|
||||
#ifdef PLATFORM_POSIX
|
||||
if(debugmode)
|
||||
break;
|
||||
int newpid = fork();
|
||||
if(newpid == 0)
|
||||
break;
|
||||
else {
|
||||
sProcessIds.Add(newpid);
|
||||
WhenConnect(newpid, socket.GetPeerAddr());
|
||||
socket.Close();
|
||||
continue;
|
||||
}
|
||||
#else
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
RLOG("Sending HTML");
|
||||
String html = String(turtle_html, turtle_html_length);
|
||||
html.Replace("%%host%%", "ws://" + Nvl(GetIniKey("turtle_host"), Nvl(host, "localhost")) + ":" + AsString(port));
|
||||
HttpResponse(socket, http.scgi, 200, "OK", "text/html", html);
|
||||
}
|
||||
socket.Close();
|
||||
if(sChildPids.GetCount() >= connection_limit)
|
||||
continue;
|
||||
if(debugmode)
|
||||
break;
|
||||
int newpid = fork();
|
||||
if(!newpid)
|
||||
break;
|
||||
else {
|
||||
LLOG("Process forked. Pid: " << newpid);
|
||||
sChildPids.Add(newpid);
|
||||
WhenConnect(newpid, websocket.GetPeerAddr());
|
||||
continue;
|
||||
}
|
||||
#else
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
RLOG("Connection established with " << socket.GetPeerAddr() << ", pid: " << getpid());
|
||||
|
||||
server.Close();
|
||||
if(socket.IsError())
|
||||
LLOG("CONNECT ERROR: " << socket.GetErrorDesc());
|
||||
stat_started = GetSysTime();
|
||||
return true;
|
||||
}
|
||||
|
||||
void TurtleServer::Broadcast(int signal)
|
||||
{
|
||||
#ifdef PLATFORM_POSIX
|
||||
if(getpid() == mainpid)
|
||||
for(int i = 0; i < sProcessIds.GetCount(); i++)
|
||||
kill(sProcessIds[i], signal);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -103,4 +103,3 @@ void TurtleServer::Flush()
|
|||
websocket.SendBinary(s);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -130,7 +130,6 @@ private:
|
|||
static void ResetImageCache();
|
||||
|
||||
private:
|
||||
static TcpSocket socket;
|
||||
static WebSocket websocket;
|
||||
static dword mousebuttons;
|
||||
static dword modifierkeys;
|
||||
|
|
|
|||
|
|
@ -12,7 +12,5 @@ Known Issues
|
|||
|
||||
3) The VirtualGui-based Turtle package inherits the problems of the old Turtle package.
|
||||
|
||||
a) One such major problem is that on windows platform, closing the remote app throws an
|
||||
exception on the server side. This requires further investigation.
|
||||
|
||||
b) The other one is high cpu usage even on idle state.
|
||||
One such major problem is that on windows platform, closing the remote app throws an
|
||||
exception on the server side. This requires further investigation.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue