B&R: Problem mit AsTCP

Leuchtkeks

Level-1
Beiträge
26
Reaktionspunkte
0
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo,

hab hier ein kleines Problem mit einer Client-Anwendung. Als "Server" dient mir momentan ein kleines Test-Tool (http://www.drk.com.ar/builder.php). Verbinden und Daten senden funktioniert, allerdings wenn ich die Verbindung händisch resete (siehe step 100 im Programm) oder künstlich einen Fehler erzeuge (Kabel ziehen) erhalte ich bei TcpClient() als Status 32608. Ich weiß jetzt aber nicht hab ich einen Fehler gemacht oder liegt das an dem Test-Tool. Hier mal der Code:

Code:
case ssw of

    ; init
    action 0:
        sockOpen.enable  = 1
        sockOpen.pIfAddr = 0
        sockOpen.port    = 0
        sockOpen.options = 0
                
        ssw = 1
    endaction
    
    ; warte auf verbindung
    action 1:
        sockOpen FUB TcpOpen()
                
        if (sockOpen.status <> 65535) then
        
            ; ok
            if (sockOpen.status = 0) then
                ssw = 2
                
            ; fehler
            else
                ssw = 100
            endif
        endif
    endaction
    
    ; optionen setzen
    action 2:
        linger_opt.lLinger = 0
        linger_opt.lOnOff  = 1
        
        sockIO.enable  = 1
        sockIO.ident   = sockOpen.ident
        sockIO.ioctl   = tcpSO_LINGER_SET
        sockIO.pData   = adr(linger_opt)
        sockIO.datalen = sizeof(linger_opt)
        
        ssw = 3
    endaction        
    
    action 3:
        sockIO FUB TcpIoctl()
        
        if (sockIO.status = 0) then
            ssw = 4
        endif
    endaction                        
                                
        
    ; client einrichten
    action 4:
        sockClient.enable   = 1
        sockClient.ident    = sockOpen.ident
        sockClient.pServer  = adr("192.168.10.60")
        sockClient.portserv = 1234

        ssw = 5
    endaction

    ; FUB abarbeiten bis verbunden
    action 5:
        sockClient FUB TcpClient()
        
        wait = wait +1
        
        ; timeout wenn kabel abgezogen
        if (wait > 20) then
            wait = 0
            ssw  = 100
        endif
        
        if (sockClient.status <> 65535) then
        
            ; ok
            if (sockClient.status = 0) then
                ssw = 6
                
            ; fehler
            else
                ssw = 100
            endif
        endif
    endaction
    
    ; warte-loop
    action 6:    
        if (aktidx <> logbuf.idx) then
            ssw = 10
        endif
    endaction
    
    ; daten senden
    action 10:
        sockSend.enable  = 1
        sockSend.ident   = sockOpen.ident
        sockSend.pData   = adr(logbuf.msg[aktidx].msg)
        sockSend.datalen = strlen(adr(logbuf.msg[aktidx].msg)) +1
                            
        ssw = 11
    endaction
    
    ; FUB abarbeiten bis daten gesendet wurden
    action 11:
        sockSend FUB TcpSend()
        
        if (sockSend.status <> 65535) then
        
            ; ok
            if (sockSend.status = 0) then
                aktidx = aktidx +1
                    
                if (aktidx = maxsize) then
                    aktidx = 0
                endif
            
                ssw = 4
                
            ; retry
            else if (sockSend.status = 32607) then
                ssw = 12
                
            ; fehler
            else
                ssw = 100
            endif
        endif
    endaction
    
    ; kurz warten
    action 12:
        wait = wait +1
        
        if (wait > 5) then
            wait = 0
            ssw  = 11
        endif
    endaction
        
    ; fehler -> reconnect
    action 100:
        sockClose.enable = 1
        sockClose.ident  = sockOpen.ident
        sockClose.how    = 0
        
        ssw = 101
    endaction
    
    action 101:
        sockClose FUB TcpClose()
        
        if (sockClose.status <> 65535) then            
            ssw = 102
        endif
    endaction
    
    ; kurz warten
    action 102:
        wait = wait +1
        
        if (wait > 20) then
            wait = 0
            ssw  = 0
        endif
    endaction
    
endcase

Im Handbuch ist kein Beispiel und ich weiß jetzt nicht mach ich bei TcpClose() was falsch oder muß ich noch irgendwelche Optionen setzen?

Im Handbuch steht zum Fehler 32608 nur folgendes:

Wird der Status tcpERR_INVALID returniert, muss der Client-Ident komplett geschlossen (TcpCLose()) werden. Soll erneut versucht werden, eine Verbindung aufzubauen, ist wieder von vorne zu beginnen (TcpOpen(), Optionen setzen, TcpConnect()).




Gruß,
Marco
 
Zuletzt bearbeitet:
Hallo,
kann mir nicht vorstellen, dass es am Test Tool liegt.

Zum Beispiel: Wenn Du das Automation Studio 3 verwendest findest du unter den Beispiellibrarys einen Beispielquellcode.

Was ich an deiner Stelle auf jeden Fall machen würde ist einen lokalen Port zu vergeben, das wird auch so gefordert.
Bei TCP Open den gleichen Port wie bei TCP Client angeben. (Oder auch ein anderer, aber nicht 0)

Ich gebe bei den Options dann noch tcpOPT_REUSEADDR mit. (TCP Open)
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Nach langem rumprobieren hab ich festgestellt das wenn sich ein Client mit dem Tool verbunden hat sich kein zweiter verbinden kann. Ich schreib jetzt mal das Gegenstück, sprich den tatsächlichen Server der die Daten empfangen soll.

Ich hab nur AS 2.7, das 3er will der Chef nichtbezahlen :(

Könntest du mir das Beispiel aus der Library posten oder zuschicken?
 
Zuletzt bearbeitet:
Ich hab nur AS 2.7, das 3er will der Chef nichtbezahlen
Geizkragen :D Auf die Dauer wird er aber nicht drum rum kommen, weil die neue Hardware von B&R das Studio 3 voraussetzt.

Könntest du mir das Beispiel aus der Library posten oder zuschicken?
Klar. Mach ich am Montag wenn ich wieder in der Firma bin.

Ich schreib jetzt mal das Gegenstück, sprich den tatsächlichen Server der die Daten empfangen soll.
Implementierst du den auch in B&R?
 
Zum Studio: Meine zwei Kollegen sind weg, ich hatte vorher nur die Leitrechner-Software geschrieben und hab jetzt das B&R noch dazu bekommen. Das Problem: Wir haben Provit2200, PP220, PP420, PP45 im Einsatz. Dazu kommen noch eben 5.7" und 10.4" und obendrein noch entweder CAN oder X2X. Und die Software für unsere Maschinen ist eine über 10 Jahre gewachsene Struktur an der inzwischn 4 Leute programmiert haben, also kannst dir vorstellen wieviel unterschiedliche Projekte aufm Server liegen was das für mich bedeutet einen Fehler zu finden, zu verbessern und die Änderungen in den anderen Projekten nachzuziehen :D

Ich brauch kein Killer-OOP, aber wenn ich mit dem 3er Studio zumindest per C++ die ganzen Sachen etwas kapseln kann um von den 364527378 Millionen globalen Variablen wegzukommen wäre ich schon ziemlich glücklich :D


Und der Server ist so eine Art einfacher Syslog-Server der einfach nur Strings empfängt und die abspeichert, entweder DB oder File, überleg ich mir noch. Das ganze läuft als dann auf dem Leitrechner-Server den sowieso jeder Kunde von uns hat.
Wie oben beschrieben sind unsere Programme für unsere Maschienen sehr komplex und ich möchte einfach erstmal was einbauen was mir zu der Protokollierung der Istwert-Daten einfach ein zweites "geheimes" Protokoll erstellt was hat der Bediener gemacht oder in welchem Programmteil ist ein Fehler aufgetaucht damit ich in Zukunft es etwas leichter habe Fehler einzugrenzen.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Meine zwei Kollegen sind weg
Fachkräftemangel?

10 Jahre gewachsene Struktur an der inzwischn 4 Leute programmiert haben
Vielleicht Zeit für einen Cut. :D

364527378 Millionen globalen Variablen
Das Problem kenne ich ;)

3er Studio zumindest per C++
C++ kostet aber derzeit nochmal richtig Asche ...

Ich brauch kein Killer-OOP
Im Embedded Bereich sicherlich nicht, es geht ganz einfach um ein wenig Objektorientierung um den Code wiederverwendbarer zu machen. Solche Sachen wo C einfach an seine Grenzen kommt.
Auf die bekannten nicht deterministischen Schlüsselwörter sollte in der Echtzeitentwicklung verzichtet werden.
 
Ja etwas Kapselung im Code wär schon toll.

Und Fachkräftemangel haben wir keinen, eher Involvenz + neuer Chef der uns aufgekauft hat und der partout nicht kapieren will das man nicht immer nur sparen kann sondern auch mal was investieren muß. Zumal IDE's und anständige Rechner heutzutage genauso Standard-Werkzeuge sind wie z.B. ein anständiger Schweißapparat. Schicke Bearbeituungszentren mit Keramik-Wendeplatten für die Werkzeuge aber der arme Konstrukteur muß mit einem Pentium4 mit 19" Röhrenmonitor arbeiten. Oh ich könnt mich schon wieder aufregen :D
 
Hab den Server fertig, war tatsächlich das Test-Tool. Kann jetzt sauber die Verbindung händisch resetten, auch der automatische reconnect bei Verbindungsabbruch oder Kabel ziehen funktioniert.
 
Eigentlich nix, nur das es halt nur eine Verbindung akzeptiert statt mehrere.

Aber das Beispiel vom AS 3 kannst mir trotzdem mal zuschicken zum studieren :)
 
