0

I have a server and a client and they can connect to each other and I can send from the client to the server but not vice versa. The program fails when i'm trying to send back data to the client.

client.py

from tkinter import *
import socket
import threading

tLock = threading.Lock()
shutdown = False

host = '::1';
port = 5000;

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

class Application(Frame):
def __init__(self, master=None):
    #Create master frame
    Frame.__init__(self,master)
    self.grid()
    self.master.title("Test 1")
    self.conn=False #State of connection to server

    #Configure main frame
    for r in range (4):
        self.master.rowconfigure(r, weight=1)
    for c in range (2):
        self.master.columnconfigure(c)

    #Create sub frames
    TopFrame=Frame(master)
    TopFrame.grid(row=0, column=0, rowspan=3)
    BottomFrame=Frame(master, bg="green")
    BottomFrame.grid(row=4, column=0, rowspan=3)
    SideFrame=Frame(master, bg="red")
    SideFrame.grid(column=1, row=0, rowspan=4)

    #Create Chat log
    self.chatlog=Text(TopFrame)
    self.chatlog.pack(padx=5, pady=5)


    #messenger and send button
    self.e1=Entry(BottomFrame, width=92)
    self.e1.pack(side=LEFT, pady=5, padx=5)
    sendButton=Button(BottomFrame, text="Send", command=self.sendmessage, height = 1, width = 10)
    sendButton.pack(side=LEFT)

    #Create connect disconnect buttons
    b1=Button(SideFrame, text="Connect", command=self.connect)
    b1.grid(row=0, column=0, padx=5, pady=5)
    b2=Button(SideFrame, text="Disconnect", command=self.disconnect)
    b2.grid(row=1, column=0, padx=5, pady=5)


def connect(self): #Connect to server
    self.chatlog['state'] = NORMAL
    self.chatlog.insert(END, ("===ATTEMPTING TO CONNECT TO SERVER\n"))
    self.chatlog['state'] = DISABLED
    self.chatlog.yview(END)

    s.connect((host,port))
    self.chatlog['state'] = NORMAL
    self.chatlog.insert(END, (s))
    self.chatlog['state'] = DISABLED
    self.chatlog.yview(END)

    self.chatlog['state'] = NORMAL
    self.chatlog.insert(END, ("\n\n PLEASE ENTER A USER NAME AND SEND"))
    self.chatlog['state'] = DISABLED
    self.chatlog.yview(END)
    self.conn=True
    print("Connected") #Connection successful

    # M- Adding threading for receiving messages
    rT = threading.Thread(target=self.receving, args=("RecvThread",s))
    rT.start()


    # When attempting to connect a second time, produces OS error: an operation was attempted on something that is not a socket

def disconnect(self):
    if self.conn: #Tests to see if client is connected
        s.close()
        self.chatlog['state'] = NORMAL
        self.chatlog.insert(END, ("===DISCONNECTED FROM SERVER.\n"))
        self.chatlog['state'] = DISABLED
        self.chatlog.yview(END)
        self.conn=False
    else: #Prevents attempting to disconnect when already disconnected
        self.chatlog['state'] = NORMAL
        self.chatlog.insert(END, ("===YOU AREN'T CURRENTLY CONNECTED.\n"))
        self.chatlog['state'] = DISABLED
        self.chatlog.yview(END)


def sendmessage(self):
    if self.conn: #Prevents sending if not connected
        self.msg=self.e1.get()
        if self.msg == "": #Empty message catcher
            self.chatlog['state'] = NORMAL
            self.chatlog.insert(END, ("===YOU CANNOT SEND AN EMPTY MESSAGE.\n" ))
            self.chatlog['state'] = DISABLED
            self.chatlog.yview(END)
        else:
            self.send_data(self.msg) #Sends message to the server
            self.e1.delete(0, END)
    else:
            self.chatlog['state'] = NORMAL
            self.chatlog.insert(END, ("===YOU ARE NOT CONNECTED TO A SERVER. YOU CANNOT SEND A MESSAGE.\n" ))
            self.chatlog['state'] = DISABLED
            self.chatlog.yview(END)

