Im Moment, während Sie diese Seite lesen, sind Sie mit ziemlicher Sicherheit gerade online mit Ihrem Provider verbunden. Doch haben Sie sich dabei, während die Statusdioden an Ihrem Modem so richtig schön am Blinken und Flackern sind, nicht auch schon überlegt, aus Ihrem selbstgeschriebenen BASIC-Programmierprojekt heraus direkt auf Ihr Modem oder lokales Netzwerk (LAN) zuzugreifen, um beispielsweise ein voll netzwerkfähiges Spiel wie Rasterbike für mehrere Spieler zu programmieren? Was die Profis bei Spieltitel wie Quake, Duke & Co. können, können Sie mit QuickBASIC genauso gut, wie Sie im folgenden soeben sehen werden.
In diesem Sinne soll dieser Artikel auch bei Ihnen das Wasser im Mund fliessen lassen :-).
Die Grundbasis jeder Kommunikation übers Internet bilden sog. Sockets, also durchgeschaltete, virtuelle
Verbindungen ähnlich wie beim Telefonnetz. Als Kommunikationsprotokoll
kommt dabei das Ihnen bestens bekannte TCP/IP zum Einsatz. Verbindungen
erfolgen immer zwischen zwei Hosts, wobei der eine Rechnerknoten die Rolle vom
Server übernimmt und dort mit bind()
auf einer
beliebigen Portnummer passiv mit listen()
auf eine
eingehende Verbindung wartet. Sobald es »klingelt«, wird der
Verbindungswunsch mit accept()
entgegengenommen. Der andere
Rechnerknoten, also der Client, nimmt mit connect()
die
Verbindung mit dem Server auf, wobei die IP-Adresse zusammen mit der
Dienstportnummer der »Telefonnummer« entspricht. Steht die
Verbindung (in UNIX/Linux sehen Sie dies mit netstat, auch Windows
bietet Ihnen dieses Kommando an), so können die beiden Hosts einander
gegenseitig nach Belieben Bytes zusenden. Aus Ihrer Sicht als
BASIC-Programmierer funktioniert das Ganze nahezu identisch wie wenn Sie mit
OPEN "COM2:9600,N,8,1" AS #1
eine RS-232-Verbindung aufgebaut haben.
Wenn Sie also bereits eine Anwendung haben, die über RS-232 kommuniziert,
ist es also keinen grossen Schritt mehr, die Anwendung voll Internet-tauglich
zu erweitern. Analog dem Auflegen beim Telefon kann einer der Rechner mit
close()
die Verbindung schliessen, der Partner sieht dann den
Trennwunsch als gesetztes
EOF()
ganz analog, wie Sie es von sequentiellen Dateien her kennen
und führt dann ebenfalls close()
aus.
Das Höchste der Gefüge, welches Ihnen QuickBASIC mit seinem
internen Befehlssatz anbietet, ist das
ACCESS
-Schlüsselwort, um auf einem Netzwerklaufwerk
exklusiven Zugriff auf Dateien zu ermöglichen. Ansonsten hat QuickBASIC
leider :-( keine weiteren Befehle für die
direkte Socket-Programmierung, weshalb die hier gezeigte Lösung
vollständig auf DOS-Interrupts
basiert.
Für die hier gezeigten Beispiele benötigen Sie
wegen CALL INTERRUPT
den QuickBASIC-Compiler! Falls Sie aber noch
mit dem bei MS-DOS beiliegenden QBASIC.EXE oder gar
GWBASIC.EXE arbeiten, müssen Sie eine mit CALL
Adresse aufrufbare Maschinensprache-Routine für den
DOS-Interrupt-Aufruf selber schreiben, wie im Artikel über DOS-Interrupts beschrieben.
Netzwerke wie das Internet sind nach dem bekannten ISO-OSI-7-Schichtenmodell aufgebaut. Auf der untersten Schicht befindet sich dabei Ihr Modem oder die Netzwerkkarte, auf dieser setzt dann der TCP/IP-Stack als softwaremässige Basis-Infrastruktur für das Bereitstellen von Sockets auf. Zwischen Hardware und TCP/IP-Stack fungiert dann noch der Netzwerkkarten- oder DFÜ-Treiber. Innerhalb Ihres BASIC-Programms kommunizieren Sie daher nie direkt mit dem Modem oder der Netzwerkkarte selber, sondern immer über die Anwendungsschnittstelle vom TCP/IP-Stack selber!
Als ich meinen ersten Netzwerk-Programmierversuch mit QuickBASIC unternahm, war das Hauptproblem einen geeigneten TCP/IP-Stack zu finden, denn das in jedem Windows 95/98/NT vorhandene WINSOCK.DLL arbeitet nur voll 32-Bit, und bisher ist mir aber noch keinen Weg bekannt, aus einer reinen Realmodus-DOS-Anwendung heraus auf 32-Bit-Routinen zugreifen zu können. Aus diesem Grund machte ich mich im Internet selber auf die Suche nach einem TCP/IP-Stack für reines DOS, welcher die Kriterien
erfüllte. Mit Hilfe von Ralf Browns Interrupt-Liste stiess ich dann auf DOSISODE, einer Programmierschnittstelle für Waterloo TCP/IP (WATTCP), welches treibermässig auf dem Pakettreiber basiert.
Die hier beschriebene Anleitung ist auch für Benützer von Rasterbike gedacht.
DOSISODE läuft unter reinem MS-DOS. Im Falle von Windows 3.1x sollten Sie Windows daher ganz beenden. Besitzer von Windows 95 und 98 sollten mit Start, Beenden..., Im MS-DOS-Modus neu starten oder beim Einschalten des PCs mit der Taste F8, Nur Eingabeaufforderung in den reinen DOS-Modus gehen. Als Kommunikationshardware eignet sich entweder ein lokales Netzwerk (LAN) mit Ethernet oder Token Ring oder ein ganz gewöhnlicher Dial-Up-Internetzugang mit PPP-Protokoll über ein Modem, wie ihn beispielsweise BlueWindow oder T-Online für Privatkunden anbieten.
Voraussetzung ist ein zum Hayes-Befehlssatz kompatibles Modem. Ob Ihr Modem diese Anforderung erfüllt, können Sie mit folgendem QuickBASIC-Programm im DOS-Modus testen:
INPUT "Wo ist das Modem angeschlossen"; comx$ OPEN comx$ + ":9600,n,8,1,rs" FOR RANDOM AS 1 DO t$ = INKEY$ IF t$ <> "" THEN PRINT #1, t$; END IF n% = LOC(1) IF n% > 0 THEN h$ = INPUT$(n%, 1) PRINT h$; END IF LOOP UNTIL t$ = CHR$(27) CLOSE 1
Dieses Programm stellt ein oberprimitives Terminalprogramm dar. Zu Beginn geben Sie die COMx-Schnittstelle entsprechend an, anschliessend sollten Sie AT gefolgt von Enter eingeben:
Wo ist das Modem angeschlossen? com2 AT OK
Mit Esc beenden Sie die das Programm wieder. Antwortet Ihr Modem mit OK, so sind sämtliche Voraussetzungen optimal erfüllt :-). Falls es nicht auf Anhieb klappt, so können Sie ATE1 gefolgt von Enter eingeben, um den Echo-Modus zu aktivieren.
Ziemlich ungeeignete Modems sind diese seit neuestem erhältlichen sogenannten WinModems, bei welchen die gesamte Datenpumpe und übrige Geräteintelligenz zwecks Kosteneinsparung weggelassen wurde, sodass die CPU Ihres Rechners dann die gesamte Modulations- und Demodulationsarbeit verrichten muss. Sowieso sind solche Geräte mit den Prozessorgenerationen vor Pentium II völlig unbrauchbar! Ebenso scheiden auch sämtliche USB-Modems aus, ausser ihr Modemtreiber erzeugt eine virtuelle COM-Schnittstelle. Interne ISDN-Karten sind beinahe alle auch ungeeignet, dagegen arbeiten externe Terminaladapter auch wieder mit dem Hayes-Befehlssatz, so dass Sie hiermit ebenfalls eine PPP-Einwählverbindung hinbringen sollten.
Wenn Sie sich gerade erst ein Modem kaufen möchten, so achten Sie am besten gleich zu Beginn darauf, dass es wie hier beschrieben über AT-Befehle angesteuert werden kann. Am besten testen Sie nach Möglichkeit mit dem obigen BASIC-Programm Ihr Wunschgerät schon im Laden.
Die folgende Information konnte ich erst später zusammenstellen: Es ist grundsätzlich möglich, PPP für DOS auch innerhalb einer MS-DOS-Eingabeaufforderung zu nutzen, weil viele Modemtreiber eine virtuelle COM2 oder COM3-Schnittstelle erzeugen. Häufig funktioniert der obige Test über dieses virtuelle Gerät dann doch noch erfolgreich.
Im Falle eines WinModems mit virtueller COMx-Schnittstelle beenden Sie einfach das Windows-eigene DFÜ-Netzwerk (rechte Maustaste über dem Piktogramm rechts unten und dort Trennen wählen), damit das Modem für PPP unter DOS frei wird.
Sämtliche Downloads und Dateivorbereitungsarbeiten können vom normalen Windows-Betrieb aus erledigt werden.
Falls Ihr Modem den Test erfolgreich bestanden hat, sollten Sie als nächstes aus dem Citilink FAQ die Datei DOSPPP05.ZIP herunterladen und im DOS-Bereich Ihrer Festplatte entpacken, beispielsweise nach C:\BASICPRG\DOSPPP.
Nun kommt etwas Konfigurationsarbeit, denn DOS ist ein Betriebssystem, welches noch keinerlei Konfigurationsassistenten kennt wie Windows, so dass Sie manuell im Texteditor EDIT.COM arbeiten müssen. Zunächst einmal sollten Sie Ihre Internet-Zugangsdaten im Detail kennen:
Diese Daten können Sie zum einen aus Ihrer Windows-Installation entnehmen, in dem Sie auf Start -> Einstellungen -> Systemsteuerung, Internetoptionen, Registerkarte Verbindungen gehen. Unter DFÜ-Einstellungen können Sie dann von Ihrem Providerkonto mit Einstellungen... alle Details abrufen. Ausserdem besitzen Sie vielfach auch ein Datenblatt Ihres Providers mit allen Angaben, vielfach finden Sie aber auch auf der Heimseite Ihres Providers im Supportbereich die entsprechenden Informationen, beispielsweise für Blue Window und T-Online.
Die obige Aufzählung dient für eine vollständige Konfiguration, welche sich auch für andere DOS-Internetanwendungen eignet. Falls Sie bestimmte Daten nicht kennen, so können Sie diese auch weglassen.
Die folgenden Angaben stützen sich auf den in der Anleitungsdatei SAMPLES.TXT enthaltenen Beispielen und sind von mir lediglich etwas optimiert worden. Die Konfiguration funktioniert jedoch recht ähnlich wie Linux, da PPPD.EXE eigentlich eine Portierung von pppd aus Linux darstellt. Falls Sie mit Linux arbeiten, werden Sie viel Vertrautes wieder finden. Nachfolgende Dateien sollten Sie also erstellen:
@echo off if _%1==_ goto DIALER if %1==h goto HANGUP if %1==H goto HANGUP goto SYNTERR :HANGUP termin 0x60 echo Connection closed goto END :SYNTERR echo Syntax error, call as %0 or %0 H goto END :DIALER if exist ip-up.bat del ip-up.bat epppdd debug kdebug 1 >>logger.out if errorlevel goto CONNERR if not exist ip-up.bat goto CONNERR call ip-up.bat if exist wattcp.cfg del wattcp.cfg echo my_ip=%MYIP% >wattcp.cfg echo gateway=%REMIP% >>wattcp.cfg echo netmask=%NETMASK% >>wattcp.cfg REM echo netmask=255.255.255.255 >>wattcp.cfg type myisp.dat >>wattcp.cfg REM echo mss=%PEERMRU% >>wattcp.cfg set WATTCP.CFG=C:\BASICPRG\DOSPPP echo Connection succesful echo Falls das erste Mal gestartet, bitte noch echo SOCKETS eingeben. Zum Auflegen %0 H eingeben goto END :CONNERR echo Connection failed... :END
Ganz wichtig ist hierbei die Verwendung von EPPPDD.EXE anstelle vom normalen PPPDD.EXE, weil DOSISODE nur sog. Class 1-Geräte (Ethernet-Netzwerkkarten) unterstützt.
Eine PPP-Verbindung gehört zur Class 6. EPPPDD.EXE simuliert im Grunde genommen das Verhalten einer Ethernet-Karte.
Die Beispieldaten beziehen sich hier auf T-Online.
nameserver=194.25.2.129 nameserver=194.25.0.125 domainslist="btx.dtag.de" smtphost=mailto.t-online.de nntphost=news.btx.dtag.de mailaddr=ihre.mail.adresse@t-online.de
Daten, die Sie von Ihrem Provider nicht ausfindig machen konnten, können Sie auch weglassen, da DOSISODE schon mit sehr wenig Angaben funktioniert.
COM2 115200 irq 3 crtscts local asyncmap 0 connect "chat -v -r ausgabe.txt -f chat.txt" user ihrbenutzername passwd ihrpasswort
Falls Ihr Modem an COM1 angeschlossen ist, benötigen Sie auch häufig IRQ 4. Schauen Sie im Gerätemanager von Windows oder mit MSD.EXE nach, wie die Interrupts auf Ihrem PC belegt sind! Vielfach können (und müssen Sie sogar!) die irq-Zeile weglassen, dies gilt vornehmlich für virtuelle COM-Schnittstellen von WinModems.
TIMEOUT 94 ABORT "NO CARRIER" ABORT BUSY ABORT "NO DIALTONE" ABORT ERROR "" \r+++ATZ "" ~\r~AT\sS7=45\sS0=0\sL1\sV1\sX4\s&c1\sE1\sQ0 OK ATDT0191011 CONNECT \c
Auch diese Angaben habe ich aus der T-Online-Heimseite entnommen.
Mit der Erstellung ist die Konfiguration soweit abgeschlossen, so dass Sie jetzt Ihre Windows-Sitzung beenden und im DOS-Modus neustarten sollten und Ihre Verbindung testen können:
C:\WINDOWS>cd \basicprg\dosppp C:\BASICPRG\DOSPPP>ppp-up Resident size: 75616 coreleft: 4720 COM2 2F8 3: [NS16550A] [cts flow control] 115200 bps MC: int 1 DTR On RTS On CTS On DSR On RI Off CD On RX: int 0 chars 0 hw over 0 hw hi 0 fifo TO 0 sw over 0 sw hi 0 TX: int 0 chars 0 THRE TO 0 main: connect ppp0 <--> COM2. sifdown: IP interface inactive. local IP address 212.185.216.211 remote IP address 212.185.216.1 sifup: IP interface active. Installed packet driver handler at vector 0x60. Connection succesful Falls das erste Mal gestartet, bitte noch SOCKETS eingeben. Zum Auflegen ppp-up H eingeben C:\BASICPRG\DOSPPP>_
Wenn alles wie in dieser Ausgabe geklappt hat, so sehen Sie Ihre dynamisch zugewiesene IP-Adresse sowie die Meldung Connection succesful.
Falls Fehler erscheinen, so findet man in der Protokolldatei C:\BASICPRG\DOSPPP\LOGGER.OUT die genaue Fehlerursache wie beispielsweise ein falsches Passwort, falsche Einwählnummer usw. Diese Datei können Sie mit type oder more betrachten, dabei sind jeweils nur die letzten paar Zeilen interessant. Da MS-DOS keinen tail-Befehl wie UNIX/Linux kennt, mit welchem man diese paar letzten Zeilen herausextrahieren kann, können Sie vor einem Einwählversuch LOGGER.OUT jeweils löschen, um unnötig langes Blättern zu vermeiden.
Für das Auflegen des Modems genügt ppp-up h:
C:\BASICPRG\DOSPPP>ppp-up h Packet driver terminator version 11.1 copyright 1988-1992, Russell Nelson. This program is free software; see the file COPYING for details. NO WARRANTY; see the file COPYING for details. termin: terminate completedConnection closed C:\BASICPRG\DOSPPP>_
Damit können Sie das Kapitel LAN überspringen und direkt zur Installation DOSISODE übergehen.
Voraussetzung ist eine manuelle und feste IP-Adresse, da DOSISODE kein DHCP unterstützt. Am besten fragen Sie im Falle einer Firma Ihren Netzwerkadministrator oder verwenden ganz einfach dieselben Parameter wie in Windows oder Linux, falls Ihr PC mit einem Boot-Manager mehrere Betriebssysteme verwaltet.
Hierfür benötigen Sie den sog. Packet Driver zu Ihrer Netzwerkkarte. Bei einer hochwertigen Marken-Netzwerkkarte finden Sie diesen auf den beiliegenden Treiberdisketten, so beispielsweise bei 3Com im Verzeichnis A:\PKTDVR. Diesen können Sie direkt in die Datei AUTOEXEC.BAT eintragen:
REM Beispiel für 3Com Etherlink III PCI 3C900 LH C:\3C900\PKTDVR\3C90XPD REM Beispiel für 3Com Etherlink 3C590 LH C:\3C590\PKTDVR\3C59XPD
Achten Sie dabei darauf, den Standard-Interrupt 0x60 zu verwenden. Falls bei Ihrer Ethernet-Netzwerkkarte kein solcher Treiber beiliegt, schauen Sie bitte auf der Heimseite des Herstellers unter dem technischen Supportbereich im Treiber-Download-Bereich nach, und zwar für das Betriebssystem DOS. Befolgen Sie dann die Anweisungen vom Hersteller, was die nötigen Anpassungen innerhalb der CONFIG.SYS und AUTOEXEC.BAT betrifft.
Falls Sie nicht fündig werden, sollten Sie den Downloadbereich von Crynwr aufsuchen, denn Crynwr bietet Ihnen zu fast jeder Netzwerkkarte den passenden Pakettreiber an, und dies sogar als kostenlose GNU-Programme :-) Für eine alte 3Com 3C503-Ethernetkarte in einem 386er in meinem privaten LAN brauchte ich beispielsweise pktd11.zip und zwar die Datei 3C503.COM mit
REM Beispiel für 3Com Etherlink 3C503 LH C:\3C503N\PKTDVR\3C503 0x60 5 0x310
in der AUTOEXEC.BAT zu laden. Am besten verwenden Sie in Ihrem Fall das Online-Inhaltsverzeichnis von Crynwr, um die für Ihre Netzwerkkarte passende Datei zu finden.
Zunächst einmal erstellen Sie ein Verzeichnis C:\DOSISODE und erstellen dort eine Datei C:\DOSISODE\WATTCP.CFG mit folgendem Inhalt (eigene Daten vom Netzwerk einsetzen!):
my_ip = 192.168.0.4 gateway = 192.168.0.2 netmask = 255.255.255.240 nameserver = 192.168.0.2 nameserver = 192.168.0.3 sockdelay = 60 mss=576 domainslist="hofenlokal.ch" mailserver=mail.hofen.ch nntphost=news.swissworld.com mailaddr=info@dreael.ch
Das Beispiel stammt aus meinem Privat-LAN. Damit DOSISODE und Waterloo TCP/IP generell die Konfiguration findet, sollten Sie noch die Zeile
SET WATTCP.CFG=C:\DOSISODE
in Ihre AUTOEXEC.BAT einfügen. Damit ist die Pakettreiber-Installation abgeschlossen. Im Falle eines Modems wird die Datei WATTCP.CFG von PPP-UP.BAT wegen der dynamisch zugewiesenen IP-Adresse beim Einwählen dynamisch erzeugt.
Zu diesem Zweck laden Sie aus Sunsite die Datei dosisode-runtime.zip (Alternative 1 Alternative 2) herunter. Von dieser 2 MB grossen Datei wird übrigens nur die Datei SOCKETS.EXE benötigt, welche Sie im Falle eines Modems nach C:\BASICPRG\DOSPPP kopieren. Im Falle eines LAN kopieren Sie SOCKETS.EXE nach C:\DOSISODE und ergänzen ausserdem die Datei AUTOEXEC.BAT mit:
REM TCP/IP-Stack LH C:\DOSISODE\SOCKETS
Modembenützer starten dieses Programm jeweils manuell mit sockets, nachdem sie sich eingewählt haben:
C:\BASICPRG\DOSPPP>ppp-up
Resident size: 75616
..
.. (Ausgaben weggelassen)
..
Connection succesful
Falls das erste Mal gestartet, bitte noch
SOCKETS eingeben. Zum Auflegen ppp-up H eingeben
C:\BASICPRG\DOSPPP>sockets
C:\BASICPRG\DOSPPP>_
Zu diesem Zweck laden Sie bitte mein Beispielprogramm TCPIP_D.BAS herunter und kopieren es beispielsweise nach C:\BASICPRG. Gehen Sie nun ins DOS und aktivieren Sie die Modemverbindung zu Ihrem Provider. Im Falle eines LAN starten Sie einfach in der entsprechenden DOS-Konfiguration, welche Ihnen SOCKETS.EXE ordnungsgemäss einrichtet.
Starten Sie anschliessend QB.EXE mit /l qb und öffnen Sie dort das Test- und Demonstrationsprogramm TCPIP_D.BAS. Dieses können Sie normal starten. Als Beispiel rufen wir vom Web-Server des Magazins »Spiegel« die Haupt-Webseite ab:
IP-Adresse des Hostes (z.B. 192.168.0.2)? 194.163.254.145 Portnummer (z.B. 23=UNIX-Telnet-Sitzung, 80=WWW-Server)? 80 Socket erzeugt Verbunden Bereit für Eingaben
Nun geben Sie
GET / HTTP/1.1 1× Return*
Host: www.spiegel.de 2× Return*
*Da viele Webserver unter UNIX laufen, kann es nötig sein, noch
zusätzlich Strg+J
einzugeben, um ein CHR$(10)
zu senden.
Es ist übrigens normal, wenn von der Eingabe nichts erscheint, da ein Webserver kein Terminal-Echo erzeugt. Wenn Sie alles richtig gemacht haben, so sollten Sie als Ausgabe direkt den HTML-Quellcode bekommen:
HTTP/1.1 200 OK
Date: Fri, 19 May 2000 21:04:23 GMT
Server: Apache/1.3.1 (Unix) mod_oas/4.62 PHP/3.0.7
Cache-Control: max-age=7200
Expires: Fri, 19 May 2000 23:04:23 GMT
Transfer-Encoding: chunked
Content-Type: text/html
<!-- Vignette StoryServer 4 Fri May 19 22:55:04 2000 -->
<HTML>
<HEAD>
<META HTTP-EQUIV="Content-Type" CONTENT="text/html">
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="EXPIRES" content="0">
<meta http-equiv="CACHE-CONTROL" content="PRIVATE">
<meta name="DESCRIPTION" content="Home - SPIEGEL ONLINE">
..
.. (weggelassen)
..
href="http://www.manager-magazin.de/" target=_blank>manager magazin</a>
| <a href="/gruppe/" target="_top">SPIEGEL-Gruppe</a>
| <a href="http://media.spiegel.de/" target=_blank>SPIEGEL Media</a>]
</font><br><br></td></tr></table>
</BODY>
</HTML>
Verbindung vom Partner geschlossen
Telnet-Sitzung beendet.
Mit diesem Programm könnten Sie bereits einen ganz einfachen Web-Browser in QuickBASIC selber implementieren! :-) Nach Beenden von QuickBASIC vergessen Sie bitte nicht, die Verbindung mit ppp-up h wieder zu trennen.
Damit ist das Thema Netzwerk-Installation soweit abgeschlossen, so dass Sie sich eine Runde Rasterbike gönnen können bzw. dort mit der Installation weiterfahren können.
DOSISODE setzt seine Schnittstelle auf den DOS-Interrupt 17h, hier finden Sie die zugehörige Dokumentation des API. Falls Sie sich etwas mit ANSI-C auskennen, empfehle ich Ihnen sehr, einen Blick in den Quellcode von SOCKETS.EXE zu werfen, und zwar in die Datei SOCKETS.C, denn aus diesem Code erfahren Sie viele wichtige Details.
Für Ihre eigenen QuickBASIC-Projekte empfehle ich Ihnen die Verwendung von TCPIP_D.BAS als Vorlage zu verwenden. Dieses Beispiel sollte aufgrund seines verhältnismässig einfachen Aufbaus weitgehend selbsterklärend sein. Ansonsten gehe ich hier kurz durch das ganze Programm hindurch:
' Demonstrationsprogramm für TCP/IP unter DOS aus QuickBASIC heraus: ' Oberprimitiver Telnet-Client ' (c) 2000 by Andreas Meile, CH-8242 Hofen SH ' e-Mail: info@dreael.ch WWW: http://www.hofen.ch/~andreas/ ' $INCLUDE: 'qb.bi' DIM dosIntEin AS RegType, dosIntAus AS RegType
Beachten Sie lediglich den Einsatz von QB.QLB wegen den
CALL INTERRUPT
-Aufrufen, in dem Sie QuickBASIC mit /l
qb aufrufen.
' Testen, ob Waterloo TCP mit DOSISODE-Interface geladen wurde dosIntEin.ax = &HE00 ' SI_CHECKLOAD CALL INTERRUPT(&H17, dosIntEin, dosIntAus) IF dosIntAus.cx <> &H1234 THEN PRINT "Sie müssen noch SOCKETS.EXE zusammen mit dem Packet Driver" PRINT "Ihrer Netzwerkkarte laden" END END IF
Mit diesem ersten Aufruf testen wir, ob die TCP/IP-Software überhaupt ordnungsgemäss installiert und geladen wurde. Dabei ist zu sagen, dass die Funktionsnummer immer in AX angegeben wird.
DO INPUT "IP-Adresse des Hostes (z.B. 192.168.0.2)"; ipAdr$ ' R und S sind eigentlich nur "Notnägel", um im Falle eines ' unordnungsgemässen Abbruchs den Socket schliessen zu können ipBin$ = "" SELECT CASE ipAdr$ CASE "s", "S" GOSUB Schliessen PRINT "SI_CLOSE ausgeführt" CASE "r", "R" GOSUB Beenden PRINT "SI_SHUTDOWN ausgeführt" CASE ELSE DO p% = INSTR(ipAdr$, ".") IF p% = 0 THEN EXIT DO ipBin$ = ipBin$ + CHR$(VAL(LEFT$(ipAdr$, p% - 1))) ipAdr$ = MID$(ipAdr$, p% + 1) LOOP ipBin$ = ipBin$ + CHR$(VAL(ipAdr$)) END SELECT LOOP UNTIL LEN(ipBin$) = 4 INPUT "Portnummer (z.B. 23=UNIX-Telnet-Sitzung, 80=WWW-Server)"; portNr%
Hier erfolgt die Benutzereingabe des Zielhosts in Form der IP-Adresse. Unter dem Punkt Einschränkungen von DOSISODE werden Sie übrigens noch erfahren, warum derzeit noch keine Hostnamen wie www.spiegel.de möglich sind. Ansonsten wird hier die Adresse bereits DOSISODE-gerecht in ipBin$ vorbereitet.
' Initialisieren dosIntEin.ax = &H300 ' SI_SOCKET dosIntEin.cx = 1 ' Typ: 1=Stream (TCP), 2=Dgram (UDP) dosIntEin.dx = 1 ' Socket-ID = 1 CALL INTERRUPT(&H17, dosIntEin, dosIntAus) IF dosIntAus.ax <> 0 THEN PRINT "Fehler beim Initialisieren" PRINT "Code:"; dosIntEin.cx END END IF PufSeg% = dosIntAus.cx PufOffs% = dosIntAus.dx DEF SEG = PufSeg% PRINT "Socket erzeugt"
Ab hier wird unser TCP/IP-Socket aufgebaut; dabei folgt DOSISODE dem auf
jedem UNIX und Linux üblichen Berkeley-Standard (BSD). Analog der
Dateinummer von BASIC, um bei PRINT#
und INPUT$()
zwischen mehreren geöffneten Dateien unterscheiden zu können,
übergeben Sie auch hier im DX-Register eine solche Nummer. Gemäss
Quellcode SOCKETS.C können Sie maximal 6 Sockets gleichzeitig
geöffnet haben.
Der Parameterdaten-Austausch erfolgt übrigens über einen von
DOSISODE reservierten Speicherbereich, von welchem wir die Segment- und
Offsetadresse zurückgeliefert bekommen. Auf diesen Speicherbereich werden
wir in QuickBASIC über PEEK()
und POKE
zugreifen.
TCP/IP unterscheidet übrigens noch zwischen Stream- (TCP) und Datagramm-Sockets (UDP). Bei Stream-Sockets gewährleistet Ihnen das Netzwerk vollständige Daten in der korrekten Reihenfolge, wofür aber auch mehr Overhead in Form von Quittungen nötig ist. UDP arbeitet daher schneller und schont die Bandbreite Ihres Modems, dafür können die Daten unvollständig und in irgend einer Reihenfolge am Zielhost angelangen. Bei UDP ist es also so, wie wenn Sie eine Brieftaubenschar wegschicken (Eine Taube entspricht einem Datagramm), bei welcher jede ihre eigene Route wählt und dabei die eine oder andere Taube einem Raubtier zum Opfer fällt. Bei TCP passiert dieser Effekt genauso, nur dass Sie dort bei beiden Poststellen Diener angestellt haben, welche die Lieferung auf Vollständigkeit hin überprüfen und bei Bedarf fehlende Nachrichten nochmals anfordern (Taube mit Dienstmeldung heimwärts schicken), so dass der Empfänger die Botschaft erst bekommt, sobald sie vollständig ist.
' Socket aufbauen dosIntEin.ax = &H500 ' SI_CONNECT dosIntEin.dx = 1 rsockaddr$ = RIGHT$(MKI$(portNr%), 1) + LEFT$(MKI$(portNr%), 1) + ipBin$ ' Daten übertragen: Nur ab dos_buffer+2 ändern FOR i% = 1 TO LEN(rsockaddr$) POKE PufOffs% + i% + 1, ASC(MID$(rsockaddr$, i%, 1)) NEXT i% CALL INTERRUPT(&H17, dosIntEin, dosIntAus) IF dosIntAus.ax <> 0 THEN PRINT "Fehler beim Verbindungsaufbau" PRINT "Code: "; dosIntAus.cx GOSUB Beenden END END IF PRINT "Verbunden"
In diesem Programmteil nimmt Ihr PC den heiss ersehnten Kontakt mit der
Aussenwelt auf. Dazu initialisieren wir die rsockaddr
-Struktur
mit der IP-Adresse von Server-Zielhost und geben ausserdem die Portnummer
ebenfalls an. Das Ganze erfolgt mittels POKE
in diesen
Speicherpuffer. Wenn der Partner die Verbindung akzeptiert hat (dieser
ruft bei sich also SI_ACCEPT
auf), dann ist der Aufruf
erfolgreich, was Sie mit AX=0 erkennen können. Ansonsten erhalten Sie wie
überall den Fehler in CX. Ein typischer Fehler ist CX=61
(ECONNREFUSED
), was dem bekannten Connection refused,
also vom Server abgelehnten Verbindungsaufbauwunsch entspricht.
' Zuerst noch sog. Non-Blocking IO aktivieren, damit Tastatur und Netzwerk- ' Socket zusammen abgefragt werden können dosIntEin.ax = &HB00 ' SI_IOCTL dosIntEin.dx = 1 ' Socket-ID CALL INTERRUPT(&H17, dosIntEin, dosIntAus) PRINT "Bereit für Eingaben"
Dieser Teil ist im Zusammenhang mit Ereignisabfragen noch ganz wichtig: Weil unser
Telnet-Clientprogramm imstande sein muss, die Tastatur und das Netzwerk
gleichzeitig abfragen zu können, müssen wir verhindern
können, dass eine SI_RECVFROM
-Operation das ganze System
blockiert, wenn gerade kein Byte empfangen wurde.
Drinbleib% = -1 WHILE Drinbleib%
Ab hier erfolgt der interaktive Telnet-Terminalbetrieb, wofür wir eine grosse Schleife benötigen.
' Netzwerk-Verbindung prüfen dosIntEin.ax = &H800 ' SI_RECVFROM dosIntEin.cx = 200 ' maximal 200 Zeichen entgegennehmen dosIntEin.dx = 1 ' Socket-ID CALL INTERRUPT(&H17, dosIntEin, dosIntAus) IF dosIntAus.ax = -1 THEN IF dosIntAus.cx = 35 THEN ' EWOULDBLOCK ignorieren (warten!) ELSEIF dosIntAus.cx = 6 THEN ' EBADF als vom Partner ausgelöstes close() behandeln PRINT "Verbindung vom Partner geschlossen" Drinbleib% = 0 ELSE PRINT "Fehler beim Lesen" PRINT "Code:"; dosIntAus.cx GOSUB Schliessen GOSUB Beenden END END IF ELSE FOR i% = 0 TO dosIntAus.ax - 1 z$ = CHR$(PEEK(PufOffs% + 16 + i%)) ' COLOR 5 ' PRINT ASC(z$); ' COLOR 7 PRINT z$; NEXT i% END IF
Wie im Artikel über
Ereignisabfragen beschrieben, erfolgt hier zunächst einmal die Abfrage
des Netzwerks, ob etwas empfangen wurde. Den Leseaufruf können Sie mit
INPUT$()
vergleichen mit einem entscheidenden Unterschied, dass
die Anzahl der zu lesenden Zeichen nur ein Wunsch darstellt, so dass
Sie immer auch mit weniger Zeichen rechnen müssen. Daher
müssen Sie den Rückgabewert immer beachten. Dieses Verhalten
ist übrigens bei jedem UNIX und Linux der Fall, sogar bei MS-DOS arbeitet
ein normaler read()
-Systemaufruf nach diesem Prinzip. Warum
Microsoft bei INPUT$()
stur die angegebene Anzahl Zeichen
erwartet, so dass gerne Einlesen nach Dateiende-Fehler
zustande kommen, ist auch mir ein Rätsel, denn meiner Meinung nach
wäre dasselbe Verhalten wie UNIX bei INPUT$()
wesentlich
zweckmässiger. Falls übrigens keine Zeichen vorliegen, erhalten Sie
eine Fehlermeldung EWOULDBLOCK, welche wir aber mit voller Absicht
ignorieren! Die Daten werden dabei mit PEEK()
aus dem
Pufferbereich geholt, dabei sollten Sie beachten, dass diese erst bei
PufOffs%+16
beginnen, da sich in den ersten 16 Bytes immer noch
die rsockaddr
-Struktur befindet.
' Tastatur prüfen t$ = INKEY$ IF t$ = CHR$(29) THEN Drinbleib% = 0 ELSEIF t$ <> "" THEN WHILE t$ <> "" dosIntEin.ax = &H900 ' SI_SENDTO dosIntEin.cx = LEN(t$) ' Anzahl Zeichen dosIntEin.dx = 1 ' Socket-ID FOR i% = 0 TO LEN(t$) - 1 POKE PufOffs% + 16 + i%, ASC(MID$(t$, i% + 1, 1)) NEXT i% CALL INTERRUPT(&H17, dosIntEin, dosIntAus) IF dosIntAus.ax < 0 THEN PRINT "Fehler beim Schreiben" PRINT "Code"; dosIntAus.cx GOSUB Schliessen GOSUB Beenden END END IF ' Verbleibende, noch nicht versandte Bytes t$ = MID$(t$, dosIntAus.ax + 1) WEND END IF WEND
Bitte beachten Sie auch hier das UNIX/Linux-mässige Verhalten: Die Zahl der zu sendenden Bytes stellt auch hier nur ein Wunsch dar, so dass Sie auch wiederum selber nachsehen sollten, wie viele Bytes effektiv versendet wurden. In unserem Falle wiederholen wir einfach bei Bedarf die Schreiboperation solange, bis alles erfolgreich versendet werden konnte.
Als Benutzer können Sie auch hier die Telnet-Sitzung wie bei jedem Telnet-Client üblich mit Strg+] beenden.
' Beenden GOSUB Schliessen GOSUB Beenden PRINT "Telnet-Sitzung beendet." END
Analog normalen Dateien müssen Sie auch am Schluss jeweils korrekt und sauber schliessen.
Schliessen: ' Zum Schluss Socket schliessen dosIntEin.ax = &HC00 ' SI_CLOSE dosIntEin.dx = 1 ' Socket-ID CALL INTERRUPT(&H17, dosIntEin, dosIntAus) IF dosIntAus.ax <> 0 THEN PRINT "Fehler beim Schliessen" PRINT "Code:"; dosIntAus.cx GOSUB Beenden END END IF RETURN
Hier wird der Socket wiederum geschlossen, aber nur so, dass Sie ohne weiteres wieder neue Sockets erzeugen können.
Beenden: ' Netzwerk-Anwendung ganz beenden dosIntEin.ax = &HD00 ' SI_SHUTDOWN CALL INTERRUPT(&H17, dosIntEin, dosIntAus) RETURN
Und hier wird das gesamte DOSISODE-Subsystem korrekt heruntergefahren. Dies
sollten Sie immer am Schluss auch tun, und zwar dann, wenn alle
Sockets mit SI_CLOSE
geschlossen wurden.
TCP/IP mit DOS ist zugegebenermassen recht umständlich im Zeitalter von Windows, wo Ihnen der Internet-Verbindungsassistent die gesamte Konfiguration erledigt. Daher zeige ich Ihnen noch hier die Grenzen auf und möchte Sie bei dieser Gelegenheit auch gleichzeitig aufrufen, konkrete Verbesserungsvorschläge zukommen lassen.
DOSISODE ist zugegebenermassen schon recht alt, und wie mir der Autor in einer e-Mail mitgeteilt hat, wird es auch nicht mehr von ihm weitergepflegt. Falls Sie aber gute C-Programmierkenntnisse besitzen und Waterloo TCP ebenfalls gut kennen, könnten Sie diese Schnittstelle beliebig erweitern. Insbesondere fehlen in der aktuellen Version:
gethostbyname()
und
gethostbyaddr()
fehlen noch vollständig. Aus diesem Grund
müssen Sie in meinem Demonstrationsprogramm immer die numerische
IP-Adresse angeben. Die Umwandlung von Rechnernamen in IP-Adressen erledigt
Ihnen nslookup unter UNIX/Linux sowie Windows NT:
/home/user> nslookup www.spiegel.de Server: asi486.hofenlokal.ch Address: 192.168.0.2 Non-authoritative answer: Name: www.spiegel.de Address: 194.163.254.145 /home/user> _Unter Windows 95 und 98 sowie WfW 3.11 können Sie mit dem ping-Kommando Rechnernamen auflösen:
C:\WINDOWS>ping www.spiegel.de
PING wird ausgeführt für www.spiegel.de [194.163.254.145] mit 32 Bytes Daten:
Antwort von 194.163.254.145: Bytes=32 Zeit=150ms TTL=240
Antwort von 194.163.254.145: Bytes=32 Zeit=82ms TTL=241
..
.. (weggelassen)
SI_BIND
, SI_LISTEN
und
SI_ACCEPT
sind ebenfalls nicht implementiert (»This function just returns« in Ralf Browns Heimseite).
Aus diesem Grund können Sie momentan nur Client-Anwendungen
programmieren. Dies war übrigens auch der Grund, weshalb ich den Server
für Rasterbike unter UNIX/Linux
entwickelt habe!tcp_tick()
-Aufrufe: Dadurch bleiben Ihnen vor allem serverseitig
die Sockets im LAST_ACK-Zustand hängen. Im Moment helfe ich
mir ab, die Schliessoperation nach Möglichkeit immer zuerst serverseitig
auszuführen, dann passiert dieser Effekt nicht.Von diesen Einschränkungen einmal abgesehen können Sie trotzdem schon recht tolle Projekte damit machen :-).
In einer Newsgroup-Anfrage wurde ich auf INT 2Fh
verwiesen, wo
es anscheinend möglich sein sollte, direkt auf Windows-API-Funktionen
zugreifen zu können. Falls es also Ihnen damit gelingen sollte, auf
beliebige 32-Bit-Funktionen aus Windows-.DLL-Dateien zuzugreifen,
wäre ich Ihnen sehr dankbar, wenn Sie sich sofort bei mir melden würden. Denn
damit könnte TCP/IP mit QuickBASIC auch wirklich
»volkstauglich« gemacht werden und Probleme wie beispielsweise
zuerst ins DOS hinausgehen, wo Sie dann den Chat mit demjenigen Kollegen, mit
welchem Sie Rasterbike spielen
möchten, beenden müssen, wären dann hinfällig :-).