Συζήτηση
Γεια χαρά, Επισκέπτης
Όνομα χρήστη: Κωδικός: Να με θυμάσαι

ΘΕΜΑ: Sockets,Client,Server (python 2.17.12)

Sockets,Client,Server (python 2.17.12) 7 Χρόνια 10 Μήνες πριν #3948

  • Psileas25
  • Το Άβαταρ του/της Psileas25
  • Αποσυνδεμένος
  • p_____
  • Δημοσιεύσεις: 6
Καλησπέρα παιδιά,

Έχω σαν εργασια να κατασκευασω ενα chat σε python , οπου ενας client θα συνδεεται σε ενα server και θα ανταλλάσουν μεταξυ τους μηνυματα.Ο καθηγητης μας πεταξε κατευθειαν στα βαθια και εχω πελαγωσει λιγο.Μετα απο συνεχεις αναζητησεις στο internet βρηκα τι ακριβως πρεπει να κανω , το τρεχω και το πραγμα δουλευει.Το θεμα , ομως , ειναι δεν ξερω σε καποια σημεια τι ακριβως γινεται.

Αρχικα για τον server:
Δημιουργω server και port , φτιαχνω το socket , κανω bind και listen και μολις συνδεθει ο client παω σε μια infinite loop οπου οι ενοτλες εκει μεσα μου φαινονται τελειως αγνωστες.Σας κανω ενα copy paste τι ακριβως υπαρχει εκει μεσα:

while 1:

received_data = conn.recv(1024)
sys.stdout.write(received_data);sys.stdout.flush()
read_data = sys.stdin.readline()
conn.send(read_data)
sys.stdout.flush()

conn.close()

Μπορεις καποιος που εχει γνωση , να μου εξηγησει τι κανει η καθε εντολη?
Πρέπει να είστε εγγεγραμμένο μέλος του Φόρουμ για να κάνετε μια δημοσίευση.

Sockets,Client,Server (python 2.17.12) 7 Χρόνια 10 Μήνες πριν #3950

  • babaliaris1
  • Το Άβαταρ του/της babaliaris1
  • Αποσυνδεμένος
  • python
  • Δημοσιεύσεις: 445
  • Ληφθείσες Ευχαριστίες 75
Psileas25 έγραψε:

while 1:

received_data = conn.recv(1024)
sys.stdout.write(received_data);sys.stdout.flush()
read_data = sys.stdin.readline()
conn.send(read_data)
sys.stdout.flush()

conn.close()

Μπορεις καποιος που εχει γνωση , να μου εξηγησει τι κανει η καθε εντολη?

conn.recv(1024) : Περιμένει μέχρι ο conn να του στείλει εώς και 1024 bytes και όταν τα στείλει
τα αποθηκεύει στο received_data.

sys.stdout.write(received_data) : εμφανίζει τα bytes στην οθόνη.

read_data = sys.stdin.readline() : Διαβάζει κάτι από τον χρήστη και το αποθηκεύει.

conn.send(read_data) : Στέλνει αυτό που διάβασε στον conn.

sys.stdout.flush() : Καθαρίζει τον buffer του stdout.

o Buffer αυτός είναι ένας πίνακας που έχει για στοιχεία τα bytes που θα εμφανίσει στην οθόνη
η επόμενη κλήση του sys.stdout.write. Ο λόγος που την καθαρίζει είναι για να είναι άδεια την επομενή φορά που θα εμφανίσει ένα νέο μήνυμα.
Πρέπει να είστε εγγεγραμμένο μέλος του Φόρουμ για να κάνετε μια δημοσίευση.

Sockets,Client,Server (python 2.17.12) 7 Χρόνια 10 Μήνες πριν #3952

  • Psileas25
  • Το Άβαταρ του/της Psileas25
  • Αποσυνδεμένος
  • p_____
  • Δημοσιεύσεις: 6
Σε ευχαριστω πολυ για τη βοηθεια.

