Προς το περιεχόμενο

Προτεινόμενες αναρτήσεις

Δημοσ.

Επειδη μαρεσεις θα σου γραψω εναν σερβερ. Εσυ θα γραψεις μετα τον client, και μετα τον server.

 

Βημα 1ο: Φτιαχτικε το github https://github.com/AnonymoPapaki/SimpleChatServer ωρα 12:43

Βημα 2ο: Αρχικο σχημα https://github.com/AnonymoPapaki/SimpleChatServer/commit/d777a77cd21c25e4df13a7f1f13504068123ff74 ωρα 1:38

Κι εσύ μ'αρέσεις, μόλις όμως βγήκα από μία σχέση και δεν είμαι έτοιμος για κάτι τόσο σοβαρό .

Έχω έτοιμο τον νέο server σε python. Θα τον ανεβάσω κάποια στιγμή.

Δημοσ.

done

 

εδω ειναι το exe SimpleChatServer.zip

 

Ο σερβερ δουλευει με TCP και τα connections διαρκουν οσο η καθε socket ειναι connected, επισης ειναι full dublex και ασυγχρονο.

 

Το προτοκολλο ειναι κατι σα εντολες. Δηλαδη..

 

Ο client εφοσον εχει γινει συνδεση σε socket level. Θα πρεπει να στειλει 

setName name$

οπου στο name βαζεις το ονομα που θες να εμφανιζεται.

 

για να στειλει ενα μηνυμα σε ολους

send all$message

για να στειλει σε ενα ατομο

send name$message

Παραλληλα ο client θα πρεπει να περιμενει ενα απο αυτα τα μηνυματα

list$
name1
name2
nameN

Οπου μας λεει ποιοι ειναι συνδεδεμενοι.

msg all
sender name$
message

Οπου μας λεει οτι ηρθε ενα μηνυμα και προοριζεται για ολους.

το name εχει το ονομα του αποστολεα

το message το μηνυμα

msg pm
sender name$
message

Το ιδιο με το πανω, μου που προοριζεται για σενα μονο.

 

αυτα

 

ΥΓ ξεχασα, εχω 9090 port

Δημοσ.

Ευχαριστώ, αυτά που λες με βοηθάνε για το πώς να προχωρήσω. Στην υλοποίησή τους όμως στη γλώσσα python, έχω πρόβληματα. Τώρα προσπαθώ να βρω πως θα απελευθερωνω τα socket με το κλείσιμο κάθε client.

Στο βίντεο είδα ότι μπορείς να γράψεις εκεί που εμφανίζονται τα μυνήματα. Εγώ το έλυσα κάνοντας το παράθυρο disabled. και το κάνω normal πριν κάθε εγγραφή και μετά πάλι disabled. Δεν ξέρω το αντίστοιχο της c++. Αν δεις το script μου είναι 3 γραμμές κώδικα στον client.

Δημοσ. (επεξεργασμένο)

Αυτή είναι λοιπόν η πολυαναμένομενη version1.1

Το μόνο που κάνει είναι ότι πέρνει το μύνημα κάθε client και το στέλνει σε όλους.

# Ver. 1.1
# Το παρόν πρόγραμμα είναι ένας απλός server 
# Εισάγω τις απαραίτητες βιβλιοθήκες
from socket import *
import threading as t

# Αυτή η συνάρτηση λαμβάνει και στέλνει δεδομένα 
# Τρέχει ξεχωριστά ως thread για κάθε connection (con)
def receive_send(con):
# Το πρώτο μύνημα που στέλνει μετά από τη σύνδεση
    connection_message='Καλωσήρθατε '+ str(len(connections))+' συνδεδεμένοι χρήστες\n' 
    con.send(connection_message.encode('utf-8'))# Το κωδικοποιώ και το στέλνω    
    while True: #βρόγχος που τρέχει πάντα 
        data_recv=con.recv(1024) #ότι δεδομένα λαμβάνει
        for i in connections: #τα στέλνει σε όλους 
            i.send(data_recv)        
    con.close()		
 
