Permalänk
Medlem

Python sockets

Hej hopp.
Det är så att jag kodar lite på fritiden på hobbynivå, d.v.s jag skriver förmodligen smutsigt och oeffektivt etc.. men det spelar inte mig någon roll då det fungerar och programmen gör som jag vill. Mycket av min programmering rör en raspberry pi och dess GPIO.
Har nu gjort ett program(med ett gui) som kan köras på en valfri dator i hemmet. Genom detta program vill jag nu kunna skicka instruktioner till min PI via nätverket(LAN). Har då googlat lite och fått fram att det är "sockets" man ska använda sig utav.
Har tittat lite på tutorials, läst lite men det har inte riktigt fastnat då de mest bara kör på utan att riktigt förklara vad de gör.
Tänkte då höra om någon kan tipsa om något bra ställe att läsa lite om just sockets.
Så som jag vill använda det kan t.ex se ut såhär:

Pi: Påslagen och väntar på ett kommando
Gui program: Skickar ett meddelande i stil med "a7"
Pi: Ååh vad trevligt, jag har ett meddelande som säger "a7"
Pi:Analyserar meddelandet och kör en funktion beroende på vad som stod i det. t.ex kan "a7" betyda att GPIO 7 skall bli HIGH
Pi: Nu har jag utfört min order, skickar en retur till Gui-datorn igen att jag är klar
Gui program: Nu fick jag svar, Pi är klar med sin instruktion
Pi:Väntar på en ny order av Gui..
etc.

d.v.s kortfattat:
Skicka en instruktion från mitt gui till pi, pi analyserar instruktionen och kör den. Pi returnerar sedan att den är klar och väntar på en ny instruktion.

Kanske finns ett annat sätt att göra detta på, mitt krav är att det sker över nätverk iaf.
Kodar i Python 3+

Så hoppas någon kan tipsa om något läsvärt eller exempel på en liknande "setup".

Visa signatur

Bara gammalt skräp...

Permalänk
Hedersmedlem

Vad har du tittat på för tutorials? Ibland kan man tycka att det bara matas på information för att det är jobbigt att ta in men all information egentligen finns där.

Denna tutorial till exempel ger ett simpelt exempel.
http://www.tutorialspoint.com/python/python_networking.htm

Det kan vara lättare om du pekar på vilka bitar som förvirrar. Saknar du förståelse för portar? Hänger du inte med i logiken? Är det vissa funktionsanrop som verkar konstiga?

Permalänk
Medlem

Tittade på Sentdex? tror jag han heter blandannat från pythonprogramming.net
Han har varit bra på mycket annat men tycker att han svävade iväg lite angående sockets.
Sen hittade jag någon tutorial efter en googling men den stack också iväg ganska snabbt och började "balla ur" utan att egentligen förklara vad alla funktioner gjorde etc..

Den du länkade var ju ganska bra faktiskt och sätter ju upp en enkel server och klient.
Min nivå/kunskap är ganska basic. Men IP och portar har jag väl hyffsad koll på.
Begrepp som TCP och UDP har man ju hört lite här och där men vet egentligen inte vad det betyder(nämns ju i länken).

Antar att man får köra lite "Hello world" igen nu när man kommer till nätverk. Ta det långsamt och ett steg i taget

Men jag ska försöka knåpa ihop lite "skarp" kod så återkommer jag när det skiter sig
Tack för länken iaf!

Visa signatur

Bara gammalt skräp...

Permalänk
Medlem

Ok, har testat lite nu på kvällen när dottern äntligen somnat^^
Gick ganska bra och fick till det, tänkte att jag skulle skriva vad jag gjort sen kanske förstå hur det fungerar.
Har kört på två separata datorer där en är server och den andra klient.

Serverskript:

import socket s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) host = "192.168.1.66" port = 12345 def dblIt(nummer): nytt = int(nummer)*2 return nytt s.bind((host, port)) s.listen(5) while True: print ("Waiting for a connection....") c, addr = s.accept() print ("Got connection from", addr) dubblerat = dblIt(c.recv(1024).decode()) msg = "Dubblerat nummer "+str(dubblerat) c.send(msg.encode()) c.close()

Dold text

Som det verkar så vid s.accept() så stannar scriptet och väntar på att någon ska connecta? Om ingen gör det så kommer scriptet aldrig att fortsätta? Vore bra att få bekräftat.
I övrigt är det väl inga konstigheter här, hade lite problem med att jag var tvungen att köra encode()/decode() p.g.a python3?
Är inte riktigt säker på vad siffran i s.listen() betyder.

