Socket kommunikáció PC és PLC között

Socket kommunikáció PC és PLC között
2014-02-06T15:21:27+01:00
2014-02-07T15:19:36+01:00
2022-11-30T12:15:38+01:00
djsamtech
Sziasztok!



A téma címében megjelölt problémával foglalkozom. PC és PLC között szeretnék TCP kapcsolatot létrehozni.

Az eddigi próbálkozásaim sem eredménytelenek. Egy jó pár tutorial, és mintapélda alapján sikerült is a kapcsolat létrehozása és az adatok fogadása.



Azt tudni illik azért, hogy ez előtt nem volt még dolgom socket programozással.



A feladat alapesetben annyi, hogy nyitok egy socket segítségével nyitok egy portot a PC, majd várom hogy a PLC, mint kliens csatlakozzon és adatokat küldjön a PC-re.



TcpListener / TcpClient segítségével egy C#-os konzol alkalmazásban ez pikk-pakk össze is jött.



Viszont szeretném ezt az egészet WinForm alapokra ültetni. Azaz lenne egy Form-om, amivel eltudom indítani a kommunikációt, és mondjuk egy listboxban megjeleníti nekem az adatokat. Majd ezt a kommunikációt egy Button-nel megszüntethetem. A konzolos alkalmazásom próbáltam átülteni formra, de nem nagyon működöt.


Találtam nagyon jó minta példát egy TCP alapú chat programra, mely egyszerű socket alapokon a localhost címmel tökéletesen dolgozik is, azonban ha a socket.Bind()-nak az Ethernet kártyám IP-címét és egy adott portot beállítok, akkor socket.Accept()-nél megáll a dolog.



A Bind()-nál azért gondoltam megadni fixen az IP-t és a portot, mivel a PLC is fixen azt az IP-címet és portot célozza meg. Próbáltam az IPAddress.Any-t is de az sem segített.



Gondoltam arra is, hogy esetleg a szinkron / aszinkron metódusok körül kellene matatnom, de mivel abban még annyira sem vagyok jártas, így azt még halogattam.



Minden segítséget, útmutatást előre is nagyon köszönök!
Mutasd a teljes hozzászólást!
Csatolt állomány
Helló!

Szerdzso kollégával ellentétben én nem ajánlanám a Socket használatát.

Az általad leírtak alapján (TCP kapcsolatra van szükséged) én maradnék a TcpClient-nél, mivel az gyakorlatilag nem más, mint egy wrapper a Socket körül, amit sokkal egyszerűbben lehet használni, mint a nyers Socket-et. A Socket osztály általános használatra van kitalálva, a TcpClient kifejezetten TCP kapcsolatok egyszerűbb kezelésére (kb. úgy kell elképzelni, mint ha StreamReader-rel olvasnál file-t a File.ReadAllText() helyett - nyilván az utóbbi is az előbbit használja, csak ez utóbbi egyszerűbb).

Ebben a topicban alaposan végigtárgyaltuk a témát, javaslom végigolvasni. Az elfogadott megoldás egy Forms alapú, TCP kommunikációra alkalmas példaprogram forrását tartalmazza, azaz ez szerintem alkalmas az induláshoz.