def connector(): #Η συνάρτηση που κάνει τις συνδέσεις
    while True: # Τρέχει συνέχεια
        con, address = s.accept() #κάνει accept και επιστρέφει το con, address
        connections.append(con) # Βάζει το κάθε νέο con στον πίνακα των συνδέσεων
		#δημιουργώ thread για τη receive_send 
        a=t.Thread(target=receive_send, args=(con,))  
        a.start()# Το ξεκινάω 

connections=[] # πίνακας συνδέσεων

host='' # κενό 
port=8000 #port 0 έως 65535 Οι θύρες 0-1023 πρέπει να αποφεύγονται γιατί είναι δεσμευμένες 
# για διάφορες λειτουργίες, περισσότερα εδώ https://en.wikipedia.org/wiki/List_of_TCP_and_UDP_port_numbers
s=socket() #normal socket, έχω παραλείψει τις παραμέτρους
s.bind((host, port)) # Το κάνω bind με το tuple(host, port)
s.listen(5)
# Τρέχω τη συνάρτηση connector
connector()

Τον client τον έγραψα σε γραφικό περιβάλλον

#Το παρόν πρόγραμμα είναι ένας client σε γραφικό περιβάλλον
#που καλεί ένα σερβερ με την ip ή hostname, port και username

#Εισάγω τις βιβλιοθήκες
from socket import *
from tkinter import *
from tkinter import ttk
import time
import threading as t

s=socket()#Δημιουργώ ένα socket

#Δίνω αρχικές τιμές στις μεταβλητές μου 
host=''
port=0
name=''

#Η συνάρτηση που στέλνει τα δεδομένα
def send_message(event): 
  str_message= name + ': ' + entry_client.get() + '\n' #Το μύνημα το οποίο περιέχει
  #το όνομα και αυτά που γράψαμε στο entry
  data_send=str_message.encode() #κάνουμε encode
  s.send(data_send) #το στέλνουμε
  entry_client.delete(0,END) #μηδενίζω τα στοιχεία του entry

def receive(): #Η συνάρτηση που λαμβάνει και τυπώνει τα μυνήματα στο text
  while True:  #Τρέχει συνέχεια
    data_recv=s.recv(1024) #λαμβάνει
    data_str_recv=data_recv.decode('utf-8') #κάνει decode
    message_place.config(state=NORMAL) #αλλάζει το status του text για να μπορώ να γράψω
    ora=time.strftime('%H:%M:%S ',time.localtime()) #παίρνω την τρέχουσα ώρα
    if data_str_recv.startswith(name): #Αν το μύνημα αρχίζει με το όνομά μου που σημαίνει ότι είναι δικό μου 
      message_place.insert(END,ora+''+data_str_recv,'me') #το τυπώνω με άλλο χρώμα 
    else:
      message_place.insert(END,ora+data_str_recv) #αλλίως το τυπώνω μαύρο	
    message_place.config(state=DISABLED) #ξανα αλλάζω το state του text

# Η συνάρτηση που κάνει τη σύνδεση με το server
def connect():
  global name,host,port,s #Δίνω νέες τιμές στις μεταβλητές μου
  name=entry_name.get()
  win.title(name)
  host=entry_ip.get()  
  server_host=host 
  port=entry_port.get()
  port=int(port) 
  s.connect((server_host, port)) #κάνω τη σύνδεση με το tuple (server_host, port)
  a=t.Thread(target=receive) #δημιουργώ thread για τη receive 
  a.start()  #και το ξεκινάω

# Απο εδώ και κάτω το γραφικό περιβάλον
win=Tk()
win.title('CLIENT')
frame1=Frame(win)
frame1.pack(expand=True, fill='both', side='top')
  
# Το Text όπου γράφονται πληροφορίες σύνδεσεις και όλα τα μυνήματα 
message_place=Text(frame1,  wrap=WORD)
message_place.grid(row=0, column=0, columnspan=7,sticky='W', padx=5, pady=5)
message_place.config(state=DISABLED) # Το απενεργοποιώ για να μην μπορώ να γράψω
message_place.tag_configure('me', foreground='blue') #Κάνω tag με άλλο χρώμα για να το 
#χρησιμοποιήσω για τα μυνήματά μου

frame2=Frame(win)
frame2.pack(expand=True, fill='both')

