[PHP/Java] Php --> Java socket, EOF vraag

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • B-Man
  • Registratie: Februari 2000
  • Niet online
Ik heb een java server draaien, die socket verbindingen accepteerd. Ik handel ze af met de nieuwe NIO packages (select()).

Tevens draai ik een php webinterface die m.b.v. fsockopen() een verbinding maakt met deze javaserver, en commando's uitvoert, en het resultaat uitleest.

Beiden draaien op linux, java versie JDK 1.4.2, PHP 4.0.6;

Als ik met telnet verbinding maak, werkt het zoals het hoort:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
uptime
Ongeldig commando: [uptime]
test
Ongeldig commando: [test]
help
Available commands:

 load   [object] [id]       Load an object
 unload [object] [id]       Unload an object
 exit | quit                Close this connection
 shutdown                   Shutdown the Mgt server

Ik stuur hier m.b.v. telnet de commando's "uptime", "test" en "help".

Als ik m.b.v. php een verbinding maak, en een commando zend mbv
PHP:
1
fputs($handle, $commando."\n");

en vervolgens het resultaat uit probeer te lezen met
PHP:
1
2
3
while(!feof($handle)) {
    $data = fgets($handle, 250);
}

dan hangt php op de fgets, aangezien feof nooit optreed.
Ik houd de verbinding server-side open aangezien een client meerdere commando's in een sessie moet kunnen uitvoeren. Het lijkt er echter op dat php dan geen EOF ziet (alhoewel de buffer wel leeg is), en dus vrolijk in de while-loop hangt.

Wat is een nette manier om dit op te lossen? Kan ik keihard een EOF char zenden vanuit mijn java server?

Ik heb een niet erg nette oplossing in de vorm van een commando dat ervoor zorgt dat iedere reactie wordt afgesloten met "/eod" (end-of-data), zodat ik in php hierop kan controleren. Aangezien er mogelijk ook andere soorten clients gebruik van gaan maken wil ik deze oplossing eigenlijk vermijden, en een oplossing hebben die wel met EOF werkt.

Acties:
  • 0 Henk 'm!

  • ACM
  • Registratie: Januari 2000
  • Niet online

ACM

Software Architect

Werkt hier

Als je de socket open houdt zal er idd nooit een EOF op verschijnen...
De netste manier lijkt me gewoon om een of ander disconnect-commando te maken en die te sturen als je php-client klaar is (je exit of quit dus). Of die client gewoon de socket laten sluiten.

[ Voor 5% gewijzigd door ACM op 26-07-2003 15:25 ]


Acties:
  • 0 Henk 'm!

  • B-Man
  • Registratie: Februari 2000
  • Niet online
daar zat ik net inderdaad ook aan te denken, wat ik namelijk vergat is het simpele feit dat ik een telnet sessie als gebruiker natuurlijk ook beindig met een "exit" of een ctrl+c...

Maar wat ik dan nog niet opgelost heb is het afhandelen van meerdere commando's:
stel ik zend vanuit php een tweetal commando's:

code:
1
2
3
4
5
6
7
load object x
Object x loaded
load object y
Object y coud not be loaded:
object does not exist
exit
[break connection]


Hoe zorg ik er dan voor dat php "ziet" dat de reactie van een commando voltooid is, en het volgende commando stuurt? PHP weet niet of een reactie een of meerdere regels bevat.
Ik wil dus een loop kunnen gebruiken die de reactie van de java server uitleest, en een seintje krijgt als de reactie voltooid is. Vervolgens kan er een ander commando verzonden worden.

Aangezien php de mogelijkheid heeft om de funtie feof te gebruiken is het misschien toch handig om EOF te zenden. Ik zocht zojuist even met google, maar vond verschillende reacties omtrent EOF: sommige berichten/pagina's melden dat EOF een state is, en geen karakter, hoewel anderen melden dat ik hiervoor
Java:
1
String retval = "Data returned"+"\032";

kan gebruiken.

Kan ik vanuit java een EOF karakter zenden? (Rij over een uurtje naar m'n kantoor om het te testen, dit is zeg maar "vooronderzoek" in mijn vrijetijd ;) )

Acties:
  • 0 Henk 'm!

  • ACM
  • Registratie: Januari 2000
  • Niet online

ACM

Software Architect

Werkt hier

Ah dat, ja dat had ik idd zelf een keer opgelost door een "end of commandoutput"-character te definieren.
Sommige protocollen lossen dat op met een dubbele-newline, anderen met een enkele . op een regel. Daar zul je dus zelf een eigen protocol voor moeten bedenken :)

Ik zou niet weten of java zomaar een EOF-char kan verzenden, ik meen van niet eigenlijk. Ik denk idd dat dat "eof is een state" meer bij de waarheid zit.

[ Voor 9% gewijzigd door ACM op 26-07-2003 15:45 ]


Acties:
  • 0 Henk 'm!

  • B-Man
  • Registratie: Februari 2000
  • Niet online
ACM: ja, ga dan toch maar verder met mijn "/eod" string.

Ik las zojuist dat EOF wel bestaat, maar verschilt per platform, en dat moet ik al helemaal niet hebben (\032 op *nix geloof ik, of \004, \026 op windows).

