Mehrere Verbindungen gleichzeitig in einem Thread mit ApacheHTTP

7bestman

Mitglied
Hallo,
ich versuche gerad mehrere Verbindungen in einem Thread mit httpcore-nio zu verarbeiten. Ich hab mich an dem Beispiel http://hc.apache.org/httpcomponents...org/apache/http/examples/nio/NHttpClient.java entlang gehangelt, jedoch werden meine Anfragen nacheinander abgearbeitet. Das sieht dann so aus:
Code:
[HTTP] attempting to open http://127.0.1.2:80/bild.zip
[HTTP] attempting to open http://127.0.2.3:80/bild.zip
[HTTP] attempting to open http://127.0.0.1:80/bild.zip
[HTTP] HTTP/1.1 200 OK
[HTTP] Request finished
[HTTP] HTTP/1.1 200 OK
[HTTP] Request finished
[HTTP] HTTP/1.1 200 OK
[HTTP] Request finished

Die Datei ist jeweils etwa 1mb groß, also sollte sie eigentlich einen Moment für die Übertragung benötigen. Verwende ich mehrere Threads, werden auch mehrere Dateien parallel übertragen.

Ich verstehe nicht, warum das nicht funktioniert! :(
Kann mir da jemand helfen?

Gruß,
Olli

Java:
import java.io.IOException;
import java.io.InterruptedIOException;

import org.apache.http.HttpRequestInterceptor;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.DefaultConnectionReuseStrategy;
import org.apache.http.impl.nio.DefaultHttpClientIODispatch;
import org.apache.http.impl.nio.pool.BasicNIOConnPool;
import org.apache.http.impl.nio.reactor.DefaultConnectingIOReactor;
import org.apache.http.impl.nio.reactor.IOReactorConfig;
import org.apache.http.nio.client.methods.AsyncByteConsumer;
import org.apache.http.nio.client.methods.HttpAsyncMethods;
import org.apache.http.nio.protocol.HttpAsyncRequestExecutor;
import org.apache.http.nio.protocol.HttpAsyncRequester;
import org.apache.http.nio.reactor.IOReactorException;
import org.apache.http.params.CoreConnectionPNames;
import org.apache.http.params.CoreProtocolPNames;
import org.apache.http.params.HttpParams;
import org.apache.http.params.SyncBasicHttpParams;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.protocol.HttpProcessor;
import org.apache.http.protocol.ImmutableHttpProcessor;
import org.apache.http.protocol.RequestConnControl;
import org.apache.http.protocol.RequestContent;
import org.apache.http.protocol.RequestExpectContinue;
import org.apache.http.protocol.RequestTargetHost;
import org.apache.http.protocol.RequestUserAgent;

public class HTTPClient {
	private BasicNIOConnPool pool;
	private HttpAsyncRequester requester;
	private DefaultConnectingIOReactor ioReactor;
	private DefaultHttpClientIODispatch ioEventDispatch;

	public HTTPClient() throws IOException {
		init();
	}

	private void init() throws IOReactorException {
		// HTTP parameters for the client
		HttpParams params = new SyncBasicHttpParams();
		params.setIntParameter(CoreConnectionPNames.SO_TIMEOUT, 3000)
				.setIntParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, 3000)
				.setIntParameter(CoreConnectionPNames.SOCKET_BUFFER_SIZE, 32 * 1024)
				.setBooleanParameter(CoreConnectionPNames.TCP_NODELAY, true)
				.setParameter(CoreProtocolPNames.USER_AGENT, "Test/1.1");

		// Create HTTP protocol processing chain
		HttpProcessor httpproc = new ImmutableHttpProcessor(new HttpRequestInterceptor[] {
				// Use standard client-side protocol interceptors
				new RequestContent(), new RequestTargetHost(), new RequestConnControl(), new RequestUserAgent(),
				new RequestExpectContinue() });

		// Create client-side HTTP protocol handler
		HttpAsyncRequestExecutor protocolHandler = new HttpAsyncRequestExecutor();

		// Create client-side I/O event dispatch
		ioEventDispatch = new DefaultHttpClientIODispatch(protocolHandler, params);

		// Create client-side I/O reactor
		IOReactorConfig config = new IOReactorConfig();
		config.setIoThreadCount(1);

		ioReactor = new DefaultConnectingIOReactor(config);

		// Create HTTP connection pool
		pool = new BasicNIOConnPool(ioReactor, params);
		pool.setDefaultMaxPerRoute(8);
		pool.setMaxTotal(64);

		requester = new HttpAsyncRequester(httpproc, new DefaultConnectionReuseStrategy(), params);
	}

	public void execute(HttpGet request, AsyncByteConsumer<Boolean> consumer) {
		requester.execute(HttpAsyncMethods.create(request), consumer, pool, new BasicHttpContext());
	}

	public void start() {
		new Thread(new Runnable() {
			public void run() {
				try {
					ioReactor.execute(ioEventDispatch);
				} catch (InterruptedIOException ex) {
					System.err.println("[HTTP] Interrupted");
				} catch (IOException e) {
					System.err.println("[HTTP] I/O error: " + e.getMessage());
				}

				System.out.println("[HTTP] Shutdown");
			}
		}).start();
	}

	public void stop() {
		try {
			ioReactor.shutdown();
		} catch (IOException e) {
			// ignore
		}
	}
}
 