# label και entry για τα μυνήματα που γράφω.
label_client=Label(frame2, text='Message: ')
label_client.grid(row=0,column=0,sticky='W',padx=5,pady=5)
  
entry_client=Entry(frame2, width=60)
entry_client.grid(row=0,column=1, sticky='W',padx=5,pady=5)
entry_client.bind("<Return>", send_message) #Με enter καλώ τη συνάρτηση που στέλνει το μύνημα
  
frame3=Frame(win)
frame3.pack(expand=True, fill='both')

# label και entry για την IP.  
label_ip=Label(frame3, text='IP: ', bg='white')
label_ip.pack(side='left',padx=5,pady=5)

entry_ip=Entry(frame3,width=20)
entry_ip.pack(side='left',padx=5,pady=5)

# label και entry για τo port.
label_port=Label(frame3, text='Port: ', bg='white')
label_port.pack(side='left',padx=5,pady=5)

entry_port=Entry(frame3)
entry_port.pack(side='left',padx=5,pady=5)

# label και entry για τo name
label_name=Label(frame3, text='Your name: ', bg='white')
label_name.pack(side='left',padx=5,pady=5)  
  
entry_name=Entry(frame3)
entry_name.pack(side='left',padx=5,pady=5)


rec_button=ttk.Button(frame3, text='connect', command=connect) # Το κουμπί για τη σύνδεση
rec_button.pack(side='left', padx=5, pady=5 )
  
win.mainloop()

και το αποτέλεσμα που πήρα μόνος μου online όπως foto

post-372633-0-75037000-1461673133_thumb.jpg

Επεξ/σία από k33theod
Δημοσ.

Tα ports 0-1024 θέλουν sudo

Ναι, και άλλα comments είναι λάθος όπως αυτά στις γραμμές 44 και 96 στον client. Θα τα διορθώσω

Δημοσ.

Άσχετο, αλλά αυτό το "Το παρώον" διόρθωσε το γιατί βγάζει μάτια!

Γιατί το τρέχουσα όρα τι κάνει, αφού και γώ που το είδα στραβώθηκα

Δυστηχώς το notepad++ που χρησιμοποιώ δεν κάνει ορθογραφικό έλεγχο και δεν περνάω μετά το κείμενο από κάποιο έλεγχο με ελληνικό ορθογράφο οπότε ξεφεύγουν αρκετά λάθη.

  • Like 1
  • 1 μήνα μετά...
Δημοσ. (επεξεργασμένο)

Αναπτύσσω και εγώ ένα chat και δυστυχώς αντιμετωπίζω ένα σοβαρό πρόβλημα. Έχω αφιερώσει > 7-8 ώρες και ακόμη δεν μπορώ να βγάλω άκρη. Δυστυχώς κώδικα δεν μπορώ να παραθέσω αυτή τη στιγμή (ίσως αφού δώσω το μάθημα  :lol: ).

 

Θα αναφέρω τι γίνεται και αν έχει κάποιος άποψη έστω στο περίπου, θα με έσωζε. Πραγματικά δεν πάει άλλο.

 

Λοιπόν:

 

Ανοίγουμε σέρβερ, συνδέουμε τον πρώτο client (ας τον πούμε client_1 για ευκολία). Όλα καλά. Στέλνει μηνύματα χωρίς πρόβλημα (τα βλέπει μόνο αυτός - δεν υπάρχει άλλος client στον chat server).

Μπαίνει ο δεύτερος (client_2). Μια χαρά κιαυτός. Μπορεί να στείλει όσα θέλει. Όταν όμως ο client_1 στείλει ξανά, δεν μπορεί να στείλει παραπάνω μηνύματα από 1!

 

Αφού, δηλαδή, συνδεθεί ο client_2, ο client_1 μπορεί να στείλει μόλις ένα μήνυμα (άλλες φορές και κανένα.... Δεν έχω προσδιορίσει ακριβώς πώς και πότε συμβαίνει αυτό). Το socket του client_1 όμως, αφού στείλει το μοναδικό μήνυμα που μπορεί μετά τη σύνδεση του client_2, δεν αποσυνδέεται. Τα μηνύματα του client_2 τα λαμβάνει όλα κανονικά.

 