Nézd meg, aztán kérdezz, ha valami nem tiszta!
Mutasd a teljes hozzászólást!

  • Szia!

    Ha kifejezetten TCP kapcsolatot szeretnél létrehozni a két eszköz között, akkor a socket() metódusod rendben van. Azt tudni kell, hogy ez egy pont-pont kapcsolat orientált kommunikációs csatorna lesz és mint olyannál meg kell tanulni az ABC-t.

    Addressing (címzés)
    Binding(kötés, társítás)
    Connect(kapcsolódás).

    A címzésnél először meg kell határoznod azt a lokális címet, ahol fogadod a bejövő kapcsolatokat és kiszolgálod őket, kommunikálsz velük.

    sock.Bind(new IPEndPoint(IPAddress.Parse("192.168.1.20"), 2500));
    Ezt a sort esetleg lehetne úgy finom hangolni, hogy programkódból kéred le az IP címedet és azt állítod be (ez esetleg változhat, ha DHCP-t használsz vagy a fix IP-det átállítod). A portnak pedig én a 0-át adnám meg igazság szerint, mert elképzelhető, hogy a 2500-as már foglalt. Ha a PLC-ből csak konkrét címre tudsz csatlakozni és ott az nem módosítható akkor legyen ez.

    Na most itt használhatnál TcpListenert is, mert annak egy fokkal kidolgozottabb a használata. Ott a Start() metódussal indítod el a figyelést és valamelyik Accept metódussal fogadod a kapcsolatot. Ott nem kell megadni, hogy hány kliensre vársz, de itt esetleg a te kódodban mondhatnád azt, hogy

    sock.Listen(1);


    Hogy ha legalább már töröd magad azt ne feleslegesen tedd. A paraméterben megadott számmal azt mondod meg, hogy hány kapcsolatra számítasz.

    WinForm esetében helyesen tetted, hogy szálban kezeled a kliens fogadást, mert bizony a sock.Accept() blokkolja az éppen aktuális szálat. Ez pedig úgy hatna, mintha lefagyott volna a program.

    Gondolom a button1-gyel indítod el a figyelést és magát a folyamatot a button2-vel pedig adatot küldesz. A figyelés leállítására nem találok gombot. Ha a szálad IsBackground értéke false (nem háttérszál), akkor előfordulhat, hogy a program bezárását követően a szál még mindig fut és az alkalmazás nem áll le, továbbra is figyel a címen.
    Szinkron Accept metódusnál a TcpListener esetében olyan megoldást tudok a figyelés megszüntetésére blokkolt állapotból, hogy meghívod a TcpListener.Stop() gombot. Így az Accept soron voltaképp egy kivételt váltasz ki, mert a a TcpListener alatt úgymond kivágtad a fát, amin állt. Azt lekezelve ezt ki tudod védeni.
    Ettől szebb megoldás, ha aszinkron Accept metódusokat használsz. Nekem ilyenre éppen a kliens oldalon volt szükség, hogy ha a csatlakozás nem sikerült (mert még a szerver nem indult el), akkor vártam 5 sec-et és újra próbálkoztam.

    Sok sikert !
    Mutasd a teljes hozzászólást!
  • Helló!

    Szerdzso kollégával ellentétben én nem ajánlanám a Socket használatát.

    Az általad leírtak alapján (TCP kapcsolatra van szükséged) én maradnék a TcpClient-nél, mivel az gyakorlatilag nem más, mint egy wrapper a Socket körül, amit sokkal egyszerűbben lehet használni, mint a nyers Socket-et. A Socket osztály általános használatra van kitalálva, a TcpClient kifejezetten TCP kapcsolatok egyszerűbb kezelésére (kb. úgy kell elképzelni, mint ha StreamReader-rel olvasnál file-t a File.ReadAllText() helyett - nyilván az utóbbi is az előbbit használja, csak ez utóbbi egyszerűbb).

    Ebben a topicban alaposan végigtárgyaltuk a témát, javaslom végigolvasni. Az elfogadott megoldás egy Forms alapú, TCP kommunikációra alkalmas példaprogram forrását tartalmazza, azaz ez szerintem alkalmas az induláshoz.

    Nézd meg, aztán kérdezz, ha valami nem tiszta!
    Mutasd a teljes hozzászólást!
  • Sziasztok!

    Szerdzso:

    Kipróbáltam amiket írtál, viszont nem jutottam eredményre.

    1., Az IPAddress.Any akár a 2500-as, akár a 0-s portal sem hozott eredményt. Ehhez még annyit fűznék hozzá, hogy command-ban a netstat -noa paranccsal figyeltem, hogy nyitva van-e a 2500-as port, illetve a figyelés működik-e. Azt kell mondanom ez minden esetben jól működött. A 2500-as port akkor jelent csak meg figyelésre, amikor a TCPlistener.Start(), vagy a socket.Listen() meg lett hívva.

    2., A sock.Listen(0) -t átjavítottam még tegnap sock.Listen(1)-re, de ez sem hozott változást.
    3., A port figyelésének megszakítását megoldottam úgy, hogy szimplán felvettem egy új button-t a formra, melynek megnyomására lefut a sock.Close() utasítás.

    Kukipapa:

    Az általad linkelt topicot már átrágtam előtte is. A mintapéldádat megcsináltam, és valóban működik, ugyan azon a szinten mint az általam is demonstrált socket-es program.
    Azaz: Localhost-on tesztelve tökéletesen működik a szerver és a kliens is. Azonban ha a szervernél átállítom a localEndpoint-ot (a számomra lényeges 192.168.1.20:2500 címre), és várom a PLC (mint kliens) felcsatlakozását, ugyanúgy nem történik semmi. A történet ugyanaz mint a socket-es szervernél: socket-nél a sock.Accept(), TcpClient-nél a listener.AcceptTcpClient() akad el. Vagyis vár a kliensre, aki meg nem csatlakozik rá.

    Ezek számomra csak azért különösek, mert amit saját magam készítettem konzolos alkalmazást TcpListener / TcpClient alapon, az tökéletesen működik, úgy hogy beégetett localEndpoint-ot használok, és természetesen a főszálban fut az egész.



    Valami ötlet még?
    Mutasd a teljes hozzászólást!
  • Helló!

    Még egyszer leírom: ne szenvedj a Socket-tel, mert csak magaddal szúrsz ki. Feleslegesen bonyolítod a dolgodat.

    A TcpCLient osztály belül ugyanazt a Socket-et használja, amit te most közvetlenül próbálsz programozni, de az előbbit a Microsoft mérnökei tervezték pont azért, hogy ilyen triviális feladatokat, mint a TCP-kommunikáció, egyszerűbben lehessen megvalósítani. A Socket közvetlen programozására csak speciális esetben van szükség, a te eseted feltehetően nem ilyen.

    Ez kb. olyan, mintha webes kommunikációra nem a WebClient oszályt használnád, hanem nekiállnál megvalósítani a komplett socket felépítést, TCP-t, HTTP-t, mindent. Felesleges. Mindent arra használjunk, amire való.

    Azonban ha a szervernél átállítom a localEndpoint-ot (a számomra lényeges 192.168.1.20:2500 címre)


    Amennyiben a TcpListener konstruktorára gondolsz a szerver részben:

    this.tcpListener = new TcpListener(IPAddress.Any, 3000);

    akkor azt hagyd így, ahogy van, mivel itt a szerver-végpontot definiálod, nem a kliensét.

    A végpontot a kliensnél kell megadni, azaz, hogy hova kapcsolódjon, pl. ha a szervered IP címe 192.168.1.45, akkor:

    serverEndPoint = new IPEndPoint(IPAddress.Parse("192.168.1.45"), 3000);

    Ez a kód tesztelten működik, két különböző gépen futtatva a szerver és a kliens részt, így amennyiben neked már a példakód futtatásánál problémáid vannak, akkor ott valami más, pl. tűzfal gond lesz. Javaslom, hogy először próbáld meg a példakódot működésre bírni, és amikor az stabilan megy, utána cseréld le a kliens részt a PLC-re!

    Még egy gondolat. Bár írtad, hogy localhost-on működik a kód, de azért ellenőrzésképpen megkérdezem: ugye a Form_Load eseményeket szépen létrehoztad, nemcsak copy/paste-elted a kódot? Mert különben az nem fog lefutni, így hiába vársz a szerver thread indulására.

    (Többször szerkesztve.)
    Mutasd a teljes hozzászólást!
  • Helló!



    Rávilágítottál a legbanálisabb problémára amit elkövethettem!

    Ha kicsit több IQ-val rendelkeznék, akkor első dolog lett volna, hogy kilövöm a tűzfalakat (mivel, hogy 2 is van a gépen).

    Bár érdekesnek tartom, hogy a konzolnak a tűzfal nem jelentett akadályt, a Form-nak pedig igen.



    Mindent egybe vetve: az alkalmazások mind jól működnek TcpListenerrel és Socket-el is.

    A pont neked jár!

    Köszönet a türelmedért és segítségedért!
    Mutasd a teljes hozzászólást!
Tetszett amit olvastál? Szeretnél a jövőben is értesülni a hasonló érdekességekről?
abcd