Heim  >  Artikel  >  Java  >  Memo für Anfänger zum Erlernen von Java (6)

Memo für Anfänger zum Erlernen von Java (6)

黄舟
黄舟Original
2016-12-20 13:51:28989Durchsuche

Nachdem wir das eigentliche Konzept durch das Programm festgelegt haben, sollten wir nun zur ursprünglichen Frage zurückkehren: Was ist Socket? Es besteht kein Zweifel daran, wie wir es am einfachsten verstehen können Sprache zum Vergleichen von Bildern? Wie wäre es mit einer unvoreingenommenen Beschreibung von Sockets in seinem Buch „Java Programming Thoughts“:
Ein Socket ist eine Software-Abstraktion für den „Terminal“ der Verbindung zwischen zwei Maschinen. Für eine bestimmte Verbindung gibt es auf jeder Maschine eine Steckdose, oder Sie können sich ein virtuelles „Kabel“ zwischen ihnen vorstellen, wobei jedes Ende des „Kabels“ in eine Steckdose gesteckt wird. Natürlich sind die physische Hardware und die Verkabelung zwischen den Maschinen völlig unbekannt. Der ganze Zweck der Abstraktion besteht darin, uns daran zu hindern, die Details zu kennen, die wir nicht wissen müssen.

Abstrakt ausgedrückt ist ein Socket nach meinem Verständnis ein Telefonhörer. Sie haben einen, und der Die Person, mit der Sie sprechen, hat jedoch auch einen. Der Empfänger der einen Person heißt jedoch ServerSocket, und der Empfänger der anderen Person heißt Socket. Es spielt keine Rolle, wer ServerSocket und wer Socket ist, da der Client und der Server von Natur aus gleich sind relativ und kann ineinander umgewandelt werden. Durch das Abheben von zwei Ohrhörern wird ein Kanal hergestellt. Ob dieser Kanal geöffnet ist, hängt davon ab, ob beide Parteien die Ohrhörer abgenommen haben Es sind nur einige Pieptöne zu hören, die bestätigen, dass die Kanäle unterschiedlich sind. Hier ist der Vorgang des Abhebens des Hörers der Vorgang der Socket-Initialisierung. Nachdem der Kanal eingerichtet wurde, d. h. nachdem alle den Hörer abgenommen haben Die Enden des Kanals können hier mit dem Sprechen beginnen, nämlich A spricht mit B, B antwortet, B spricht mit A und A hört zu. Diese beiden Prozesse werden über zwei Leitungen übertragen Der Stream verbirgt alle Details der Übertragung und lässt beide Kommunikationsparteien denken, dass das, was sie übertragen, der Ton ist, nicht die Codierung.

Das zuvor geschriebene serverseitige Programm ist tatsächlich ein Single-. Der Verarbeitungsmechanismus des Servers für den Client besteht darin, dass er nur eine Verbindung gleichzeitig verarbeiten kann. Da handleConnection eine kontinuierliche Schleifenblockierungsmethode verwendet, wird eine verarbeitet, und wenn eine erkannt wird, eine andere Wenn mehrere Verbindungen gleichzeitig eine Anfrage stellen, kann ein solches Programm nicht mit mehreren Verbindungen im Netzwerk umgehen, da nicht garantiert werden kann, dass nur ein Client eine Verbindungsanfrage stellt Der Server gleichzeitig, und es ist denkbar, dass die Geschwindigkeit der Verwendung der Blockierungsmethode zur Bewältigung mehrerer Client-Verbindungen langsam sein wird.

Dies führte offensichtlich zu einer auf mehrere Verbindungen ausgerichteten Version kann durch Multithreading erreicht werden. Da das zu lösende Problem darin besteht, Client-Verbindungen zu bearbeiten, ist das Prinzip nicht schwer abzuleiten Nachdem Sie eine Verbindungsanforderung erkannt haben, erstellen Sie sofort einen Thread, um diese zu verarbeiten, und hören Sie dann weiter auf die nächste Verbindungsanforderung. Daher müssen wir nur den ursprünglichen Code in handleConnection belassen. Er kann automatisch in den Ausführungscode eingefügt werden Der Thread und der Code zum Erstellen eines neuen Threads können der handleConnection hinzugefügt werden. Es ist sehr einfach.

Im gleichen Stil wie im vorherigen Artikel, schauen wir uns die Codedetails jedes Teils an.
Zuerst Erstellen Sie die Klasse MultiThreadRemoteFileServer für diese Multithread-Version

Sehen Sie sich die Definition dieser Klasse an
import java.io.*;
import java.net.*;

public class MultiThreadRemoteFileServer{
PROtected int listenPort;
public MultiThreadRemoteFileServer(int aListenPort){
}
public static void main(String[] args) {
}
public void AcceptConnections( ) {
}
public void handleConnection(Socket incomingConnection) {
}
}

ist fast dasselbe wie RemoteFileServer, der einzige Unterschied besteht in der Klasse, die wir jetzt erstellt haben. Ein Konstruktor ist hinzugefügt, damit die Abhörportnummer von uns selbst bestimmt werden kann. Sie ist wie folgt definiert:

public MultithreadedRemoteFileServer(int aListenPort) {
listenPort = aListenPort;
}

Sehen wir uns das an at main() first
public static void main(String[] args) {
MultithreadedRemoteFileServer server = new MultithreadedRemoteFileServer(3000);
server.acceptConnections();
}

Es gibt keinen Unterschied, es ist dasselbe wie die main()-Funktion von RemoteFileServer, außer dass die Portnummer beim Erstellen vom Hauptprogramm angegeben wird.