Hm, die Beispiele unterscheiden sich so gesehen gar nicht von dem was ich fabriziert habe, also gehe ich mal davon aus das ich es richtig gemacht habe ;)

Was ich auch gesehen habe das der "Server" nur einen Client bedient, ich hab halt N Clients. Pack ich mir die Infos vom Client (Ip, Port, Ident) dann einfach in eine Schleife und Loop die durch? Aber was passiert bei TcpSend() oder TcpRecv()? Blockieren die FUB's bis was kommt?

Das Problem das ich habe das ich Daten zwischen zwei Steuerungen austauschen will, aber eben nicht weiß wer sendet zuerst was. Der Slave an den Master oder umgekehrt. Ich hab in einem alten Projekt von meinem Ex-Kollegen mir das mal angeschaut, der macht das aber per UDP und hat zwei Verbindungen, eine zum Senden und eine zum Empfangen. Weiß nicht ob das sinnvoll ist, normal kann ich doch alles über eine Verbindung abwickeln?

Wir haben zur Zeit Probleme mit dem PP400, seltsame Fehler die meistens auf das Ethernet zurück zu führen sind, beim PP200 hatten wir die nicht. Der Ethernet-Controller vom PP400 scheint da etwas zickig zu sein. Wir hatten heute den Verkaufsleiter bei uns im Haus, aber was genaues konnte er mir dazu nicht sagen. Deswegen experimentiere ich grad mit TCP in meinem "Lern-Projekt" um das zu Testen und dann unsere eigentlichen Steuerungen umzubauen auf TCP um zu sehen ob wir dann etwas Ruhe in Netzwerk bringen.