Παω σε επομενη ερωτηση.Στο τριτο κομματι της ασκησης , πρεπει να κανω το chat ετσι ωστε και ο client και ο server να μπορουν να στειλουν οσα μηνυματα θελουν (Στο παραπανω μιλανε ενας ενας , δηλαδη δεν μπορει καποιος απο τους δυο να στειλει δυο-τρια-κλπ μηνυματα σερι).Αυτο απο οτι καταλαβα γινεται με import os και χρηση της συναρτησης fork().Το σκεπτικο μου ειναι να δημιουργειται μια child() και οταν το pid=os.fork()==0 να στελει , οταν ειναι θετικο να λαμβανει , και αρνητικο να βγαζει error.(Αυτα ειναι οι σκεψεις μου και δεν ξερω αμα ειναι σωστες)

ο κωδικας μου ειναι ο παρακατω

#Server

import socket, sys, os

IP = 'localhost'
PORT = 7070


s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

s.bind((IP, PORT))

s.listen(5)

print 'waiting for a connection'

conn, addr = s.accept()
print 'connection address ', addr



pid = os.fork()

while 1:
if pid==0:
received_data = conn.recv(1024)
print'received from client:', received_data
sys.stdout.flush()
if pid>0:
s_message = sys.stdin.readline()
conn.send(s_message)
sys.stdout.flush()
if pid<0
print 'ERROR'

conn.close()

Για τον client ειναι κατι αντιστοιχο.Το προβλημα ειναι οτι οταν ανοιγω τον server ειναι ολα οκ.Μολις μπει ο client μου βγαζει το εξης σφαλμα:

Traceback (most recent call last):
File "C:\Users\User\Desktop\askisi4\client4.py", line 14, in <module>
pid=os.fork()
AttributeError: 'module' object has no attribute 'fork'

Μπορεις να μου πεις τι ακριβως κανω λαθος?
Να σημειωσω οτι με τα παιδια που το τρεχουν με linux ειναι οκ.Μηπως εχουν θεμα τα windows?
Πρέπει να είστε εγγεγραμμένο μέλος του Φόρουμ για να κάνετε μια δημοσίευση.

Sockets,Client,Server (python 2.17.12) 7 Χρόνια 10 Μήνες πριν #3961

  • babaliaris1
  • Το Άβαταρ του/της babaliaris1
  • Αποσυνδεμένος
  • python
  • Δημοσιεύσεις: 445
  • Ληφθείσες Ευχαριστίες 75
Psileas25 έγραψε:
Για τον client ειναι κατι αντιστοιχο.Το προβλημα ειναι οτι οταν ανοιγω τον server ειναι ολα οκ.Μολις μπει ο client μου βγαζει το εξης σφαλμα:

Traceback (most recent call last):
File "C:\Users\User\Desktop\askisi4\client4.py", line 14, in <module>
pid=os.fork()
AttributeError: 'module' object has no attribute 'fork'

Μπορεις να μου πεις τι ακριβως κανω λαθος?
Να σημειωσω οτι με τα παιδια που το τρεχουν με linux ειναι οκ.Μηπως εχουν θεμα τα windows?

Αυτό που σε λέει εδώ η python είναι ότι δεν υπάρχει μέθοδος με το όνομα fork στο module os.
Αυτό νομίζω έχει να κάνει με το την version python χρησιμοποιείς και όχι το λειτουργικό.

Αυτό που κάνει η fork είναι η δημιουργεία ενώς καινούργιου proccess. Ένα proccess είναι ένα ξεχωριστώ κομμάτι κώδικα το οποίο τρέχει παράλληλα με τον άλλο κώδικα που έχεις.
Αυτό είναι χρήσιμο έτσι ώστε να μην κολλάει το προγραμμά σου σε ένα σημείο που χρειάζεται να κάνει κάτι.

Για παράδειγμα η μέθοδος accept() κολλάει την ροή του προγραμματός σου μέχρι ο client να συνδεθεί στον server. Αν δεν θές να κολλάει μπορείς να βάλεις την accept μέσα σε ένα ξεχωριστώ proccess έτσι ώστε να τρέχει αυτόνομα από τον άλλο σου κώδικα.

Υπάρχει ένα module που ονομάζεται Threading και μπορείς να το χρησιμοποιήσεις για να κάνεις proccesses.

Πραγματικά δεν ξέρω γιατί στην σχολή σου σας μαθαίνουν τόσο παλιές λειτουργίες όπως την os.stdout.write και άλλα παρόμοια, είναι τελείως άχρηστα. Η python έχει αναπτυχθεί πάρα πολύ εως τώρα. Τσάμπα σας τυραννάνε.
Τελευταία διόρθωση: 7 Χρόνια 10 Μήνες πριν από babaliaris1.
Πρέπει να είστε εγγεγραμμένο μέλος του Φόρουμ για να κάνετε μια δημοσίευση.