7bestman

Mitglied
Und wenn ich das ganze mit einem DefaultHTTPAsyncClient mache, macht er jede Anfrage in einem anderen Thread:

Java:
import java.io.IOException;

import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.nio.client.DefaultHttpAsyncClient;
import org.apache.http.nio.client.methods.AsyncByteConsumer;
import org.apache.http.nio.client.methods.HttpAsyncMethods;
import org.apache.http.params.CoreConnectionPNames;

public class HTTPClient {
	private DefaultHttpAsyncClient httpClient;

	public HTTPClient() throws IOException {
		httpClient = new DefaultHttpAsyncClient();
		httpClient.getParams().setIntParameter(CoreConnectionPNames.SO_TIMEOUT, 3000)
				.setIntParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, 3000)
				.setIntParameter(CoreConnectionPNames.SOCKET_BUFFER_SIZE, 32 * 1024)
				.setBooleanParameter(CoreConnectionPNames.TCP_NODELAY, true);

		httpClient.start();
	}

	public void execute(HttpGet request, AsyncByteConsumer<Boolean> consumer) {
		httpClient.execute(HttpAsyncMethods.create(request), consumer, null);
	}
}

:/ Warum kann Java nicht so einfach wie Python sein?
 
M

MultiThreading

Gast
Grundsätzlich gilt : wenn du etwas "parallel" machen willst brauchst du erstmal grundsätzlich Threads. NIO alleine reicht da leider nicht für (das N steht für Non-blocking).
Ich kenne mich zwar nicht mit Apache Commons aus, aber Zeile 63 sieht schon mal verdächtig aus. Wie soll er denn etwas parallel mit mehreren Threads ausführen wenn du ihm ein Thread-Limit von "1" vorschreibst. Ich würde erstmal versuchen was passiert wenn dieser Wert erhöt wird.
Andernfalls ganz einfach mit der SE-API : für jeden Request einfach einen neuen Thread erstellen und darin ablaufen lassen.
 

7bestman

Mitglied
Grundsätzlich gilt : wenn du etwas "parallel" machen willst brauchst du erstmal grundsätzlich Threads. NIO alleine reicht da leider nicht für (das N steht für Non-blocking).
Ich kenne mich zwar nicht mit Apache Commons aus, aber Zeile 63 sieht schon mal verdächtig aus. Wie soll er denn etwas parallel mit mehreren Threads ausführen wenn du ihm ein Thread-Limit von "1" vorschreibst. Ich würde erstmal versuchen was passiert wenn dieser Wert erhöt wird.
Andernfalls ganz einfach mit der SE-API : für jeden Request einfach einen neuen Thread erstellen und darin ablaufen lassen.

Das ist nicht ganz richtig. Um I/O "parallel" auszuführen, benötigt man nur einen einzigen Thread, wenn man eventbasiert arbeitet. Du kannst dem Betriebssystem sagen: "Hier hast du 10 Filedescriptoren, schau du mal bis ich irgendwo von lesen kann und dann sag mir Bescheid, von welchem ich blockierungsfrei lesen kann"
Mehr Infos z.B. hier: Asynchronous I/O - Wikipedia, the free encyclopedia