Da fällt mir auch noch ein: Die Infodaten die ich austausche sind in einer Struktur verpackt die ich dann hin- und hersende. Wie kann ich bei so was effektiv überprüfen ob sich was geändert hat? So ne art Checksumme und mir die dann merke? Oder in einer Schleife jeden einzelnen Wert überprüfen ob er sich verändert hat?
 
Hallo Leuchtkeks (schöner Name, leuchtet so schön :)

also ich würde auf Verdacht nicht einfach UDP auf TCP umbauen - noch dazu wo der eigentliche Fehler nicht lokalisiert ist und nicht klar ist ob das mit UDP zusammenhängt.

Da würde ich etwas mehr Zeit verwenden um den Fehler zu analysieren (Logbuch Einträge, Fehlerverhalten versuchen zu nachzustellen, )

Verschiedene Prozessoren haben z.T. auch unterschiedliches Verhalten im Bezug auf Zykluszeit usw. --> könnte anderes Verhalten der Applikation bewirken.

---
Effektives vergleichen : am Besten mit memcmp, wenn Sende_Flag gesetzt ist, müssen deine Fubs senden....

Code:
 if (memcmp(ADR(Quelle), ADR(Quelle_cmp), sizeof(Quelle)) <> 0) then
     Sende_Flag = 1
     memcpy(ADR(Quelle_cmp), ADR(Quelle), sizeof(Quelle_cmp))
endif

....
....

if (Sende_Flag = 1) then
 .... 
 do senden
 ....
endif
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Ich war neulich bei einem Kunden, da hatte sich rausgestellt dass das (ungeschirmte) Ethernet-Kabel direkt neben den Motorleitungen lag. Sobald mehr als zwei Maschinen liefen (mit FU) war Ende. Kabel gegen ein geschirmtes getauscht und schon war Ruhe.

Wie gesagt vorher mit dem PP200 lief das ganze Jahrelang ohne Problem, mit dem PP400 nicht mehr.