Sockets,Client,Server (python 2.17.12) 7 Χρόνια 10 Μήνες πριν #3962

  • babaliaris1
  • Το Άβαταρ του/της babaliaris1
  • Αποσυνδεμένος
  • python
  • Δημοσιεύσεις: 445
  • Ληφθείσες Ευχαριστίες 75
Πάμε τώρα στο προβλημά σου. Δεν ξέρω τη σας έχουν πει οι καθηγητές σας αλλά εγώ να ξέρω αλλιώς τα πράμματα.

Για να κάνεις ένα chat system κάνεις τα εξής:

1) Χρηάζεσαι έναν server ο οποίος θα λαμβάνει πληροφορία και θα στέλνει από και προς τους clients και δεν θα είναι ταυτόχρονα client ο ίδιος.

2) Χρειάζεσαι τον κώδικα του client.

Άρα αν υποθέσουμε ότι θέλουν να μιλήσουν 2 άτομα μεταξύ τους, πρέπει να τρέχουν 3 προγράμματα ταυτόχρονα. 1 ο server, και τα άλλα 2 θα είναι clients οι οποίοι συνδέονται στον ίδιο server.

Όπως βλέπεις εσύ πριν είχες έναν client και έναν server o οποίος δούλευε και σαν client ταυτόχρονα. Ο server πρέπει να ασχολήτε μόνο με την επεξεργασία των δεδομένων και τίποτα άλλο.

Άρα κοίτα τη θα κάνεις:

Θα φτιάξεις έναν server ο οποίος περιμένει να συνδεθούν 2 χρήστες ακριβώς. Μόλις συνδεθούν, μέσα σε ένα ατελείωτο loop θα αρχίσεις την επεξεργασία.

Επεξεργασία Server:

Στην αρχή του loop σου θα πρέπει να περιμένεις να λάβεις bytes από τους δύο χρήστες κάπως έτσι:
client1.recv(1024)
client2.recv(1024)

Εδώ όμως υπάρχει πρόβλημα. Το client1.recv(1024) θα κολλήσει το προγραμμά σου με αποτέλεσμα ο server να μην λαμβάνει μημύματα από τον client2 μέχρι ώσπου να λάβει τουλάχιστον ένα από τον client1 και να συνεχίσει την κάτω εντολή. Για αυτό πρέπει να βρεις έναν τρόπο να τρέχεις ταυτόχρονα αυτές τις δύο εντολές και ανάλογα με το ποιος θα σου στείλει πρώτος μήνυμα τότε θα κάνεις το εξής:

εάν σε στείλει μήνυμα πρώτα ο client1 τότε ο server σου θα πάρει αυτό το μήνυμα και θα το στείλει στον client2. Και αντίστοιχα εάν πάρει πρώτα από τον client2 θα το στείλει στον client1.
Και έτσι θα πραγματοποιεί την εποικινωνία ο server μεταξύ αυτών των δύο clients.



Τώρα ο κώδικας του client είναι πολύ απλός. Απλός θα συνδέεσαι στον server και μετά μέσα σε ένα ατελείωτο loop θα στέλνεις συνέχει μυνήματα με το server.send(). To πρόβλημα όμως έδώ είναι πως θα λαμβάνεις μηνύματα χωρίς να κολλάει πάλι η ροή του προγράμματος. Σε ένα ξεχωριστώ proccess θα βάλεις ένα ατελείωτο loop το οποίο για πρώτη γραμμη θα έχει server.recv(1024) και μόλις λαμβάνεις ένα μήνυμα θα το εμφανίζεις στην οθόνη.


Αυτήν είναι γενικά η λογική. Προσπαθησέ το και αν δεν τα καταφέρεις θα σου γράψω και κανένα παράδειγμα.
Πρέπει να είστε εγγεγραμμένο μέλος του Φόρουμ για να κάνετε μια δημοσίευση.

Sockets,Client,Server (python 2.17.12) 7 Χρόνια 10 Μήνες πριν #3964

  • babaliaris1
  • Το Άβαταρ του/της babaliaris1
  • Αποσυνδεμένος
  • python
  • Δημοσιεύσεις: 445
  • Ληφθείσες Ευχαριστίες 75