Acties:
  • 0 Henk 'm!

  • Janoz
  • Registratie: Oktober 2000
  • Laatst online: 16-09 09:15

Janoz

Moderator Devschuur®

!litemod

Het EOF karakter zou ik iig niet op die manier gaan gebruiken. Het is namelijk nogal erg ongedefinieerd wat er met de hele verbinding gebeurt waneer je zo een disconect simuleerd.

Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'


Acties:
  • 0 Henk 'm!

  • hobbit_be
  • Registratie: November 2002
  • Laatst online: 04-07 12:07
waarom niet gewoon xml-socketje doen? kun je je socket server ineens lekker super compatible houden - of xml-rpc? en als je weet wat het formaat is dat je terug krijgt hoef je niet eens echt te gaan xml-parsen: ie een snelle substr is dan al genoeg. Doe ik vaak met Director->NIO. (de rest, VB, Flash, PHP werken dan weer wel met "echte" xml aware dingen.). Maar wel een tikkeltke overhead...

Acties:
  • 0 Henk 'm!

  • B-Man
  • Registratie: Februari 2000
  • Niet online
hobbit_be: had ik ook al aan gedacht, alleen omvat het "protocol" maar een stuk of 5 relatief eenvoudige commando's. XML lijkt me daarom overkill.
Janoz: ben alweer van het idee afgestapt, doe het nu dus met mijn eigen "end-of-data" string, die een client kan uitlezen.

Overigens werkt het NIO verhaal echt super! Mijn code is tevens een stuk simpeler geworden, doordat ik geen onnodige threads meer hoef te volgen.

Acties:
  • 0 Henk 'm!

  • hobbit_be
  • Registratie: November 2002
  • Laatst online: 04-07 12:07
B-Man. idd - als je slechts 5 commands hebt. Eigenlijk wou ik er nog bij zeggen dat een 'xml-socket' als enigste vereiste heeft dat het eindigt op een \0 character.

Overigens zijn mijn NIO ervaring ook zeer positief. Het maximum op mijn 'chat server' was 880 connected clients. Meer en W32 API (Winsockets) begon te flippen. En idd erg leuk dat je geen threading issues hebt. Wel heb ik mijn server socket in een thread gestoken zodat ik daar geen speciale select in moet proppen. Ook detecteert NIO een socket close aan client side iets waar de oude heel slecht in waren (moest steeds met een soort keep-alive werken). Natuurlijk is het wel grappig dat NIO in feite gewoon sockets voor het native platform is. Ook een klein nadeel is de overhead van het moeten werken met ByteBuffers...

Acties:
  • 0 Henk 'm!

  • B-Man
  • Registratie: Februari 2000
  • Niet online
hobbit_be: de socket close detectie is inderdaad erg handig, dat werkte voorheen wat "ranzig" vond ik. De overhead van ByteBuffers heb ik eigenlijk nog niet gemerkt: als in "geen merkbaar verschil". Heb je wat cijfers om te laten zien wat de overhead is?

Acties:
  • 0 Henk 'm!

  • hobbit_be
  • Registratie: November 2002
  • Laatst online: 04-07 12:07
B_Man: nee geen cijfers, maar wel genoeg ervaring met Java 'optimise' code om te weten dat daar nodeloos tijd verspilt word. (ie een hele extra copy, maar in het ergste geval een char by char copy - daar staat de root code van Java veel te vol van). Zelf gebruik ik 1 Direct Char + Byte Buffer (dus native memory) aangezien dit kan. Voor elke client blijf ik het wel bij StringBuffer's houden. Maar das is het probleem van NIO dat dit zo low level is (read: doet gewoon een function call naar een native API) dat je met de Unicode in contact komt waar elke OS zijn eigen strategy heeft terwijl java natuurlijk maar 1. Maar scalability vergeleken met threads is gewoon absurd. Met thread kon ik amper 120 aan en dat gebruikte toen 100% nu amper 40% (met 880). De code is wel redelijk optmised omdat dit nu ook kan (ie vooral dat je ineens een heel reeks data kunt inlezen en effe snel checken of de laatste char = \0 , geen while (char != \0) loopje meer en dat kan tellen. die 880 hebben volgens mij te maken dat ik op een W2K doos zit en dat daar (denk ik) restricties opzitten van hoeveel sockets enzo en buffers erop staan. bij W2K AS vast meer. Voor mij is NIO het beste van Java 2. Als je bedenkt dat het toch vooral serverside wordt gebruikt is het absurd geen select() te hebben.

Acties:
  • 0 Henk 'm!

  • B-Man
  • Registratie: Februari 2000
  • Niet online
hobbit_be: ja het gekopieer (char by char of byte for byte) komt onnodig veel voor. Naja, waar het uiteindelijk natuurlijk ook inzit zijn de immutable strings.

Ik werk ook met een stringbuffer per client. Kan eigenlijk ook bijna niet anders, omdat iedere keypress een event genereerd, en ik commando's verwerk met mijn server.

Ik heb trouwens in algemene zin het gevoel dat het geheel responsiever is op een van mijn mijn single-proc machines, mogelijk vanwege het feit dat er geen thread creation overhead meer is.

Ben het met je eens dat NIO een van de beste zaken van Java 2 is.
Pagina: 1