Hab bei nem anderen Kunden das Netz dann mal mit nem Ethernet-Tester durchgemessen. Ist zwar Frameverlust vorhanden, aber noch innerhalb der Toleranz.
 
Da fällt mir auch noch ein: Die Infodaten die ich austausche sind in einer Struktur verpackt die ich dann hin- und hersende. Wie kann ich bei so was effektiv überprüfen ob sich was geändert hat? So ne art Checksumme und mir die dann merke? Oder in einer Schleife jeden einzelnen Wert überprüfen ob er sich verändert hat?

Normerweise weißt du doch wenn du etwas in die Struktur schreibst, mit diesem Ereignis schickst du das Packet dann auch ab.
Also löst die Funktion die die Daten in die Struktur schreibt das Ereignis zum senden aus.

@bits'bytes: Der Vergleich mit memcmp muss nicht zwingend gut gehen, vorallem wenn in der Struktur nicht auf das Memory Alignment geachtet wurde. (Meistens so)
Könnte sein memcmp gibt eine Fehlinformation aus, dass die Strukturen unterschiedlich sind, obwohl sie eigentlich gleich sein.

TCP Multiserver ist kein Problem und eine feine Sache.
Ich lege für jeden zu verbindenen Clients ein TcpSend und TcpReceive an, da die Fubs intern States verwenden.

Pro Zyklus gehe ich mit einer Schleife über alle Clients.
Vor TcpSend und TcpReceive muss auf jeden Fall immer der TcpServer aufgerufen werden, da der die Verbindungen managed. Sonst sind die Verbindungen tot.

Weiß nicht ob das sinnvoll ist, normal kann ich doch alles über eine Verbindung abwickeln?
Würde sagen es ist nicht sinnvoll, wenn man UDP einsetzt muss man sich immer die Frage stellen, sind die Daten wichtig die ich versende oder dürfen diese auch verloren gehen?
Wenn sie wichtig sind, dann nimm ich gleich TCP anstatt in UDP im Endeffekt TCP nachzubauen.
 
Würde sagen es ist nicht sinnvoll, wenn man UDP einsetzt muss man sich immer die Frage stellen, sind die Daten wichtig die ich versende oder dürfen diese auch verloren gehen?
Wenn sie wichtig sind, dann nimm ich gleich TCP anstatt in UDP im Endeffekt TCP nachzubauen.

Jup, genau das wird gemacht. Beim senden werden zwei Checksummen mitgeschickt sowie die IP, beim Empfang dann die Checksummen gegenrechnet und noch die IP überprüft ob das alles passt. Ich glaub wenn ich mich recht entsinne liegt das daran dass das ganze vor Urzeiten mal als Library geschrieben wurde für die ersten Provit's die untereinander und noch mit der ganz alten Leitrechner-Software auf ner NT Kiste kommuniziert haben. Und damals war irgendwas mit TCP weswegen das ganze dann mit UDP gemacht wurde. 100% weiß ich es auch nicht mehr genau.
 
Eben, das ist auch mein Gedanke. Und deswegen die Überlegung von UDP auf TCP umrüsten weil wie gesagt wir zur Zeit die seltsamsten Phänomene in unserer Steuerung haben was die Kommunikation betrifft. Der Verkaufsleiter von B&R der heute da war schickt mir ein Angebot die Tage zu wegen Upgrade aus Automation Studio 3 ink. zwei Tage Intensiv-Kurs bei uns im Haus, dann kann ich dem auch mal unsere Programme zeigen und mit dem abklären ob das so noch alles sinnvoll ist, siehe die vorherigen Beiträge zwecks gewachsener Struktur und so.
 
@bits'bytes: Der Vergleich mit memcmp muss nicht zwingend gut gehen, vorallem wenn in der Struktur nicht auf das Memory Alignment geachtet wurde. (Meistens so)
Könnte sein memcmp gibt eine Fehlinformation aus, dass die Strukturen unterschiedlich sind, obwohl sie eigentlich gleich sein.

Sehe ich nicht so. Wenn beide Variablen den selben Typ haben (z.B tMyType) dann kann das gar nicht schief gehen.

auch wenns zB. so aussehen würde (xx sind die "Leerbytes", welche durch Alignment nicht verwendet werden)

B1, B2
B3
xx
B5, B6, B7, B8
B9
xx, xx, xx
B13, B14, B15, B16

Wenn jetzt beide Variablen den selben Typ haben, geht das sicher gut. Wenn sich irgend ein Bx ändert wird gesendet, ein xx ändert sich ja sowieso nicht, da ja nicht verwendet.

bg
bb
 
Zurück
Oben