Das N in NIO steht laut Wikipedia auch nciht für non-blocking sondern für "New IO".

Das ganze Problem hat sich erledigt. Das funktioniert ziemlich genau wie in meinem zweiten Stück Code geschrieben. Meine Übertragung ging nur wirklich zu schnell. Habe es mit einem langsamen Server und größerer Datei probiert, und alles ist super!

Was nun noch schön wäre, wenn ich den HTTPClient im EventDispatcher-Thread einfach 20-30 mal pro Sekunde für ein paar Milisekunden laufen lassen könnte. Dann entfällt nämlich jegliches Synchronisieren mit der UI, weil das komplette Programm sexy in nur einem Thread laufen kann.

Java:
import java.io.IOException;

import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.concurrent.FutureCallback;
import org.apache.http.impl.nio.client.DefaultHttpAsyncClient;
import org.apache.http.impl.nio.conn.PoolingClientAsyncConnectionManager;
import org.apache.http.impl.nio.reactor.IOReactorConfig;
import org.apache.http.nio.client.methods.AsyncByteConsumer;
import org.apache.http.nio.client.methods.HttpAsyncMethods;
import org.apache.http.params.CoreConnectionPNames;

public class HTTPClient {
	private DefaultHttpAsyncClient httpClient;

	public HTTPClient() throws IOException {
		IOReactorConfig ioReactorConfig = new IOReactorConfig();
		ioReactorConfig.setIoThreadCount(1);

		httpClient = new DefaultHttpAsyncClient(ioReactorConfig);
		httpClient.getParams().setIntParameter(CoreConnectionPNames.SO_TIMEOUT, 3000)
				.setIntParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, 3000)
				.setIntParameter(CoreConnectionPNames.SOCKET_BUFFER_SIZE, 32 * 1024)
				.setBooleanParameter(CoreConnectionPNames.TCP_NODELAY, true);

		PoolingClientAsyncConnectionManager mgr = (PoolingClientAsyncConnectionManager) httpClient
				.getConnectionManager();
		mgr.setDefaultMaxPerRoute(16);
		mgr.setMaxTotal(64);

		httpClient.start();
	}

	public void execute(HttpGet request, AsyncByteConsumer<Boolean> consumer) {
		httpClient.execute(HttpAsyncMethods.create(request), consumer, null);
	}

	public void execute(String url, FutureCallback<HttpResponse> future) {
		httpClient.execute(new HttpGet(url), future);
	}
}
 
M

MultiThreading

Gast
"I/O-OPs im EDT" ... AUA ... da wird mir schon beim lesen schlecht. Denn DAS sollte man in Java GRUNDSÄTZLICH vermeiden. I/O-OPs gehören IMMER in einen eigenen Thread. Was du dann in diesem machst ist eigentlich ziemlich egal, aber den EDT mit I/O-OPs zu belasten ist einfach extrem schlechtes Design. Mal davon abgesehen das Java auch nicht "in nur einem Thread" läuft. Es werden gleich zum Start der VM mehreren deamon-Thredas gestartet. Der einzige non-deamon-Thread zum Zeitpunkt des "Starts" ist der "main-Thread" der public static void main(String[]) callt. Zumindest diesen Fehler solltest du dringend beheben.
 

7bestman

Mitglied
Das ist ja Quatsch. Das Ding heißt Event Dispatcher Thread weil dort Events verarbeitet und weitergehen werden. Das selbe passiert auch beim eventbasierten IO. Warum soll ich nun zwei EDT laufen haben und hin und her synchronisieren müssen? Solange ich nichts blockierenden ausführe, ist doch alles super. und eventbasiertes IO ist entsprechend nicht blockierend.
 
M

MultiThreading

Gast
Ich enthalte mich weiteren Anmerkungen zu diesem Design-Fehler.
Vielleicht noch folgendes : der EDT ist ausschließlich für die Verarbeitung von User-Inputs sowie die Manipulation der GUI verantwortlich. Alles andere hat NICHTS im EDT zu suchen, auch kein non-blocking-I/O (wie gesagt : I/O hat sowieso nichts im EDT verloren).
 