Klient:

import socket s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) host = "192.168.1.66" port = 12345 s.connect((host, port)) msg = "5".encode() s.send(msg) print(s.recv(1024).decode()) s.close()

Dold text

Inga större konstigheter här heller. Jag skickar iväg 5 till servern och får som svar 10 då servern dubblerar i sin funktion.

Känns kul ändå att det fungerar, ska nu försöka mig på ett lite mer större skript med en mer avancerad serversida.
Återkommer om något går åt helvete

Visa signatur

Bara gammalt skräp...

Permalänk
Hedersmedlem
Skrivet av bardbard:

Ok, har testat lite nu på kvällen när dottern äntligen somnat^^
Gick ganska bra och fick till det, tänkte att jag skulle skriva vad jag gjort sen kanske förstå hur det fungerar.
Har kört på två separata datorer där en är server och den andra klient.

Serverskript:

import socket s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) host = "192.168.1.66" port = 12345 def dblIt(nummer): nytt = int(nummer)*2 return nytt s.bind((host, port)) s.listen(5) while True: print ("Waiting for a connection....") c, addr = s.accept() print ("Got connection from", addr) dubblerat = dblIt(c.recv(1024).decode()) msg = "Dubblerat nummer "+str(dubblerat) c.send(msg.encode()) c.close()

Dold text

Som det verkar så vid s.accept() så stannar scriptet och väntar på att någon ska connecta? Om ingen gör det så kommer scriptet aldrig att fortsätta? Vore bra att få bekräftat.
I övrigt är det väl inga konstigheter här, hade lite problem med att jag var tvungen att köra encode()/decode() p.g.a python3?
Är inte riktigt säker på vad siffran i s.listen() betyder.

Klient:

import socket s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) host = "192.168.1.66" port = 12345 s.connect((host, port)) msg = "5".encode() s.send(msg) print(s.recv(1024).decode()) s.close()

Dold text

Inga större konstigheter här heller. Jag skickar iväg 5 till servern och får som svar 10 då servern dubblerar i sin funktion.

Känns kul ändå att det fungerar, ska nu försöka mig på ett lite mer större skript med en mer avancerad serversida.
Återkommer om något går åt helvete

Det ser bra ut.

Det finns bra dokumentering för sockets. Det är bara att leta:
https://docs.python.org/3/library/socket.html#socket.socket.l...

Permalänk
Medlem

s.accept är ett s.k. blockerande anrop, d.v.s. anropet ska inte returnera förens en uppkoppling har etablerats. Dock finns det i dokumentationen angivet flera fall då anropet kommer att resultera i ett undantag och vad anledningen är. Mitt råd är att läsa igenom dokumentation kring dessa funktioner för att se vad som kan gå fel.

s.listen anger en kö-längd, d.v.s. hur många kan ligga och "vänta" på att få sin uppkoppling etablerad medans "servern" håller på och hanterar ett annat anrop. Om antalet "väntande" anrop överstiger gränsen du sätter så kommer uppkopplingar att börja nekas.

Visa signatur

-- Citera mig om ni vill få återkoppling --

Permalänk
Medlem
Skrivet av dopedog:

s.accept är ett s.k. blockerande anrop, d.v.s. anropet ska inte returnera förens en uppkoppling har etablerats. Dock finns det i dokumentationen angivet flera fall då anropet kommer att resultera i ett undantag och vad anledningen är. Mitt råd är att läsa igenom dokumentation kring dessa funktioner för att se vad som kan gå fel.

s.listen anger en kö-längd, d.v.s. hur många kan ligga och "vänta" på att få sin uppkoppling etablerad medans "servern" håller på och hanterar ett annat anrop. Om antalet "väntande" anrop överstiger gränsen du sätter så kommer uppkopplingar att börja nekas.

Tackar för svar och förklaring. Något jag tror jag lyckades läsa mig till är att send() och recv() också är blockerande anrop men att det går att ändra med setblocking() ? För min tilltänkta applikation så får det gärna vara blockerande

Visa signatur

Bara gammalt skräp...

Permalänk
Medlem
Skrivet av bardbard:

Tackar för svar och förklaring. Något jag tror jag lyckades läsa mig till är att send() och recv() också är blockerande anrop men att det går att ändra med setblocking() ? För min tilltänkta applikation så får det gärna vara blockerande

Precis så är det.

Visa signatur

-- Citera mig om ni vill få återkoppling --

Permalänk
Medlem

