Sehr cooler Song! (auch wenn man sich ja irgendwie auch angesprochen fühlen muss :D)
[via node0 via hostblogger]
Weitere Lieder von Jasper gibt es bei Youtube.
Sehr cooler Song! (auch wenn man sich ja irgendwie auch angesprochen fühlen muss :D)
[via node0 via hostblogger]
Weitere Lieder von Jasper gibt es bei Youtube.
In guter alter Tradition, möchte ich hier noch einmal in kurzen Worten die Gegebenheiten am vorigen “iPhone 3G Freitag” beschreiben:
08:00: | Der Wecker schellt. In froher Erwartung schwinge ich mich aus dem Bett und heize den Kaffeeautomaten an. In Anbetracht der letzten iPhone-Einführung in Deutschland gehe ich den Morgen gelassen an. Mein Mitstreiter des Tages hat vorsorglich ja zwei iPhöne reservieren lassen. |
09:00: | Nach Kaffee und Duschen fahre ich mit dem Auto zur U-Bahn und mit der U-Bahn weiter in die Stadt… Wer weiß, vielleicht gibt es doch Andrang und die Stadt ist dicht. |
09:15: | Nachricht vom Mitstreiter, bei ihm wird es wohl doch 09:30. Ich kämpfe mich (Müdigkeit) zum T-Punkt vor. Ich sehe eine _kleine_ Schlange von 5 Leuten, davon ist einer ein hyperaktiv-telefonierender und vor-der-Tür-parkender Audi A4 Fahrer, ein anderer trägt ein dezent S/W Apple-T-Shirt. Im Lauf der nächsten 10min wächst die Schlange um zwei weitere Kunden, die wild gestikulierend mit einer – scheinbar falschen – Telefonrechnung herumfuchteln. |
09:25: | Entwarnung. Ich entschließe mich dazu, einen Kaffee nachzutanken. Ich begebe mich zum nahen Stern-Bock und bestelle einen regular Cafe Mocá. |
09:27: | Sie sind heute schnell. Ich erhalte einen tall Cafe Mocá. War wohl ein Missverständnis. Ich beschließe, dass der Tag gut werden wird und steuere wieder das T an. |
09:35: | Der Mitstreiter trifft ein. Lagebesprechung. Wir betrachten argwöhnisch den schon gefüllten T-Punkt. Beschließen was zu tun ist und legen uns eine Schlangen-ansteh-Strategie zurecht. |
09:45: | Der T-Punkt ist nicht pber das normale Maß gefüllt, dennoch scheint der wohlige Geruch von Stress und Sonderaktion in er Luft zu liegen und Verkäuferinnen und Verkäufer hetzen mit gehetzten Blicken vom Lager zum Verkaufsraum. Wir entscheiden uns für eine Zwei-Schlangen-Strategie (okay für mehr fehlen uns eh die Leute :-D). |
09:55: | Der große Moment. Wir haben unsere eigene Telekommunikationsfachkraft. Die gute Frau ist voll Echtzeitmultitasking-fähig und scheint mindestens über 10 Kerne zu verfügen. |
10:00: | Wir ordern. Die Vorbestellungen scheinen – natürlich – nicht mehr auffindbar zu sein. Anscheinend hat jeder Verkäufer seine eigene Hitlist erstellt und mit nach Hause genommen. Dennoch erhalten wir zwei schwarze 16GB Modelle. |
10:25: | Ich bin an der Reihe. Ich erhalte (nach Aussage der threaded-Verkäuferin) das letzte iPhone des Ladens (ob das jetzt nur die 16GB Version betrifft steht noch im Raum). Die Verpackung ist aus unerfindlichen Gründen vor-geöffnet worden. Egal. Nach kurzer Sichtkontrolle greife ich zu. Ich muss doch keine 25 EUR Bereitstellung zahlen (Aktion! 🙂 ), allerdings kann ich JETZT meine alte Nummer nicht übernehmen (Aktion! 🙁 ). Wenn ich das wollte müsste ich nächste Woche Dienstag wiederkommen. Ich betrachte die sanft-glänzende Apple-Verpackung und erinnere mich daran als ich das letzte Mal wegen Klein-Foo in einen T-Punkt gehen wollte. Ich entschließe mich dazu, die logistische Herausforderung einer neuen-Nummer-Verteilung in meinem Social-Network in Kauf zu nehmen. |
10:45: | Ich ordere eine Multi-SIM Karte mit dem Plan, den iPhone Tarif auch mit anderen Devices nutzen zu können. Ich werde gefühlte 100 Mal darauf aufmerksam gemacht, dass die zusätzliche SIM einmalig 30 EUR kostet. Bestellung fertig:
|
11:00: I | Ich zahle. Und erhalte zusätzlich zwei Karten für das Fußballspiel Bayern gegen Bor. Dortmund am 23. Juli. Leider bin ich an dem Tag nicht in Deutschland, aber ich bin sicher, dass ich dafür Abnehmer finden werde. Ich entscheide mich gegen die durchsichtige Silikon-Schutzhülle. Ich möchte etwas dunkleres… Gibt es fürs alte iPhone (hehe wie schnell die Technik veraltet). Ich zahle nur das iPhone. DIe Multi-SIM scheint vergessen. Ich schaue in mein Shopping-Bag, sehe zwei Umschläge und verlasse schmunzelnd den Laden. ich beschließe das der Tag gut wird. |
11:30: | Wir lassen uns im Edwards nieder. In Erwartung von freiem WiFi, bestellen wir unsere Getränke und entpacken unsere iPhöne. Dummerweise scheint grade heute das WiFi ausgefallen zu sein (Verschwörung!!!!). Wir leeren unser Bestelltes und schlagen den Weg nach Hause ein. |
12:15: | Wir erreichen Home, Sweet Home. Das WiFi ist vorhanden und stabil. Wir füllen den Tisch mit Apple-Devotionalien. Wir verbinden iPhone mit Macbook (pro), Macbook (pro) mit WiFi und starten iTunes. |
12:30: | Nach einem – nervenden – iTunes-Update beginnt die Aktivierung des iPhones. Schnell die neue Nummer rausgesucht und mit iTunes Account abgeglichen. |
12:45: | Ich erhalte meinen ersten Anruf auf meinen iPhone. Ein Herr Maier oder Müller. Wunder sich, dass ich ich bin. Komisch. Meine Nummer scheint noch nicht lange ungenutzt zu sein. |
13:00: | Wir Updaten unsere iPhone-Firmware. Ich erkenne, dass mein iPhone mit meinen Kontakten kämpft. Ich schaue nach – nein keine großen Dateien. Nach gefühlten 30 min synchronisieren nun Email- und Browsereinstellungen. Done. Ich buche mein iPhone in mein heimatliche WiFi ein. Nettes Teil. Ich beschließe, dass der Tag gut ist. |
14:00: | Wir entdecken den AppStore. Wir installieren uns zahlreiche (hmmm 10?) der kostenlosen Anwendungen. Remote ist cool. Auch LifeGame lässt den Programmierer in mir aufleben. Freudig entdecke ich den AIM-Client. |
14:30: | Wir beschließen nun die Dev-Tools zu testen. Wir installieren “the latest iPhone-SDK”. |
15:15: | Der Hunger meldet sich. Wir gehen zu dem Chinesen gegenüber. Der schließt leider um 15h. Wir müssen hungrig aussehen. Aus Mitleid wird uns angeboten, dass wir uns etwas Bestellen können und es dann mitnehmen können. Netter Laden, toller Service. Wir bestellen beide das gleiche (schlechtes Gewissen ^^), geben Trinkgeld und verlassen das Lokal gen Heimat. |
15:30: | Wir essen. iPhone-Display ist “Fett”-proofed! |
15:45: | Ich teste den HW-Modes der Dev-Tools. XCode-Organizer schlägt vor, die aktuelle Firmware aufs iPhone zu spielen. Ich stimme zu (noch ist der Tag gut) |
16:00: | Mein iPhone ist wieder im Auslieferungszustand und möchte sich wieder neu aktivieren lassen. Ich starte iTunes und beginne den Vorgang. Ich erhalte wahlweise Fehler -9838 oder -4 (negativere Fehlernummer sind die schlechteren?). Ich fluche ein wenig. Stelle mich darauf ein, am morgigen Samstag mich in einen T-Punkt zu kämpfen. Ich lade noch einmal manuell per iTunes die Firmware aufs iPhone. Kein Erfolg. SIM-Lock weg und iTunes bockt? Ich schmeiße Google an. Finde den netten Thread auf FSCKLOG. Ich lese mich durch die 200 Kommentare und stelle fest, dass ich nicht alleine bin. Hatten wir morgens wohl sehr viel Glück und nun Pech. |
17:30: | -9838 … -4 |
17:30: | -9838 … -4 |
18:00: | -9838 … -4 |
18:15: | -4 (Fehler -9838 scheint behoben – erkommt jedenfalls nicht mehr). Ich beschließe meine iPhone-Playlist zu füllen. |
18:30: | Aus Frust fahre ich Auto. Ich bringe meinen Mitstreiter zum abendlichen Workout. |
19:00: | Mache Dinge die mich ablenken. (Fotos scannen) |
21:00: | -4 |
21:15: | -4 |
22:30: | -4 |
23:15: | Kein Fehler. “Kann iTunes Store nicht erreichen”. |
23:30: | Aktivierung geht. Der Tag findet ein gutes Ende. Ich kann mein iPhone wieder einrichten. Synchronisiere abermals Kontakte (30min), Musik, Bilder und Videos (20min). |
00:00: | Ich sehe mir noch ein paar der DEV-Videos an und schlafe ein. |
Da ich die letzten Tage gezwungenermaßen sehr viel Zeit hatte (warum kommt später) und ich irgendwie mal Grund in meine Kisten und Boxen bringen möchte, habe ich angefangen, meine (Papier-) Fotos einzuscannen und in iPhoto zu übertragen.
Die Frage stelle sich mir nun, wie ich aus 200 Tiff Dateien die das aktuelle Datum tragen (also das des Scans) ordentliche Digitalbilder hinkriege, sodass sie A) nicht zuviel Platz wegnehmen und B) nicht alle auf einen Tag datiert sind. Als Datum reicht mir erstmal nur der jeweilige Monat des Jahres.
Nachdem ich von freundlichen Mitmenschen (danke Willem, danke Christoph) mit geeigneten Shellscripten versorgt worden bin, war die Sache mit der Dateigröße vom Tisch der folgende Einzeiler macht das recht gut:
for i in `ls`; do convert $i neues_verzeichnis/$i.png; done
Nicht vergessen: “neues_Verzeichnis” natürlich anpassen und das ganze (wenn man es denn in eine Datei packt) chmod +x setzen.
Aber das reichte mir ja nicht ^^
Und was mache ich, wenn ich gar nicht mehr anders kann? Ich nutze PHP…. gute, alte, unübersichtliche Scriptsprache.
Well… thats the Code:
<?php
if(count($argv) < 2) die(“Usage:\n php -f convert.php — -filetype -month -year\n php -f convert.php — -png -07 – 1997\n _MIND THE — !!_ \n”);
$sdir = getcwd ();
echo “Sourcefolder: “.$sdir.” …\n”;
$tdir = $sdir.”/converted”;
$ext = substr($argv[1], 1);
$month = substr($argv[2], 1);
$year = substr($argv[3], 1);
echo “$ext-$month-$year\n”;
$time = mktime(12, 0, 0, $month, 15, $year);
echo $time.”\n”;
@mkdir($tdir);
if ($handle = @opendir($sdir)) {
while (false !== ($file = readdir($handle)))
if($file != “.” and $file != “..” and $file != “converted”){
$filearray = explode(“.”, $file);
array_pop($filearray);
$newfile = $tdir.”/”.implode(“.”, $filearray).”.png”;
echo “convert $sdir/$file $newfile\n”;
system ( “convert $sdir/$file $newfile” );
echo “set Date to: “.date(“d.m.y”, $time).”\n”;
touch ($newfile, $time);
}
}
?>
Tut genau das was es soll…
Aufgerufen wird er mit
php -f convert.php
Danach wird einem gesagt, was man an Parametern übergeben kann/soll/darf/muss.
Nun bleibt mir nur noch, mich mit meiner eigenen Vergangenheit in Form von Fotos konfrontiert zu sehen ^^.
svn: Can't move 'xyz/.svn/tmp/entries' to 'xyz/.svn/entries': Operation not permitted
Diese Fehler sprang mir grade entgegen, nachdem ich mal wieder ein
svn up
machen wollte.
Nach genauerer Betrachtung, stellte ich dann fest, dass
xyz/.svn/entries
nur Lesesrechte hat.
Ein
sudo chmod 777 xyz/.svn/entries
half leider auch nichts:
chmod: ./xyz/.svn/entries: Operation not permitted
Das fand ich dann schon ziemlich dreist irgendwie :-D.
Letztendlich half mir ein:
cp xyz/.svn/entries xyz/.svn/entries2 sudo rm xyz/.svn/entries cp xyz/.svn/entries2 xyz/.svn/entries sudo chmod 777 xyz/.svn/entries
Was zwar auf dem ersten Blick ein wenig aufwendig erscheint, aber in Form eines bash-scriptes angenehm die Arbeit übernimmt.
Allerdings weiß ich jetzt immer noch nicht WARUM dieser Fehler kommt.
Letztendlich habe ich mich ja daran gewöhnt, dass subversion meint, . hätte ein Lock….
Wenn mir da jemand mal erklären könnte, ob ich da was falsch mache oder wie… das fände ich mal toll :-).
During my experiences with IPMI i figured out, that there is an issue with the build in ipmitool for MacOs.
If you want to use the IPMI 2.0 protocol (needed for Serial over Lan (SOL) ), you have to add an “-I lanplus” to the ipmitool command.
The problem is, that there is no such parameter in the original MacOs version.
So you have to recompile your own version:
Go to
http://ipmitool.sourceforge.net and download the source code.
You have to make sure, that you already have installed the common build enviroment (xCode).
You have to find out where the original version of ipmitool is:
# whereis ipmitool
# /usr/bin/ipmitool
So after you extracted the ipmitool source you have to configure it with the right path:
# ./configure –prefix=/usr/
This tells the compiler, that binary should be placed in /usr/bin/ and the libs should be go to /usr/lib/
You finish with:
# make
# sudo make install
After that you will find your parameter in the help message:
# ipmitool -h
pmitool version 1.8.9
usage: ipmitool [options…] <command>
-h This help
-V Show version information
-v Verbose (can use multiple times)
-c Display output in comma separated format
-d N Specify a /dev/ipmiN device to use (default=0)
-I intf Interface to use
-H hostname Remote host name for LAN interface
-p port Remote RMCP port [default=623]
-U username Remote session username
-f file Read remote session password from file
-S sdr Use local file for remote SDR cache
-a Prompt for remote password
-e char Set SOL escape character
-C ciphersuite Cipher suite to be used by lanplus interface
-k key Use Kg key for IPMIv2 authentication
-L level Remote session privilege level [default=ADMINISTRATOR]
Append a ‘+’ to use name/privilege lookup in RAKP1
-A authtype Force use of auth type NONE, PASSWORD, MD2, MD5 or OEM
-P password Remote session password
-E Read password from IPMI_PASSWORD environment variable
-m address Set local IPMB address
-b channel Set destination channel for bridged request
-l lun Set destination lun for raw commands
-t address Bridge request to remote target address
-o oemtype Setup for OEM (use ‘list’ to see available OEM types)
-O seloem Use file for OEM SEL event descriptions
Interfaces:
lan IPMI v1.5 LAN Interface [default]
lanplus IPMI v2.0 RMCP+ LAN Interface
Commands:
raw Send a RAW IPMI request and print response
i2c Send an I2C Master Write-Read command and print response
spd Print SPD info from remote I2C device
lan Configure LAN Channels
chassis Get chassis status and set power state
power Shortcut to chassis power commands
event Send pre-defined events to MC
mc Management Controller status and global enables
sdr Print Sensor Data Repository entries and readings
sensor Print detailed sensor information
fru Print built-in FRU and scan SDR for FRU locators
sel Print System Event Log (SEL)
pef Configure Platform Event Filtering (PEF)
sol Configure and connect IPMIv2.0 Serial-over-LAN
tsol Configure and connect with Tyan IPMIv1.5 Serial-over-LAN
isol Configure IPMIv1.5 Serial-over-LAN
user Configure Management Controller users
channel Configure Management Controller channels
session Print session information
sunoem OEM Commands for Sun servers
kontronoem OEM Commands for Kontron devices
picmg Run a PICMG/ATCA extended cmd
fwum Update IPMC using Kontron OEM Firmware Update Manager
firewall Configure Firmware Firewall
exec Run list of commands from file
set Set runtime variable for shell and exec
hpm Update HPM components using PICMG HPM.1 file
So concerning my first try of a web based zfs managment interface i will restart the project with some new conditions:
The Beginning ^^:
So my first task is to bring an overview of all system-disks (other devices are not necessary at the moment) into my ruby context.
So basic system command is:
root@sunny:~# format < /dev/null
Searching for disks…
The device does not support mode page 3 or page 4,
or the reported geometry info is invalid.
WARNING: Disk geometry is based on capacity data.
The current rpm value 0 is invalid, adjusting it to 3600
done
c3t0d0: configured with capacity of 18.61GB
AVAILABLE DISK SELECTIONS:
0. c0d0 <DEFAULT cyl 3734 alt 2 hd 255 sec 63>
/pci@0,0/pci-ide@11,1/ide@0/cmdk@0,0
1. c3t0d0 <ST92011A–3.04 cyl 2430 alt 2 hd 255 sec 63>
/pci@0,0/pci925,1234@11,3/storage@2/disk@0,0
Specify disk (enter its number):
Beside of the interesting warning, this will do the job. The format command will normally lead to a prompt. To avoid this, you just pipe the output to /dev/null.
The really valuable stuff is in the upper part of the output.
After consulting the ruby API about strings and arrays i ended up with the following (dirty) lines of code:
#!ruby
#!/usr/local/bin/ruby -rubygems
s = %x{format < /dev/null}
sa = s.split(“\n”)
counter = 0
dsk = false
puts “Array: “+sa.length().to_s()
sa.map do |i|
if i.strip().length() > 0
print counter.to_s()+” ”
if counter == (sa.length()-1)
dsk = false
end
if dsk == true
puts “DSK: “+i.strip()+”\n”
else
puts i.strip()+”\n”
end
if i.eql?(“AVAILABLE DISK SELECTIONS:”)
dsk = true
end
end
counter += 1
end
I found a really nice post about the ruby command line interface. That post gave me a good start in experimenting with the produced string output. You just always remember the irb to test parts of your code. Of course there is _A_Lot_ of debugging code. But the end-result is correct. Of course there should no hard-coded string in there. A by the way: it was a little bit inconvenient to quarrel again with the integer<->string conversion after some relaxing and luxurious years coding Java ^^. Okay so no implicit casting in ruby (?). Oh wait a minute – no typed language, so no casting?.
Oh yes… i don’t want to hide the output:
root@sunny:~$ ruby cmd.rb
The device does not support mode page 3 or page 4,
or the reported geometry info is invalid.
WARNING: Disk geometry is based on capacity data.
The current rpm value 0 is invalid, adjusting it to 3600
Array: 12
0 Searching for disks…
1 done
3 c3t0d0: configured with capacity of 18.61GB
6 AVAILABLE DISK SELECTIONS:
7 DSK: 0. c0d0 <DEFAULT cyl 3734 alt 2 hd 255 sec 63>
8 DSK: /pci@0,0/pci-ide@11,1/ide@0/cmdk@0,0
9 DSK: 1. c3t0d0 <ST92011A–3.04 cyl 2430 alt 2 hd 255 sec 63>
10 DSK: /pci@0,0/pci925,1234@11,3/storage@2/disk@0,0
11 Specify disk (enter its number):
So i guess i found my disks. At the end, i can just iterate about the even number of entries :-).
Okay ruby-gurus. How can i optimize my code. I am beginner level and “slurred” during years, coding Java and anciently PHP.
I am sure there is a lot of potential to cleanup this mess ^^.
I tried The Camping Short, Short Example for the ruby camping framework.
#!ruby #!/usr/local/bin/ruby -rubygems require 'camping' Camping.goes :HomePage module HomePage::Controllers # The root slash shows the `index' view. class Index < R '/' def get render :index end end # Any other page name gets sent to the view # of the same name. # # /index -> Views#index # /sample -> Views#sample # class Page < R '/(\w+)' def get(page_name) render page_name end end end module HomePage::Views # If you have a `layout' method like this, it # will wrap the HTML in the other methods. The # `self << yield' is where the HTML is inserted. def layout html do title { 'My HomePage' } body { self << yield } end end # The `index' view. Inside your views, you express # the HTML in Ruby. See http://code.whytheluckystiff.net/markaby/. def index p 'Hi my name is Charles.' p 'Here are some links:' ul do li { a 'Google', :href => 'http://google.com' } li { a 'A sample page', :href => '/sample' } end end # The `sample' view. def sample p 'A sample page' end end
It seems to be very easy to create the separat pages.
The example above generates one entry page. (the index method in Views) and one additional page (sample method).
As far as i should know it from rails, it uses the same MVC pattern and theres is a similar syntax. Just the Views are in native ruby without mixing up with html.
But maybe that will appear later on.
The next step is to see howto connect ruby with some inner sys-functions of nexenta ^^.
Just a short one:
After succeeding in installing ruby gems, i finally was able to install the ruby micro-framework camping.
So ruby should just be used as a small administration web interface. In my eyes a rails aproach seems to be like breaking a fly on the wheel.
Just easy as this:
root@sunny:~# gem install camping –source http://code.whytheluckystiff.net
…
Installing ri documentation for markaby-0.5…
Installing ri documentation for camping-1.5.180…
Installing RDoc documentation for activesupport-1.4.2…
Installing RDoc documentation for builder-2.1.1…
Installing RDoc documentation for markaby-0.5…
Installing RDoc documentation for camping-1.5.180…
Smooth and easy. Ready to rumble ;-).
Next in the row is the installation of the ruby gems package.
So it should be easy… just following the instructions.
So…..
root@sunny:~# wget http://rubyforge.org/frs/download.php/38647/rubygems-1.2.0.zip
root@sunny:~# unzip rubygems-1.2.0.zip
root@sunny:~# cd rubygems-1.2.0
root@sunny:~# ruby setup.rb config
./lib/rubygems/spec_fetcher.rb:1:in `require’: no such file to load — zlib (LoadError)
from ./lib/rubygems/spec_fetcher.rb:1
from ./lib/rubygems/source_index.rb:10:in `require’
from ./lib/rubygems/source_index.rb:10
from ./lib/rubygems.rb:767:in `require’
from ./lib/rubygems.rb:767
from setup.rb:22:in `require’
from setup.rb:22
Welcom to error world ;-).
Okay…. should be easy to solve:
root@sunny:~# apt-get install libzlib-ruby zlib1g-dev
or for 64bit Plattforms:
root@sunny:~# apt-get install libzlib-ruby lib64z1-dev
But still the same Error!
Finally i found something in the Weblog of Lucas Chan.
Hm its about readhat/centos…. okay why not.
Just go to the ruby sources:
root@sunny:~# cd /usr/local/src/ruby-1.8.6-p110/
root@sunny:~# cd ext/zlib
root@sunny:~# ruby ruby extconf.rb –with-zlib-include=/usr/include –with-zlib-lib=/usr/lib
checking for deflateReset() in -lz… yes
checking for zlib.h… yes
checking for kind of operating system… Unix
creating Makefile
root@sunny:~# make
root@sunny:~# make install
and finally:
root@sunny:~# cd /usr/local/src/rubygems-1.2.0/
root@sunny:~# ruby setup.rb config
….
== Thanks
Keep those gems coming!
— Jim & Chad & Eric (for the RubyGems team)
Again: something learned!
Da das ja heute bei der Tafelrunde eher etwas zusammengesucht war, habe ich mich noch mal hingesetzt und mir die Dinge an-/eingelesen.
Ich werde einfach mal versuchen die Fragen, die da aufkamen wiederzugeben und dann mit passenden Texten beantworten:
Schamlos kopiert von http://de.wikipedia.org/wiki/Multicast – teiweise gekürtzt und ein wenig angepasst.
Die Formulierungen sind auf die frühe Stunde zurück zu führen.
Anschließend zur Entspannung noch ein wenig Java – ein einfacher Chat-Server:
Zuerst der “Server” – Der ja eigentlich auch Teil jedes Clients ist:
public class NameServer{ // the multicast group address sent to new members private static final String GROUP_HOST = "228.5.6.7"; private static final int PORT = 1234; // for this server private static final int BUFSIZE = 1024; // max size of a message private DatagramSocket serverSock; // holds the names of the current members of the multicast group private ArrayList groupMembers; try { // try to create a socket for the server serverSock = new DatagramSocket(PORT); }catch(SocketException se){ System.out.println(se); System.exit(1); } groupMembers = new ArrayList(); waitForPackets(); // das ist dann hier wieder die typische Server-While-Schleifen-Methode private void waitForPackets(){ DatagramPacket receivePacket; byte data[]; System.out.println("Ready for client messages"); try { while (true) { data = new byte[BUFSIZE]; // set up an empty packet receivePacket = new DatagramPacket(data, data.length); serverSock.receive( receivePacket ); // wait for a packet // extract client address, port, message InetAddress clientAddr = receivePacket.getAddress(); int clientPort = receivePacket.getPort(); String clientMsg = new String( receivePacket.getData(), 0, receivePacket.getLength() ).trim(); processClient(clientMsg, clientAddr, clientPort); } }catch(IOException ioe){ System.out.println(ioe); } } ... }
Und hier dann noch mal der “Client”-Anteil:
public class MultiChat { // timeout used when waiting in receive() private static final int TIME_OUT = 5000; // 5 secs // max size of a message private static final int PACKET_SIZE = 1024; // NameServer address and port constants private static final String SERVER_HOST = "localhost"; private static final int SERVER_PORT = 1234; /* The multicast port. The multicast group address is obtained from the NameServer object. */ private static final int GROUP_PORT = 5555; // for communication with the NameServer private DatagramSocket clientSock; private InetAddress serverAddr; // for communication with the multicast group private MulticastSocket groupSock; private InetAddress groupAddr; public MultiChat(String nm){ /* Attempt to register name and get multicast group address from the NameServer */ makeClientSock(); waitForPackets(); } // end of MultiChat(); private void makeClientSock(){ try { // try to create the client's socket clientSock = new DatagramSocket(); clientSock.setSoTimeout(TIME_OUT); // include a time-out }catch( SocketException se ) { se.printStackTrace(); System.exit(1); } try { // NameServer address string --> IP no. serverAddr = InetAddress.getByName(SERVER_HOST); }catch( UnknownHostException uhe) { uhe.printStackTrace(); System.exit(1); } } // end of makeClientSock() private void waitForPackets(){ DatagramPacket packet; byte data[]; try { while (true) { data = new byte[PACKET_SIZE]; // set up an empty packet packet = new DatagramPacket(data, data.length); groupSock.receive(packet); // wait for a packet processPacket(packet); } }catch(IOException ioe){ System.out.println(ioe); } } // end of waitForPackets() }
Wie man ziemlich gut erkennen kann, ist es auch nicht wesentlich anders, als wenn man sich direkt Sockets erstellt. Gefunden habe ich das Ganze in dem Buch “Killer Game Programming in Java” – heißt wirklich so – hin und wieder finden sich da wirklich interessante Dinge besprochen (Link: hier!).
So das wars.
Die Tage wollte ich noch mal bissel was zu OSGi schreiben – so denn das schöne Buch ankommt.
Und aus – leider aktuellem Anlass – zu IPMI und wieso es eigentlich schon fast unverschämt ist, dass ein _mitgelieferetes_ Linux-Tool fehlerhaft ist und deswegen vom Hersteller empfohlen wird, extra dafür ein Windows aufzusetzen. Nichts gegen Windows, aber wieso liefert man ein fehlerhaftes Tool dann mit?
P.S.: Schreibt mal wieder 😉