Για να σου κάνω και πολύ ποιο εύκολα τα πράγματα, υπάρχει ένα τρομερό module το οποίο ονομάζεται select, και μπορεί να σου διαχειρηστή αυτόματα τα recv() και accept() χωρίς να κολλάει η ροή του προγραμματός σου και χωρίς να χρειαστεί να κάνεις ξεχωριστά proccesses.

Λοιπόν δες πως ακριβώς είναι ο κώδικας ενός server για chat χρησιμοιποιόντας την select.
import socket, select
 
#Creating the server socket.
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
 
#Bind the server to the local machine with the port 1996.
server.bind( ("", 1996) )
 
#Start listening.
server.listen()
 
running = True
sockets = [server]
 
 
while running:
 
    #Get next network activity.
    readable, writeable, exceptional = select(sockets, [], sockets)
 
    #Server is ready to accept.
    if server in readable:
 
        #Accept the cilent.
        client, addr = server.accept()
 
        #Append the client into the sockets list.
        sockets.append(client)
 
 
    #Elif there are other readable sockets except the server.
    elif len(readable) > 0:
 
        #Read the data.
        data = readable[0].recv(1024)
 
        #The connection with this client has closed.
        #So remove this socket from the list.
        if len(data) == 0:
            readable[0].close()
            sockets.remove(readable[0])
 
 
        #If a client send the commanc /close
        #then shut down the server.
        elif bytes.decode( data ) == "/close":
            running = False
 
        #Send the data to all the clients.
        else:
 
            #Go though all clients.
            for s in sockets:
 
                #Send the message to all other clients
                #except the one who send it and the server ofcourse.
                if s is not readable[0] and s is not server:
                    s.send(data)
 
 
#Close the server socket.
server.close()

Ας καταλάβουμε τη κάνει η select:

Πρώτα παίρνει 3 ορίσματα (input, output, input). Στο input πρέπει να δώσεις μία λίστα η οποία περιέχει όλα τα sockets που είναι ανοιχτά κατά την διάρκεια τις σύνδεσης. Η λίστα πρέπει να περιέχει τουλάχιστον ένα socket αρχικά για αυτό την αρχικοποιώ με τον server ο οποίος είναι το πρώτο socket που δημιουργήτε. Το output είναι απλός μια άδεια λίστα.

Όταν ένα από τα inputs είναι έτοιμο να λάβει μήνυμα, τότε η selecτ επιστρέφει 3 λίστες.

Η πρώτη readable είναι μια λίστα που περιέχει όλα τα sockets από τα οποία είναι έτοιμα να τρέξουν την recv() ή εάν είναι ο server τότε είναι έτοιμος να κάνει accept() έναν νέο client.
Αυτό σημαίνει ότι η select μου εξασφαλίζει ότι οι μεθοδοι recv() και accept() δεν θα κολλήσουν την ροή του προγραμματός μου αφού τα readbable sockets είναι ήδη έτοιμα να το κάνουν αυτό.

Τo writeable είναι μια λίστα με όλα τα sockets στα οποία μπορώ να στείλω κάποιο μήνυμα.

Το exceptional είναι μία λίστα με όλα τα sockets τα οποία ανύψωσαν (όπως λέμε) μία εξέρεση (exception.)

Τώρα όπως βλέπεις και στον κώδικα κάνω τα εξής:

Πρώτα βλέπω εάν σην readable υπάρχει ο server. Eαν υπάρχει τότε αυτο συμένει ότι ένας client προσπαθεί να συνδεθεί στον server, άρα μπορώ να καλέσω την accept() χωρίς να κολλήσει το πρόγραμμα μου αφού ξέρω ότι ήδη ένας client προσπαθεί να συνδεθεί. Στην συνέχεια προσθέτο τον client στην λίστα sockets έτσι ώστε να μην τον χάσω και βέβαια η select να τον λάβει υπόψην της όταν την ξανά καλέσω στο επόμενο loop.