Die Änderungen, über die wir uns hauptsächlich Sorgen machen, liegen im Hintergrund
Schauen Sie sich nun das AcceptConnection-Listener-Programm an
public void AcceptConnections() {
try {
ServerSocket server = new ServerSocket( listenPort, 5); // Ist Ihnen beim Erstellen des Server-Sockets ein zusätzlicher Parameter aufgefallen? Dieser Parameter wird verwendet, um die maximale Anzahl von Verbindungen anzugeben, die gleichzeitig beantragt werden können. Der Standardwert ist 50
Socket incomingConnection = null;
while (true) {
incomingConnection = server.accept();
handleConnection(incomingConnection);
}
} Catch (BindException e) {
System.out.println("Binden an Port nicht möglich " + listenPort);
} Catch (IOException e) {
System.out.println("ServerSocket konnte nicht an Port instanziiert werden: " + listenPort);
}
}

Die einzige Änderung ist ein weiterer Parameter. Hier ist der Funktionsmechanismus. Angenommen, wir geben an, dass der Rückstandswert 5 beträgt und fünf Clients Verbindungen zu unserem Server anfordern. Unser Server beginnt mit der Verarbeitung der ersten Verbindung, die Verarbeitung dieser Verbindung wird jedoch lange dauern. Da unser ausstehender Wert 5 ist, können wir fünf Anfragen gleichzeitig in die Warteschlange stellen. Wir arbeiten an einem, das heißt, es warten noch fünf weitere. Insgesamt warten sechs auf die Bearbeitung. Wenn unser Server immer noch damit beschäftigt ist, Verbindung Nr. 1 zu akzeptieren (denken Sie daran, dass sich noch Nr. 2 bis 6 in der Warteschlange befinden), wenn ein siebter Client eine Verbindungsanforderung stellt, wird der siebte Client abgelehnt.

Weiter Unsere nächste Änderung betrifft offensichtlich die Methode handleConnection, die den überwachten Thread verarbeitet. Wie bereits erwähnt, generieren wir in der Multithread-Version sofort einen Thread, wenn wir eine Verbindungsanforderung erkennen, und ignorieren ihn. Dann ist hier ein Satz um einen neuen Thread zu erstellen.

public void handleConnection(Socket ConnectionToHandle) {
new Thread(new ConnectionHandler(connectionToHandle)).start();
}

Das ist uns aufgefallen Es gibt eine neue Klasse ConnectionHandler. Diese Klasse ist Runnable, eine Schnittstellenklasse (dies ist ein Thread, der mithilfe einer Schnittstelle implementiert wird). Wenn Sie es nicht verstehen, können Sie einen Blick auf Nr. 17 werfen (etwas über Threads). Wir Verwenden Sie ConnectionHandler, um einen neuen Thread zu erstellen und ihn zu starten. Wie wir gerade gesagt haben, wurde der Code in der handleConnection von RemoteFileServer intakt in die run()-Methode dieser Schnittstellenklasse ConnectionHandler übertragen.

Dann werfen wir einen Blick auf die gesamte ConnectionHandler-Klasse. Definieren Sie sie.

class ConnectionHandler implementiert Runnable {
protected Socket socketToHandle;
public ConnectionHandler(Socket aSocketToHandle) {
socketToHandle = aSocketToHandle;//Übergeben Sie durch den Konstruktor die zu verarbeitende Socket-Instanz als Parameter Komm rein
}
public void run() {//Der Originalcode zum Lesen/Schreiben von Socket ist alles hier
try {
PrintWriter streamWriter = new PrintWriter(socketToHandle.getOutputStream());
BufferedReader streamReader = new BufferedReader(new InputStreamReader(socketToHandle.getInputStream()));

String fileToRead = streamReader.readLine();
BufferedReader fileReader = new BufferedReader(new FileReader(fileToRead)) ;

String line = null;
while ((line = fileReader.readLine()) != null)
streamWriter.println(line);

fileReader.close( );
streamWriter.close();
streamReader.close();
} Catch (Exception e) {
System.out.println("Fehler bei der Behandlung eines Clients: " + e);
}
}
}

Was die run()-Methode von ConnectionHandler tut, ist das, was handleConnection() auf RemoteFileServer tut. Wickeln Sie zunächst InputStream und OutputStream (mithilfe von getOutputStream() und getInputStream() von Socket) in BufferedReader bzw. PrintWriter ein. Dann verwenden wir diese Codes, um die Zieldatei Zeile für Zeile zu lesen. Da der Dateipfad im InputStream geladen wird, müssen wir den FileReader-Stream verwenden, um den Dateipfad in der Mitte einzuschließen, und ihn dann über das BufferedReader-Paket auslesen.

Unsere Multithreading-Serverstudie ist abgeschlossen. Sehen wir uns noch einmal die Schritte zum Erstellen und Verwenden der „Multithread-Version“ des Servers an:

1 Ändern Sie AcceptConnections() Verwenden Sie den Standardwert 50 (oder einen beliebigen Wert, der größer als 1 ist. Geben Sie eine Zahl an), um ServerSocket zu instanziieren.

2. Ändern Sie handleConnection() von ServerSocket, um einen neuen Thread mit einer Instanz von ConnectionHandler zu generieren.

3. Leihen Sie sich den Code der handleConnection()-Methode von RemoteFileServer aus, um die run()-Funktion der ConnectionHandler-Klasse zu implementieren.

Das Obige ist der Inhalt des Memos (6) für Anfänger, die Java lernen. Weitere verwandte Inhalte finden Sie auf der chinesischen PHP-Website (www.php.cn).


Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn