Socket Problem mit C++/Java

JayWorkDe

Mitglied
Hallo zusammen,
mein Problem liegt in der Kommunikation zwischen Java und C++...

Java:
DataInputStream FromClient = new DataInputStream(this.client.getInputStream());
    		
byte[] buffer = new byte[2048];
int numberRead = FromClient.read(buffer, 0, 2048);

Soweit der Empfang...

Code:
char buffer[2048];
int res = recv(socket, buffer, 1024, 0);

buffer[res] = '\0';

send(socket2,buffer,res,0);

Soweit das Senden...


Mein Problem ist folgendes... Der Java(Client) empfängt mehr Bytes als 1024(der Server schickt aber nur 1024). Da ich den Quellcode einer Webseite übertrage ist es aber wichtig das alles 100% stimmt. Ich hoffe ihr habt Ideen woran das liegen könnte?
 
Ich empfehle benutz mal wireshark, und guck dir den rohverkehr der daten an, und ob wirklich exact richtig gesendet wird.

Ansonsten würde ich:
Als erstes einen int(oder long) mit der anzahl der byte schicken, dann auf ajva seite den einzeln! lesen einen buffer mit der länge erstellen, und solange lesen bis der voll ist. (Da dein datastream blockiert wenn du versuchst mehr zu lesen als vorhanden ist.
Ausserdem beachten, das read laut javadoc auch weniger lesen kann als den buffersize

Java:
final int messagesize = Client.in.readInt();
final byte[] cache = new byte[messagesize];
final ByteBuffer bbuffer = ByteBuffer.wrap(cache);
int realread = 0;
while (realread < messagesize) {
  realread += Client.in.read(cache, realread, messagesize - realread);
}
 
Das hat jetzt nichts mit deinem Problem zu tun - aber warum setzt du denn
Code:
buffer[res] = '\0';
?
Kann mir nicht vorstellen, dass das ein NULL-terminierter "String" ist oder?!
 
Ich empfehle benutz mal wireshark, und guck dir den rohverkehr der daten an, und ob wirklich exact richtig gesendet wird.

Ansonsten würde ich:
Als erstes einen int(oder long) mit der anzahl der byte schicken, dann auf ajva seite den einzeln! lesen einen buffer mit der länge erstellen, und solange lesen bis der voll ist. (Da dein datastream blockiert wenn du versuchst mehr zu lesen als vorhanden ist.
Ausserdem beachten, das read laut javadoc auch weniger lesen kann als den buffersize

Java:
final int messagesize = Client.in.readInt();
final byte[] cache = new byte[messagesize];
final ByteBuffer bbuffer = ByteBuffer.wrap(cache);
int realread = 0;
while (realread < messagesize) {
  realread += Client.in.read(cache, realread, messagesize - realread);
}


Ich dachte ein Datastream liest einfach bis das Ende erreicht ist und stopt dann... Ich werde mal versuchen zuerst die länge zu schicken. Danke schonmal 😉
 
Das hat jetzt nichts mit deinem Problem zu tun - aber warum setzt du denn
Code:
buffer[res] = '\0';
?
Kann mir nicht vorstellen, dass das ein NULL-terminierter "String" ist oder?!


Der "char" buffer hat die Größe 2048... wenn ich aber z.B. nur 40 Bytes von der Webseite zurück bekomme dann kann man den char so terminieren.
 
Der "char" buffer hat die Größe 2048... wenn ich aber z.B. nur 40 Bytes von der Webseite zurück bekomme dann kann man den char so terminieren.

Ja, das habe ich verstanden - aber das stimmt glaube ich nicht. Das ist ja kein C-String sondern ein Puffer. Die Null kannst dir an der Stelle sparen.

Because the send() API doesn't use a trailing null-character to determine the end of the data to send. Instead, it uses the buffer_length parameter to determine how much data to send.
vgl.
The send() and recv() API calls

Dazu kommt, dass du bei recv die Puffergröße mit 1024 statt 2048 angibst.
Das hat beides aber wie gesagt nichts mit dem Problem zu tun ...

Aber Idee: Vielleicht gehört vor das
Code:
send(socket2,buffer,res,0);
ein
Code:
if (res > 0)...

Nicht, dass du das ganze in einer check-Schleife eingebettet hast und der bei leerem Puffer nur Müll weiterleitet.
 
Wenn ich die API richtig verstehe, kommt im Fehlerfall gar nichts (res <0)

res == 0 => Keine Daten vorhanden
res < 0 => Fehler... z.B. socket geschlossen
res > 0 => Daten sind vorhanden

Aber ich meinte... wenn res < 0 ist... dann werden ja auch keine 2048 Bytes geschickt... deswegen muss für mein Problem ja schon res > 0 sein...

Bei genauerem betrachten denke ich Empire Phoenix hat recht... Wenn der Datastream (Java) nicht nur das nimmt das geschickt wird sondert wartet bis die 2048 voll sind dann ist ja logisch das nichts hinhaut 😀... Ich muss also immer erstmal sicherstellen wie viel Bytes gesendet werden und dann die buffer-größe setzen...

Kennt vllt. jemand einen typ stream der automatisch aufhört wenn nichts mehr kommt? ggf. auch einen terminator für Java Strings? (sollte ja dann denke ich auch klappen)

lg
 
Ich würde dir vor irgetwelchem rumbasteln erstmal empfehlen mit wireshark zu testen ob wirklich das richtig gesendet wird.
Kannst dir selber einen terminator ausdenken. irgetetwas das in websites nicht vorkommen kann. und dann einfach aufhören.
 
So... nach langem hin und her gebastel hab ich das mit den 1024 Bytes in den Griff bekommen... Ich musste C++ Seitig einfach nur Sleep(500) nach jedem senden einbauen... Darauf will Java wohl nicht warten und vergnügt sich mit den bereits empfangenen Bytes...

Um die Geschwindigkeit zu erhöhen habe ich die Verbindungen in C++ ebenfalls in Threads ausgelagert.

Jetzt habe ich aber ein neues Problem...

und zwar wenn ich eine Seite aufrufe wird ja nicht nur z.B. die index.html geholt sondern für jedes Bild, jede Datei wird ein neuer Socket angelegt... Ich habe aber den C++ Server nur auf einem Client liegen.

Code:
index.html ->                                        Socket 1  
bild1.jpg ->                                           Socket 2 
bild2.jpg ->         C++ Server    -->          Socket 3
style.css ->                                         Socket 4
javascript.js ->                                     Socket 5

ich denke das Problem liegt nun darin das Java zugespammt wird von den ganzen C++ Threads und nicht hinterher kommt. Synchronized bringt mir leider auch nichts (wenn ich es richtig verwendet habe).

Wisst ihr vllt. rat?


Java:
public class ServerThread extends Thread implements Runnable

synchronized
public void run() 
{ 		
try 
........


Ich hoffe ihr könnt mir weiterhelfen 😉...

lg
 
Zuletzt bearbeitet:
> Ich musste C++ Seitig einfach nur Sleep(500) nach jedem senden einbauen...

es läuft eine Schleife die mehrfach 1024 Bytes sendet? na danke dass diese Information die ganze Zeit verschwiegen
und felsenfest angeblich nur 1024 Bytes gesendet wurden..

---------

viele Verbindungen sind grundsätzlich nicht böse sondern normal für einen WebServer,
wenn du mal mehr als nur ca drei Zeilen und vorallem ... posten würdest könnte man erkennen,
ob dein Java-Server einigermaßen normal arbeitet,

bei jedem accept() muss eben für die Verbindung ein neuer Thread geöffnet
(oder sparsamer die Aufgabe an einen laufenen Thread übergeben/ sonstwo abgelegt),
und gleich wieder mit accept() auf die nächste Verbindung gewartet werden

(in allen Sätzen 'würde' und 'werden'..)
 
ok ich poste mal grob den Code 😉...

Java:
- Server.java

Java:
public class Server extends Thread

ServerSocket server = new ServerSocket(5000);

try 
{
    Socket client = server.accept();
					
    DataOutputStream out = new DataOutputStream(client.getOutputStream());
					
    User user = new User(client);
					
    vUser.add(user);
					
    ServerThread st = new ServerThread(this,client,user);
					
    user.setServerThread(st);
									
} catch (IOException e) {}

User ist eine Klasse in der ich den Client Socket, Thread ect. speichere...


- ServerThread.java
Java:
public class ServerThread extends Thread implements Runnable

public ThreadTask tTask = null;
public Timer timer = null;

public ServerThread(Server server, Socket client,User user) 
{
    tTask = new ThreadTask(this.server,this.user);
    	
    timer = new Timer();
    timer.schedule(tTask, 3000, 3000);
		
    start();
}

synchronized
public void run() 
{ 		
    try 
    {	
        DataInputStream FromClient = new DataInputStream(this.client.getInputStream());
    		
    	byte[] buffer = new byte[2048];
    	int numberRead = 0;
    	    
    	while(true)
    	{    
    	    numberRead = FromClient.read(buffer, 0, 2048);

            if(numberRead == -1)
    	    {
    	        break;
    	    }

            query = new String(buffer,0,numberRead);

            if(this.server.client != null)
    	    {
                this.tTask.begin = System.currentTimeMillis();
    	    }

            User us = null;
    	    if(this.user.isCpp())
    	    {
    	        if(query.indexOf("Socket[addr=") != -1)
    		{
                    String socket = query.substring(query.indexOf("Socket[addr="), query.indexOf(this.server.port+"]")+5);
    		    query = query.substring(socket.length());
    		
    							
    		    synchronized(this.server.vUser) 
    	   	    {
    		        for(int i = 0; i < this.server.vUser.size(); i++)
    		        {
    		            User tmp = (User)this.server.vUser.get(i);
    		   	   	        				
    		   	    if(socket.indexOf(tmp.getSocket().toString()) != -1)
    		   	    {
    		   	        us = tmp;
    		   	        break;
    		   	    }
    		        }
    	   	     }
    	        }
             }else{
    	        us = this.server.client; // der einzigste Cliente des C++ Programm's
             }

             if(us != null)
    	     {
    	         if(this.user.isCpp())
    		 {
    		     us.getDataoutputstream().write(query.getBytes(),0,query.getBytes().length);
    		 }else{
    		     query = "SOCKET: "+this.user.getSocket()+"\r\n"+query;
    							
    		     us.getDataoutputstream().write(query.getBytes(),0,query.getBytes().length);
    		 }
    	     }
        }
    }
    catch (EOFException e) {System.out.println("EOF: "+e.toString());}
    catch (IOException e) {System.out.println("IO: "+e.toString());} 
}


- ThreadTask
Java:
public class ThreadTask extends TimerTask

public void run()
{
    if(begin != 0)
    {
        long now = System.currentTimeMillis()-begin;
			
	if(now >= 3000)
	{
	    server.removeConnection(this.user);
	}
    }
}

Als nebeninfo... ich habe eine Index.java mit der ich die Server.java z.B. 10 mal aufrufe (mit anderem Port) um 10 Server gleichzeitig zu haben... deswegen ist die Server.java ebenfalls ein Thread

-------------------------------------------------------------------
C++:

- main.cpp
Code:
SOCKET client;

HANDLE proxy_threads[100];
string head[100];
int thread_pos = 0;

int serverport = 5000;

int main()
{
    Verbingung auf port 5000 aufbauen....

    header empfangen....

    unsigned long id;
    head[thread_pos] = out;
    proxy_threads[thread_pos] = CreateThread(0,0,&HandleProxyClients,0,0,&id);
		
    Sleep(500);
    if(thread_pos == 100)
    {
        thread_pos = 0;
    }else{
	thread_pos++;
    }
}


DWORD WINAPI HandleProxyClients(LPVOID data)
{
    int cur = thread_pos;
	
    char buffer[2048];
    int res = 0;

    SOCKET toWebsite = socket( AF_INET, SOCK_STREAM, 0 );

    Verbindungsaufbau mit den Headerdaten....

    send(toWebsite,requestToSend.c_str(),requestToSend.length(),0); // Request beinhaltet den Header

    res = recv(toWebsite, buffer, 1024, 0);

    while(res != 0)
    {
        buffer[res] = '\0';
	string toSend = receivefromsock+buffer; //receivefromsock behinhalt die Socketdaten... Socket [addr..... (die von Java mitgeschickt werden damit ich weiß welche Browserverbindung die Daten angefordert hat)

	printf("sende %d\n",toSend.length());
	send(client,toSend.c_str(),toSend.length(),0); // Client ist die Verbidnung die den Header empfängt & die Quellcodes sendet (Java)

	res = recv(toWebsite, buffer, 1024, 0);
		
	Sleep(500);
    }

    DWORD ff;
    GetExitCodeThread(proxy_threads[cur],&ff);
    ExitThread(ff);
    
    return 0;
}


Ich hoffe ich hab den Code verständlich gepostet 😀...

lg
 
Zuletzt bearbeitet:
was ich noch editieren wollte (wäre aber kein Satz mit 'würde' geworden):
was ist eigentlich deine Frage, was genau funktioniert aktuell nicht?

um mehrere Verbindungen anzunehmen braucht es wie gesagt eine Schleife für accept(),
ist nicht zu sehen,
dass du extra einen ServerThread startest, oder auch eine User-Liste führst, spricht aber eigentlich dafür

Writing the Server Side of a Socket (The Java™ Tutorials > Custom Networking > All About Sockets)
Supporting Multiple Clients

To keep the KnockKnockServer example simple, we designed it to listen for and handle a single connection request. However, multiple client requests can come into the same port and, consequently, into the same ServerSocket. Client connection requests are queued at the port, so the server must accept the connections sequentially. However, the server can service them simultaneously through the use of threads - one thread per each client connection.

The basic flow of logic in such a server is this:

while (true) {
accept a connection;
create a thread to deal with the client;
}

The thread reads from and writes to the client connection as necessary.
 
> Ich musste C++ Seitig einfach nur Sleep(500) nach jedem senden einbauen...

es läuft eine Schleife die mehrfach 1024 Bytes sendet? na danke dass diese Information die ganze Zeit verschwiegen und felsenfest angeblich nur 1024 Bytes gesendet wurden..


Sorry das ich nicht gleich gesagt hab, dass es sich um eine Schleife handelt. Ich ging davon aus, dass man das versteht wenn ich schreibe das ich ganze Seiten rüber schicken muss 🙁.
 
Es ist so, dass ich versuche die Router zu umgehen.

Es geht um eine Art IP-Vermietung. (Ähnlich dem Tor-Projekt).


1. Ich starte das C++ Programm => Dieses baut eine Verbindung zum Javaserver über Port 5000 auf.
2. Du stellst in deinem Browser die Server-ip und Port als Proxyverbindung ein.
3. Der Javaserver leitet deine Anfrage an mein C++ Programm weiter.
4. Mein C++ Programm ruft die entsprechende Seite auf und gibt den Quellcode zurück an den Java-Server.
5. Der Javaserver schickt den Quellcode an deinen Browser.
6. Du siehst die Seite.

Um die "Identifikation" zu gewährleisten, dass wirklich DU das Bild abc.jpg sehen möchtest, schicke ich dein Socket im Header mit an C++ und wandle es in der ServerThread.java wieder um. Somit wird wirklich der Verbindung die das Bild angefordert hat die Bytes geschickt.
 
mehrere Stufen machen das ganze nicht unbedingt schwieriger, jede muss für sich korrekt arbeiten,
dass überall Threads laufen ist eben so,
wobei du nach Empfang mehrerer Verbindungen vom Client zwischen den inneren Programm-Stufen
wohl mit wenigen dauerhaft genutzten Verbindungen/ Threads auskommen kannst

mit
> // der einzigste Cliente des C++ Programm's
hast du das anscheinend auch schon, abgesehen davon dass man 'einzig' nicht steigern kann

du solltest hierbei wahrscheinlich ein etwas umfangreicheres Protokoll verwenden, sende nicht nur den Query-String,
sondern auch z.B. eine Request-Nummer, dann kann der C++-Server verschiedene Querys unabhängig bearbeiten und
durchaus auch in verschiedener Reihenfolge zurücksenden, was der Java-Server hoffentlich gleich richtig weiterleitet
an die jeweils richtigen Browser-Sockets, über die Id gemerkt,

auch das hast du vielleicht schon, wie ich jetzt sehe, mit
> query.indexOf("Socket[addr=")
?

vielleicht also noch nichts neues in meinem Posting, ich bin auch nicht zwingend der Experte dazu,
obwohl ich anscheinend schon paar richtige Gedanken ehrlich selber erinnert habe 😉

eine konkrete Frage fehlt in deinem Posting meiner Ansicht nach weiterhin
 
mehrere Stufen machen das ganze nicht unbedingt schwieriger, jede muss für sich korrekt arbeiten,
dass überall Threads laufen ist eben so,
wobei du nach Empfang mehrerer Verbindungen vom Client zwischen den inneren Programm-Stufen
wohl mit wenigen dauerhaft genutzten Verbindungen/ Threads auskommen kannst

Mein Problem besteht ja darin, dass es mir so vorkommt als hätte die ServerThread keine enstprechend viele Instanzen sondern würde einzeln arbeiten.


du solltest hierbei wahrscheinlich ein etwas umfangreicheres Protokoll verwenden, sende nicht nur den Query-String,
sondern auch z.B. eine Request-Nummer, dann kann der C++-Server verschiedene Querys unabhängig bearbeiten und
durchaus auch in verschiedener Reihenfolge zurücksenden, was der Java-Server hoffentlich gleich richtig weiterleitet
an die jeweils richtigen Browser-Sockets, über die Id gemerkt,

auch das hast du vielleicht schon, wie ich jetzt sehe, mit
> query.indexOf("Socket[addr=")
?
[/QUOTE]

Der Socket.toString() wird sowohl an das C++ Programm als auch wieder zurück an den Java-Server geben. Damit ich eben die Bytes an die Korrekte Verbindung (des Browsers) weiterleiten kann.


[quote="SlaterB, post: 908636"]
vielleicht also noch nichts neues in meinem Posting, ich bin auch nicht zwingend der Experte dazu,
obwohl ich anscheinend schon paar richtige Gedanken ehrlich selber erinnert habe 😉

eine konkrete Frage fehlt in deinem Posting meiner Ansicht nach weiterhin

Ich versuche es nochmal verständlich zu sagen... Mein Problem ist, dass die Threads nicht einer nach dem anderen laufen. Wie ich auch schon sagte, denke ich, dass ich mit synchronized arbeiten muss. Jedoch bekomme ich das nicht hin.

Meine Frage also lautet: Wie muss ich da mit synchronized arbeiten, damit es nicht kreuz und quer zugeht.
 
> dass es mir so vorkommt als hätte die ServerThread keine enstprechend viele Instanzen sondern würde einzeln arbeiten.
+
> Wie muss ich da mit synchronized arbeiten, damit es nicht kreuz und quer zugeht.

ist 'einzeln arbeiten' vs. 'kreuz und quer' nicht ein Widerspruch?


ob und wie du überhaupt mehrere Verbindungen vom Client empfängst ist wie früher gesagt noch unklar,
accept() sehe ich nur einmal ausgeführt,
danach startest du einen Thread, wenn wirklich pro Verbindung neu, dann arbeiten die anscheinend durcheinander,

dem kannst du begegnen, indem nur ein Thread parallel zum accept()-Thread läuft,
dieser schaut in einer Schleife, ob Aufträge da sind, der accept()-Thread legt neue Aufträge ab, dabei synchronisieren,
so wäre Bearbeitung nacheinander gesichert
 

Neue Themen


Zurück
Oben