# M- Method to handle receiving from the server
# adds the data to the chat log.
def receving(self, name, sock):
    while not shutdown:
        try:
            tLock.acquire()
            while True:
                data, addr = sock.recvfrom(1024)
                self.chatlog['state'] = NORMAL
                self.chatlog.insert(END, (data + '\n'))
                self.chatlog['state'] = DISABLED
                self.chatlog.yview(END)
        except:
            pass
        finally:
            tLock.release()

def send_data(self, message):
    try:
        s.send(message.encode('UTF-8'))
    except:
            self.chatlog['state'] = NORMAL
            self.chatlog.insert(END, ("===THE PREVIOUS MESSAGE DIDN'T SEND. THIS IS POSSIBLY DUE TO A SERVER ERROR.\n"))
            self.chatlog['state'] = DISABLED
            self.chatlog.yview(END)


root = Tk()
app = Application(root)
app.mainloop()

Server.py

import socket
import threading
import sys

hosts=["::1"]
port=5000

#dictionay to hold the socket as the key and the user name as the value
dic = {}

class Server:
def __init__ (self,hosts,port):
    self.host=hosts
    self.port=port
    self.socketserver=socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
    self.socketserver.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    print("Socket has been created successfully")
    for i in hosts:
        try:
            host=i
            self.socketserver.bind((host,port))
            print("Connection succeded to address",i)
            print ("The server is now binded to the following IP address",host,"Port",port)
            break
        except socket.error:
            print("Connection failed to address",i)
        else: 
            sys.exit()

def Accept_connections(self):
    while True:
        self.socketserver.listen(10)
        print("Socket is now awaiting connections")
        server, clientaddress = self.socketserver.accept()
        print("Connection enstablished with: " +str(clientaddress))   
        threading.Thread(target = self.message,args = (server,clientaddress),).start()

def message(self,server,clientaddress):
    while True:
        try:
            data= server.recv(1024)
            print("data ", data)
            #check to see if it is a new socket that is not in the stored
            #socket dictionary
            if server not in dic.keys():
                print("if statement")
                #if it is a new socket
                #add the socket and the user name
                dic[server] = data
                for key in dic:
                    #send the joined message to the users
                    print("failing")
                    key.send("\n\n" + data + " has joined the chat")
            else:
                #alias is a variable used to store the sockets username
                alias = dic[server]
                for key in dic:
                    #send the message to the sockets in the dictionary
                    key.send(alias + ": " +data)

        except:
            server.close()
            #edit this bit !
            print("Data transfer failed")
            return False

Server(hosts,port).Accept_connections()

The program fails at:

    key.send("\n\n" + data + " has joined the chat")

When a client connects they enter a user name to be known as. This stores it with a socket in a dictionary. The error occurs when looping round the sockets to inform the other clients they have joined. Any help would be brilliant. This was working on python27 but has now stopped when i updated to python34.

7
  • Does the program output a stacktrace when the error occurs? If so please provide it. Commented Mar 29, 2016 at 18:33
  • Hi, The only output is "data transfer failed" Commented Mar 29, 2016 at 18:37
  • Change the except: line in server.py to except Exception as ex: and add a line immediately after : print(ex). What is printed? (Your except is hiding the details of the failure). Commented Mar 29, 2016 at 18:40
  • Ah so it is. The error printed is "Can't convert 'bytes' object to str implicitly" Commented Mar 29, 2016 at 18:43
  • 2
    You probably need to decode the data parameter in key.send("\n\n" + data + " has joined the chat"), so key.send("\n\n" + data.decode('utf-8') + " has joined the chat"). The lesson here is not to use 'bare' excepts: be explicit about the exceptions that you are catching, and if you must have a catchall like except Exception then log the errors that it swallows. Commented Mar 29, 2016 at 18:48

1 Answer 1

1

Managed to find the fix. When I upgraded to 3 the sending stopped working as it was trying to send strings. Python 3 requires bytes to be sent.

key.send(data + b' joined')

Was the solution

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.