Forum: Mikrocontroller und Digitale Elektronik ATMega32 + ENC28J60 + TCP


von Tobi (Gast)


Angehängte Dateien:

Lesenswert?

Hallo zusammen,

also irgendwie habe ich Probleme einen TCP Verbindung aufzubauen.

Mein Atmel hat einen TCP/IP Stack implementiert.
Eine kleine Anwendung auf dem µC soll nun eine Verbindung über TCP mit 
einem Java Programm auf dem Rechner aufbauen.

Dies funktioniert soweit auch. Egal wer die Verbindung initiiert.

Beginne ich den Handshake nun vom Java Programm antwortet der µC promt 
und das Java Programm antwortet wiederum mit einem Ack.

Beginne ich ein SYN vom µC zu senden, kommt erst nach einem 
undefinierten späteren Zeitraum ein SYN/ACK vom Java Programm zurück 
welches sich definitiv in der ServerSocket.accept() Funktion befindet.
Auf dem angehängten Bild antwortet der µC auf das erste (nach vielen 
vergeblich gesendeten SYN) SYN/ACK aus irgend einem Grund nicht. Dies 
muss ich noch herausfinden wieso... jedoch komisch ist, dass erst nach 
einem RST welches vom JAVA Programm kommt alles direkt funktioniert.
Hat ein RST bei einem Handshake irgend eine Bedeutung?!? Ich wüsste 
nicht welche.

Die Verbindung kommt immer zustande. Jedoch mal schnell mal sehr spät.
Hat jemand ne Ahnung ob das auch am Java Programm liegen kann? Erwartet 
die accept Funktion des ServerSockets irgend einen besonderen 
Optionsparameter des TCP Packets?

192.168.2.101 ist der µC und 192.168.2.100 der PC mit dem Java Proramm.

Die Routine im µC zum Aufbauen einer TCP Verbindung sieht folgendermaßen 
aus:
1
uint8_t ConnectHost(uint32_t destIP, uint16_t sourcePort, uint16_t destPort, void(*fp1)(uint8_t*,uint16_t))
2
{
3
  uint8_t maxSend = 5;
4
  uint8_t SOCKET = TCP_RegisterSocket(destIP, (uint8_t*) &destIP, destPort, sourcePort, fp1);
5
  
6
  if(SOCKET >= MAX_TCP_CONNECTIONS) return(0xff);
7
  
8
  uint8_t ret = GetIP2MAC(destIP, tcp_Sockettable[SOCKET].destMAC);
9
10
  if(ret == 0xff) return 0xff;
11
  
12
  tcp_Sockettable[ SOCKET ].ConnectionState = CONNECTING;  
13
  tcp_Sockettable[SOCKET].destIP = destIP;
14
  tcp_Sockettable[SOCKET].SequenceNumber = 1273489229;
15
  MakeTCPheader(SOCKET,(TCP_SYN_FLAG),0,MAX_RECIVEBUFFER_LENGHT,ethBuffer);
16
  
17
  ethSendFrame(ethBuffer, ETHERNET_HEADER_LENGTH + IP_HEADER_LENGHT + TCP_HEADER_LENGHT + 0);
18
19
  
20
21
  myTimer synTimer;
22
  startTimer(&synTimer, 500);  // Set timer to 500*5ms = 2500ms wait
23
24
  while(maxSend){
25
    ethBufferLen = ethGetFrame(ethBuffer, MAX_ETH_FRAME_LENGTH);
26
27
    if(ethBufferLen != 0){
28
    packetE2 += 1;
29
      struct IP_packet *ipPacket;  
30
      ipPacket = (struct IP_packet *) &ethBuffer[ETHERNET_HEADER_LENGTH];
31
      struct TCP_header *tcpPacket;  
32
      tcpPacket = (struct TCP_header *) &ethBuffer[ETHERNET_HEADER_LENGTH + IP_HEADER_LENGHT];
33
34
      if((ipPacket->IP_Protocol == PROTO_TCP) && (tcpPacket->TCP_DestinationPort == tcp_Sockettable[SOCKET].sourcePort) && (tcpPacket->TCP_ControllFlags == (TCP_SYN_FLAG | TCP_ACK_FLAG))){
35
        if(tcp_Sockettable[SOCKET].SequenceNumber+1 == ChangeEndian32bit(tcpPacket->TCP_AcknowledgeNumber))
36
          tcp_Sockettable[SOCKET].AcknowledgeNumber = ChangeEndian32bit(tcpPacket->TCP_SequenceNumber) + 1;
37
          break;
38
      }
39
    }
40
41
    if(checkTimer(&synTimer)){
42
      MakeTCPheader(SOCKET,(TCP_SYN_FLAG),0,MAX_RECIVEBUFFER_LENGHT,ethBuffer);
43
  
44
      ethSendFrame(ethBuffer, ETHERNET_HEADER_LENGTH + IP_HEADER_LENGHT + TCP_HEADER_LENGHT + 0);
45
      maxSend--;
46
      startTimer(&synTimer, 500);
47
    }
48
49
  }
50
51
  if(maxSend > 0){
52
    SendAck(SOCKET,tcp_Sockettable[SOCKET].SequenceNumber+1,tcp_Sockettable[SOCKET].AcknowledgeNumber);      
53
    tcp_Sockettable[SOCKET].ConnectionState = CONNECTED;
54
  }
55
  else{
56
    TCP_UnRegisterSocket(SOCKET);  
57
    return(0xFF);
58
  }
59
60
  return 0x00;    
61
}