Tänkte väcka denna tråd till liv igen då jag kommit en bra bit på vägen med mina sockets.
Tänkte höra om metoden jag använder är rätt..

Har en server samt klient(såklart...). Klienten skickar data till servern och sedan väntar klienten på svar från servern innan den fortsätter.
Här använder jag mig utav recv() för att pausa programmet tills servern skickar något.

Det jag funderar på är om det finns bättre sätt då servern kanske tar 5 sekunder på sig ena gången för att skicka svar, medans nästa gång kanske det tar 40sekunder.
Finns det någon nackdel med att ha klienten blockerad i 40sek med recv()?
Läste någonstans att man enbart ska använda recv() när man vet att ett meddelande är påväg, inte använda det som en blockad som jag gör då det fanns andra sätt?

Visa signatur

Bara gammalt skräp...

Permalänk
Medlem
Skrivet av bardbard:

Tänkte väcka denna tråd till liv igen då jag kommit en bra bit på vägen med mina sockets.
Tänkte höra om metoden jag använder är rätt..

Har en server samt klient(såklart...). Klienten skickar data till servern och sedan väntar klienten på svar från servern innan den fortsätter.
Här använder jag mig utav recv() för att pausa programmet tills servern skickar något.

Det jag funderar på är om det finns bättre sätt då servern kanske tar 5 sekunder på sig ena gången för att skicka svar, medans nästa gång kanske det tar 40sekunder.
Finns det någon nackdel med att ha klienten blockerad i 40sek med recv()?
Läste någonstans att man enbart ska använda recv() när man vet att ett meddelande är påväg, inte använda det som en blockad som jag gör då det fanns andra sätt?

Hej,

Man brukar programmera sockets med asyncronous io för kunna hantera flera connections samtidigt. Annars kommer bara 1 klient kunna hanteras åt gången i och med det är blockerade. Vanlig för det är man använder select i olika programmerings språk. Här är ett exempel.

https://pymotw.com/2/select/

Annat är ett annat alternativ att du programmerar med threads. Nackdelen är att det tar lite mer minne av servern då den behöver spawna en ny thread per connection. Har gått lite i mode fram och tillbaka det där om man ska programmera med select eller threads.

EDIT: Nu förstod jag inte exakt vad du försöker göra men en annan lösning om försöker skicka kommandon till servern som ska exekveras är att du tar en ditt på fabric i python.

Permalänk
Medlem

@nighter
Hej och tack för svar. Tror jag behöver beskriva lite mer detaljerat vad det är jag försöker göra då dina förslag känns lite på fel spår.
Så jag har en raspberry pi som är kopplad till motorer och sköter styrningen av dessa.
På pajen ligger servermjukvaran. På en laptop ligger klientmjukvaran.
Det jag gör är att via ett GUI på laptopen skickar instruktioner till pajen hur den skall köra motorerna. Detta sker över nätverk därav användningen av sockets.
Sekvensen ser då ut på följane sätt:
1: Klienten(laptop) skickar instruktioner till server(pi). Exempelvis "kör motor 1 i 20 sekunder". Klienten avvaktar nu svar från server(via recv())
2: Servern mottager instruktion och utför
3: Servern skickar till klienten att instruktionen är utförd
4: Klienten mottager svar från servern att instruktionen är utförd. Koden fortsätter att rulla

Tiden en motor körs är den som varierar, kanske 1 sekund ena gången och 37 sekunder den andra.
Jag kommer aldrig att ha mer än 1 klient ansluten så trådar etc känns inte som att det är aktuellt.
När man bara har 1 klient som jag kanske recv()-blockad inte är några fel?

Nåväl, hoppas du förstår bättre nu hur mitt case ser ut

Visa signatur

Bara gammalt skräp...

Permalänk
Medlem

har en liten fundering angående detta igen...

Buffras meddelande som sänds via sockets om t.ex mottagaren inte hinner med, typ enligt följande:

#Fil som skickar kanske skickar såhär, d.v.s "ingen" delay emellan s.send("1".encode()) s.send("2".encode()) s.send("3".encode()) #Medans filen som tar emot datan kanske beter sig på följande sätt a = s.recv(1024).decode() sleep(3) b = s.recv(1024).decode() sleep(3) c = s.recv(1024).decode()

Skulle mottagaren i fallet ovan då få resultatet att a=1, b=2, c=3 eller skulle det bli något error iom att mottagaren inte är "redo" att lyssna?
När meddelande skickas så lagras det i en buffer vilka mottagaren läser när denne är redo?

Tacksam för svar

Visa signatur

Bara gammalt skräp...