7bestman

Mitglied
Java:
void onButtonClick() {
    http.open("http://example.com/changelog.txt", new ResponseHandler() {
        public void onResponse(String text) {
            changelog.setText(text);
        }
    });
}

ist ja wohl 10 mal hübscher als Code, der ständig explizit zwischen
den Threads hin und her synchronisieren muss.
Java:
void onButtonClick() {
    runOnUiThread(new Runnable() {
        public void run() {
            final String text = httpFetch("http://example.com/changelog.txt");
            runOnUiThread(new Runnable() {
                public void run() {
                    changelog.setText(text);
                }
            });
        }
    });
}

Und besonders doof wird es, wenn die UI und der IO Thread auch noch gemeinsam
auf eine Daten-Struktur zugreifen wollen, die dann erstmal ge_lockt_ werden
muss. dann sind wir nämlich wieder dabei, etwas blockierendes im UI Thread
zu machen. Hübsch? Nein.

Ein Blick in die Beschreibung zu Concurrency in Swing [1] erzählt im übrigens
nichts darüber, dass ausschließlich User-Inputs verarbeitet werden dürfen.
Es steht sogar explizit da: "Application code can schedule additionals tasks
on the event dispatch thread (if they complete quickly,"
Außerdem nehmen sich die Events von event-basiertem IO und User-Input
Events nichts. (Streng genommen sind die auf einem Unix-System mit
X-Server sogar die gleichen, da die X-Events auch von einem Socket gelesen
werden können, über das mit dem X-Server kommuniziert wird).

Bei GLIB und GTK wurde das meiner Meinung nach richig gemacht. Dort gibt
es nur einen Eventloop, den glib MainLoop, und es werden neben dem
GTK Toolkit, die den Eventloop verwendet auch IO-Operationen [2] angeboten,
die mit dem gleichen Eventloop laufen,

Wenn du mir nun also mal erzählen könntest, "warum" Event basiertes IO
deiner Meinung nach nichts im EDT zu suchen hat, dann wär das mal schön.

[1] Initial Threads (The Java™ Tutorials > Creating a GUI With JFC/Swing > Concurrency in Swing)
[2] IO Channels
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
izoards Mehrere TCP Verbindungen auf einen Server [alles Local] Netzwerkprogrammierung 2
F Socket Verbindungen über mehrere Server Netzwerkprogrammierung 4
G Proxy und mehrere Verbindungen Netzwerkprogrammierung 4
G Mehrere SSL Verbindungen Netzwerkprogrammierung 2
TRunKX Ein Port mehrere Verbindungen? Netzwerkprogrammierung 7
U Einen HandlerThread, der mehrere Verbindungen verwaltet? Netzwerkprogrammierung 2
Aruetiise Socket Mehrere Clients Netzwerkprogrammierung 4
E Mehrere Sockets Netzwerkprogrammierung 2
C Mehrere Spielewelten im Multiplayer Netzwerkprogrammierung 2
J Framework mehrere Clients/ Server-Broadcast/oracle XE/ XML Netzwerkprogrammierung 1
V Server / mehrere Clients / MySQL / Konzept Netzwerkprogrammierung 2
S Server - Mehrere Klassen sollen Daten senden und empfangen Netzwerkprogrammierung 25
Creylon Socket Mehrere gleichzeitig eingehende Nachrichten Netzwerkprogrammierung 8
N SOCKET mehrere Requests, keep Alive serverspezifisch? Netzwerkprogrammierung 3
Z Socket [Chatprogramm] Mehrere Clients an einen Server Netzwerkprogrammierung 10
V Authentifikation über mehrere Server? Netzwerkprogrammierung 3
G Socket Mehrere Clientanmeldungen am Server Netzwerkprogrammierung 13
D Mehrere Clients über Java-Sockets Netzwerkprogrammierung 13
cedi Socket Mehrere Clients an einem Server Netzwerkprogrammierung 4
B SSH mit Jsch, mehrere Befehle senden Netzwerkprogrammierung 4
M Jetty Konfiguration mehrere Handler? Netzwerkprogrammierung 2
F UDP Server - mehrere Pakete auf einmal Netzwerkprogrammierung 12
A Mehrere gleich Packete behandeln Netzwerkprogrammierung 4
L Socket Chat Server für mehrere Clients Netzwerkprogrammierung 7
R mehrere MySQL-Zugriffe Netzwerkprogrammierung 3
B Paralleler Dateitransfer: Ein Client - Mehrere Sockets? Wie connecten? Netzwerkprogrammierung 16
S Mehrere Attachments mit JavaMail API auslesen Netzwerkprogrammierung 3
O Mehrere Datei per DataInput/OutputStream über Socket Netzwerkprogrammierung 12
A Datenverteilung: Mehrere Threads verwenden? Netzwerkprogrammierung 4
T Netzwerkchat Problem: Mehrere Nachrichten ~ Anfängerproblem Netzwerkprogrammierung 3
W Bestimmt IP Adresse verwenden wenn man mehrere hat Netzwerkprogrammierung 5
D Clients sollen mehrere Sessions starten Netzwerkprogrammierung 11
A Jakarta Commons HTTPClient: Mehrere Requests gleichzeitig Netzwerkprogrammierung 2
R Mehrere Dateien über einen Socket senden Netzwerkprogrammierung 2
G Nachricht an mehrere Clients schicken Netzwerkprogrammierung 10
L mehrere Streams über einen Socket? Netzwerkprogrammierung 8
V Mehrere Streams durch einen Stream senden Netzwerkprogrammierung 14
E Mehrere / bestimmte Netzwerkkarten ansteuern Netzwerkprogrammierung 10
F Mehrere Attachments mit JavaMail API Netzwerkprogrammierung 2
A Mit Client auf mehrere Server zugreifen Netzwerkprogrammierung 5
M Mehrere Ports gleichzeitig abhören Netzwerkprogrammierung 5
G Server an mehrere Clients Netzwerkprogrammierung 15
L JavaMail: Automatisches Email Versand (mehrere Empfänger) Netzwerkprogrammierung 4
X mehrere Request über eine HttpURLConnection Netzwerkprogrammierung 2
J Grundsätzliches zu SSL verschlüsselten Verbindungen Netzwerkprogrammierung 2
D Socket-Verbindungen übers Internet Netzwerkprogrammierung 4
I Offene Verbindungen lesen(Ressourcenmonitor lesen) Netzwerkprogrammierung 2
G FTP FTP-Client funktioniert nicht bei Modem-Verbindungen Netzwerkprogrammierung 8
N Java NIO eingehende und ausgehende Verbindungen mit einem Selector Netzwerkprogrammierung 12
S RMI Polling oder lange Verbindungen Netzwerkprogrammierung 6
M Socket Leistungsfähigkeit eines xSocketservers, wieviele Verbindungen max? Netzwerkprogrammierung 4
D Aktuelle Anzahl der verfügbaren TCP/IP Verbindungen Netzwerkprogrammierung 6
E TCP-Server soll viele offene Verbindungen verwalten Netzwerkprogrammierung 12
D Was für Verbindungen mit Socket möglich? Netzwerkprogrammierung 2
J Nacheinander Verbindungen eingehen Netzwerkprogrammierung 2
A persistente, multi-threaded Verbindungen Netzwerkprogrammierung 12
S Verbindungen der Browser ermitteln? Netzwerkprogrammierung 9
G Windows-Verbindungen Netzwerkprogrammierung 4
R Zuviele TCP-Verbindungen Netzwerkprogrammierung 4
F konfigurierte Netzwerkverbindunge/DFÜ-Verbindungen ermitteln Netzwerkprogrammierung 4
M Socket Verbindungen für einen Chat Netzwerkprogrammierung 10
D .jpg, .wav per ServerClient Verbindungen verschicken Netzwerkprogrammierung 8
S eclipse: client/server gleichzeitig starten Netzwerkprogrammierung 8
A RMI: Wieviele Clients können sich gleichzeitig anmelden? Netzwerkprogrammierung 34
K Windows 10 Threads gleichzeitig Netzwerkprogrammierung 18
F nur ein benutzer gleichzeitig / locking mechanismus Netzwerkprogrammierung 3
A Rmi Client und Server Gleichzeitig! Netzwerkprogrammierung 3

Ähnliche Java Themen

Neue Themen


Oben