Im Prinip geht hier hervor, dass 5 mal versucht wird alle 2,5 sekunden 
ein SYN zu senden und dann aktiv auf eine Antwort gewartet wird.
Weitere verbindungversuche kommen dadurch zustande, dass die Routine 
darüber diese obige immer wieder aufruft bis es klappt.

Hoffe jemand kann mir weiterhelfen... ich hänge hier schon eine ganze 
Weile.

Vielen Dank für eure Mühe!

Tobi

von Balu (Gast)


Lesenswert?

Man rufe

ConnectHost(..., uint16_t sourcePort, ..., ...)

mit einem randomisierten uint16 auf (anstatt einer Konstante)
und dann geht es.

-Balu

von Tobi (Gast)


Lesenswert?

Aha?!?!?Wieso darf ich nicht einen festen Source Port verwenden?

Danke Tobi

von Sascha W. (sascha-w)


Lesenswert?

weil die meisten TCP-Stacks eingehende Pakete anhand ihrer Portnummer 
auch für bereits geschlossenen Verbindungen zuordnen (für eine gewisse 
Zeit).
Einfach in einem Bereich die Portnummer bei jeder neuen Verbindung um 
eins erhöhen - wenn du mal schaust wie der PC das macht wirst du das 
selbe Muster feststellen.

Sascha

von Tobi (Gast)


Lesenswert?

super danke für euren Tip!!!

Jetzt funktioniert es um einiges besser!!

Komisch ist nur das manche SYN/ACK nicht direkt erkannt werden, aber das 
bekomm ich auch noch hin.

Komisch ist auch das das Java Programm beim Beenden der Verbindung nicht 
nur ein Fin/ACK sendet sondern davor auch noch ein PSH/ACk mit eine 
Datenbyte das 0 ist.... komisch... naja...

Danke euch!!

von Balu (Gast)


Lesenswert?

>nur ein Fin/ACK sendet sondern davor auch noch ein PSH/ACk mit eine
>Datenbyte das 0 ist.... komisch... naja...

Nope. Nicht komisch.

Ordentliche TCP/IP Stacks puffern Daten im Kernel zwischen und ein
Betriebssystem darf schonmal warten, ob es nicht noch auf ein
weiteres zeitnahes Paket spekulieren mag. Mit dem PSH gibt eine
remote Applikation den "Hinweis", dass es nunmehr ein guter
Zeitpunkt waere, die Daten an die lokale Applikation
weiterzugeben.

>Komisch ist nur das manche SYN/ACK nicht direkt erkannt werden, aber das
>bekomm ich auch noch hin.

Reine Glaskugelvermutung: es riecht nach einem (reverse) DNS Timeout.

-Balu

von Tobi (Gast)


Lesenswert?

Hallo Balu,

danke für deine Infos,

das bedeutet, dass mein Java Programm mir nur mitteilen möchte ich solle 
noch etwas senden wenn ich dies möchte da sonst das Beenden der 
Verbindung folgt?!?
Aber wieso triggert mich das Programm an... wenn ich etwas zu senden 
habe würde ich das doch ohnehin tun?!?
Bzw mir ist nicht ganz klar wie ich auf das Datenpaket reagieren soll.