Γενικά, παρατήρησα ότι: ο client_1 στέλνει τα μηνύματα στον server, αλλά αυτός δεν τα βλέπει. Δεν "ακούει" ότι του στέλνουν κάτι.

 

Αν κατάλαβε κανείς τίποτα από τα παραπάνω και έχει καμία ιδέα απλώς, ας την αναφέρει. Ξέρω είναι ανόητο χωρίς ούτε δείγμα κώδικα, αλλά ακόμη και μία ιδέα ίσως φανεί χρήσιμη.

 

Edit: Όλα, μέχρι χθες το βράδυ που το άφησα, λειτουργούσαν μια χαρά. Σήμερα πρόσθεσα επιπλέον λειτουργίες και κάπου χάλασε η δουλειά. Φυσικά μπακ-απ αρχείο δεν υπάρχει (υπάρχουν, αλλά είναι αρκετά παλιά...), οπότε ψάχνω χωρίς κανένα όφελος μέχρι στιγμής. Και πάλι βέβαια, τα features που πρόσθεσα σήμερα δεν έχουν σχέση ρε γαμώτη με το συγκεκριμένο πρόβλημα.

 

Edit 2: Όσο έπαιζα με lists, όλα θυμάμαι πως δούλευαν ρολόι. Το πρόβλημα ξεκίνησε όταν αντικατέστησα τις lists με dictionaries.

 

Edit 3: Τσέκαρα και με wireshark. Τα πακέτα φτάνουν μέχρι τον σερβερ. Αυτός όμως δεν νιώθει.

Επεξ/σία από giorgos147
Δημοσ.

Αυτό ακούγεται σα να έχεις κάποιο bug στη λογική που διαβάζει ο server από τα sockets των clients.

 

Μπορεί για παράδειγμα να έχεις μια μεταβλητή που κάπως αποθηκεύεται το socket που άνοιξε τελευταίο και να χρησιμοποιείς αυτήν μόνο κανονικά (οπότε ο τελευταίος client παίζει κανονικά ενώ οι προηγούμενοι όχι, ο server δεν ασχολείται μαζί τους). Ή μπορεί να βάζεις τα socket σε ένα πίνακα και να μην κάνεις select/read σε όλα παρά μόνο στο τελευταίο, ή κάτι along these lines.

  • Like 1
Δημοσ.

Αυτό ακούγεται σα να έχεις κάποιο bug στη λογική που διαβάζει ο server από τα sockets των clients.

 

Μπορεί για παράδειγμα να έχεις μια μεταβλητή που κάπως αποθηκεύεται το socket που άνοιξε τελευταίο και να χρησιμοποιείς αυτήν μόνο κανονικά (οπότε ο τελευταίος client παίζει κανονικά ενώ οι προηγούμενοι όχι, ο server δεν ασχολείται μαζί τους). Ή μπορεί να βάζεις τα socket σε ένα πίνακα και να μην κάνεις select/read σε όλα παρά μόνο στο τελευταίο, ή κάτι along these lines.

 

Αυτό ήταν.

 

Για να εξηγήσω: Στο σημείο που έστελνα σε όλους, είχα δηλώσει να διαβάζει από το dictionary την ίδια μεταβλητή με αυτή που τερματίζω το σοκετ, οπότε και μάλλον, όπως είπες, κράταγε τον τελευταίο.

 

Τώρα βέβαια πώς μπορούσε να στείλει ακόμη ένα μήνυμα, είναι άγνωστο. 

 

Χίλια ευχαριστώ ρε συ.

  • Like 1

Δημιουργήστε ένα λογαριασμό ή συνδεθείτε για να σχολιάσετε

Πρέπει να είστε μέλος για να αφήσετε σχόλιο

Δημιουργία λογαριασμού

Εγγραφείτε με νέο λογαριασμό στην κοινότητα μας. Είναι πανεύκολο!

Δημιουργία νέου λογαριασμού

Σύνδεση

Έχετε ήδη λογαριασμό; Συνδεθείτε εδώ.

Συνδεθείτε τώρα
  • Δημιουργία νέου...