Εάν τώρα δεν υπάρχει ο server στην readable αλλά η readable έχει μέσα στοιχεία (αυτό το ελέγχο με το len(readable)>0 δηλαδή εάν το μέγεθος της είναι μεγαλύτερο του 0) τότε το πρώτο στοιχειο της θα είναι σίγουρα ο client ο οποίος έστειλε πρώτος μήνυμα. Άρα μπορώ να λάβω το μήνυμα με την recv() χωρίς καμία τύψη. Μόλις λάβω το μήνυμα τσεκάρω len(data) == 0. Όταν ένα socket λαμβάνει
0 bytes αυτό συμαίνει ότι έχει κλείση. Όταν συμβαίνει αυτό πρέπει να αφαιρέσω από την λίστα sockets αυτό το κλειστώ socket.

Εάν δεν είναι len(data) == 0 τότε μπορώ να κάνω ότι θέλω με την πληροφορία που έλαβα από τον
client. Εδώ πρώτα ελέγχω να δω εάν με έστειλε κάποια εντολή (command). Εάν η εντολή είναι /close τότε τερματίζω τον server. Διαφορετικά θεωρώ ότι η πληροφορία είναι απλός ένα μήνυμα και άρα την στέλνω σε όλλα τα sockets εκτός του server και του socket από τον οποίο πήρα το μήνυμα.

Ελπίζω να σου έδωσα να καταλάβεις πως δουλεύει και πόσο χρήσιμη είναι η select.


Τώρα χρησιμοποιόντας πάλι την select μπορείς να γράψεις τον κώδικα για τον client. Δοκιμασέ το και πες μου εάν κολλήσεις κάπου.

Σημείωση:

Να ξέρεις ότι η send() και recv() στέλνουν bytes. Άρα εάν εσύ θέλεις να στήλεις κάποια συμβολοσειρά θα πρέπει να την μετατρέπεις σε bytes και αντίστροφα.

Η μέθοδος str.encode(message) παίρνει ως όρισμα ένα string και σου επιστρέφει τα bytes.

Ενώ η bytes.decode(data) παίρνει ως όρισμα bytes και τα μετατρέπει σε string.

Άρα για να στείλεις μήνυμα:
server.send( str.encode("Για σου φίλε τη κάνεις;") )
ενώ για να λάβεις
message = bytes.decode(  client.recv(1024)  )
Τελευταία διόρθωση: 7 Χρόνια 10 Μήνες πριν από babaliaris1.
Πρέπει να είστε εγγεγραμμένο μέλος του Φόρουμ για να κάνετε μια δημοσίευση.

Sockets,Client,Server (python 2.17.12) 7 Χρόνια 10 Μήνες πριν #3973

  • Psileas25
  • Το Άβαταρ του/της Psileas25
  • Αποσυνδεμένος
  • p_____
  • Δημοσιεύσεις: 6
Με βοηθησες παρα πολυ και σε ευχαριστω.

Τωρα οσον αφορα στους καθηγητες ειλικρινα δεν ξερω τι προσπαθουν να κανουν.Δικτυα ειναι το μαθημα και ξαφνικα μας πεταξαν μεσα σε αυτα και πελαγωσαμε.Προσπαθουμε βεβαια να βγαλουμε μια ακρη. :) :) :) :) :) :)
Πρέπει να είστε εγγεγραμμένο μέλος του Φόρουμ για να κάνετε μια δημοσίευση.

Sockets,Client,Server (python 2.17.12) 7 Χρόνια 10 Μήνες πριν #3977

  • babaliaris1
  • Το Άβαταρ του/της babaliaris1
  • Αποσυνδεμένος
  • python
  • Δημοσιεύσεις: 445
  • Ληφθείσες Ευχαριστίες 75
Psileas25 έγραψε:
Με βοηθησες παρα πολυ και σε ευχαριστω.

Τωρα οσον αφορα στους καθηγητες ειλικρινα δεν ξερω τι προσπαθουν να κανουν.Δικτυα ειναι το μαθημα και ξαφνικα μας πεταξαν μεσα σε αυτα και πελαγωσαμε.Προσπαθουμε βεβαια να βγαλουμε μια ακρη. :) :) :) :) :) :)

Καλή συνέχεια!
Πρέπει να είστε εγγεγραμμένο μέλος του Φόρουμ για να κάνετε μια δημοσίευση.
Συντονιστές: pmav99
Χρόνος δημιουργίας σελίδας: 0.311 δευτερόλεπτα

Μοιράσου το!

Powered by CoalaWeb

Λίστα Ταχυδρομείου