Ich hab meine Implementation zur Zeit soweit, dass ich jedesmal einen 
Autoreply auf ein Datenpaket sende. (Java Programm ist ein kleiner TCP 
Chat)
Egal was ich mit dem Java Programm sende, sendet mein Atmel immer ein 
"Hallo" zurück.
Nun kommt aber diese blöde Datenpaket am Ende der Verbindung (aber auch 
nicht jedes mal) und bringt das Ende durcheinander.

Mein Atmel sendet dann ein ACk auf das Datenpaket mit dem Dateninhalt 
"0" vom Java Programm und dann ... je nachdem wie es zeitlich hinkommt 
meist sendet das Java Programm ein FIN/ACK direkt vor meinem Autoreply 
der dann logischerweise nicht mehr beantwortet wird.

Ich könnte ja sagen, ein Datenpaket mit Inhalt "0" wird generell 
verworfen.. oder wie handhabt man dieses Paket üblicherweise??

Hab ja nun einen Zufallsgenerator für den Sourceport eingebaut.
Komisch ist allerdings immernoch, dass es oft ewig dauert bis auf mein 
SYN eine Bestätigung kommt. Manchmal geht es aber ganz fix. (besser wie 
immer mit dem gleichen Port) ... Das mit dem DNS Timeout hab ich noch 
nicht ganz rausgefunden Balu. Meinst du ich müsste evtl einen DNS Client 
implementieren damit das funktioniert?

Wieso aber funktioniert es in die andere Richtung einwandfrei?
Hier nutze ich immer die gleichen Ports und der Three Way Handshake 
funktioniert verdammt schnell... hm..

Danke euch!!!
Tobi

von Balu (Gast)


Lesenswert?

>das bedeutet, dass mein Java Programm mir nur mitteilen möchte ich solle
>noch etwas senden wenn ich dies möchte da sonst das Beenden der
>Verbindung folgt?!?

Du meinst das PSH-Flag? Grob kannst Du Dir das als (java.io)-
flush()-Netzwerk-Entsprechung vorstellen. (Keine Ahnung,
ob das im Programm steht oder von der Java-Laufzeitumgebung
erzeugt wird, normalerweise "stört" ein PSH-Flag nicht)

>Mein Atmel sendet dann ein ACk auf das Datenpaket mit dem Dateninhalt
>"0" vom Java Programm und dann ...
Ein "leeres ACK" bestätigt die bis dahin (vom *TCP*-Netzwerkstack)
empfangenen Daten. Hmm... Die meisten lightweight
embedded-"Netzwerkstacks" verlagern Teile der TCP state machine
ins Applikationsprogramm... d.h. ohne die Lektüre und das saubere
Umsetzen der TCP state machine wird das nicht konform umgesetzt
werden können.

>Hab ja nun einen Zufallsgenerator für den Sourceport eingebaut.
>Komisch ist allerdings immernoch, dass es oft ewig dauert bis auf mein
>SYN eine Bestätigung kommt.
Ich nehme an, Du verwendest Linux. In diesem Moment mit "netstat -ant"
ansehen, in welchem Zustand der Socket unter dem Java-Rechner ist (jetzt
waere die Kenntnis der TCP state machine wichtig ;-) (Unter Windows
wird es ein analoges Kommando geben...)

Vorschlag:
Auf einem zweiten Rechner die Funktionalität des AVRs nachbilden.
Das sollte in einem 30-Minuten-Hack zu schaffen sein. Geht nun der
ursprüngliche Java Rechner "ordentlich" ?

Mit einem frisch gestarteten Java-Rechner ein
"nslookup <ip-des-embedded-AVRs>" eingeben. Ist das Ergebnis gleich
da oder musst Du aehnlich lange warten wie auf das SYN-ACK?
DNS hat ein Feature names negative Caching, d.h. man darf sich auch
merken, dass ein DNS Aufruf keine Ergebnisse liefert(z.B. timeout). Dann
gibt es das zweitemal natürlich sofort ein (negatives) gecachtes
Ergebnis...  Wenn etwa gleiche Zeiten: ist da irgendwo logging mit
symbolischen Namen angeschaltet?

-Balu

von lasometer (Gast)


Lesenswert?

Hallo

ich weiß der Beitrag ist schon ein bisschen älter, aber ich wollte mal 
mein Glück versuchen.
Ich arbeite momentan an einem eigenen Projekt(chen) und einen HTTP 
Request an einen Server senden, es gibt jedoch keine Beispiele für einen 
HTTP Client. Es wäre schön wenn ich mir deinen AVR code mal anschauen 
könnte

lg

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.