I have made a chat server client but when I run it I get this error:
Traceback (most recent call last):
File "C:/Users/Public/Documents/Programming/Chat Client/Chat Client.py", line 21, in
<module>
s = socket.socket((socket.AF_INET, socket.SOCK_STREAM))
AttributeError: type object 'socket' has no attribute 'socket'
I don't see the problem so can anyone help me, here is my code:
# Import Modules
from tkinter import *
from socket import *
from threading import *
# Window Setup
root = Tk()
root.title('Chat Client')
root.state('zoomed')
# Chat Variables
global s
s = socket.socket((socket.AF_INET, socket.SOCK_STREAM))
s.connect((TARGET, DEFAULT_PORT))
enter = StringVar()
TARGET = s.gethostname()
DEFAULT_PORT = 45000
# Chat Message Box Setup
chat = Text(root, height=31, state=DISABLED)
entry = Entry(root, fg='blue', textvariable=enter, width=200)
scroll = Scrollbar(root)
chat['yscrollcommand'] = scroll.set
scroll['command'] = chat.yview
scroll.pack(side=RIGHT, fill=Y)
chat.pack(side=TOP, fill=X)
entry.pack(side=BOTTOM)
# Send Command
def send(event):
msg = enter.get()
chat['state'] = NORMAL
chat['fg'] = 'blue'
chat.insert(END, ('You: ' + msg + '\n'))
while 1:
s.sendall(msg)
chat['state'] = DISABLED
chat['fg'] = 'black'
enter.set('')
s.close()
entry.bind('<Return>', send)
def recieve():
s.bind((TARGET, DEFAULT_PORT))
s.listen(True)
conn, addr = s.accept()
while True:
data = conn.recv(1024)
chat['state'] = NORMAL
chat['fg'] = 'red'
chat.insert(END, ('Stranger: ' + data + '\n'))
thread.start(recieve, ())
thread.start(send, ())
root.mainloop()
I am not sure what is wrong with my code so could anyone please help me?
Thanks In Advance!
from socket import *
You've imported the entire socket module. There is no socket.socket. You've imported the socket object directly into the current namespace.
To access it, simple do
s = socket((socket.AF_INET, socket.SOCK_STREAM))
If you had done
import socket
Then you could access the socket object via the module namespace.
Related
I have a customtkinter (CTk) button widget that, when pressed, sends an encoded message to a client depending on the button's "text" value; in this case, if the button's text is "Off", it sends the message "On" and vice versa to the client.
import tkinter as tk
import traceback
import customtkinter as cust
import socket
from threading import Thread
from tkinter import messagebox
class GUI2(cust.CTk): #second window; not the root
def __init__(self):
super().__init__()
self.PORT = 5000
self.SERVER = socket.gethostbyname(socket.gethostname())
self.ADDRESS = (self.SERVER, self.PORT)
self.FORMAT = "utf-8"
self.clients = [] #list to store all client connections
self.server = socket.socket(socket.AF_INET,
socket.SOCK_STREAM)
self.server.bind(self.ADDRESS)
self.master2 = cust.CTkToplevel()
self.ecdpower = cust.CTkButton(self.master2, text = "Off", fg_color = "Black", text_color = "White", hover_color = "Silver", command = lambda: Thread(target = self.startstream).start())
self.ecdpower.grid(row = 0, column = 0) #button to send message to client connections
self.thread = Thread(target = self.startChat)
self.thread.start() #starts function to accept client connections
def startChat(self): #function to accept client connections
self.server.listen(30)
try:
while True:
self.conn, self.addr = self.server.accept()
self.clients.append(self.conn) #stores all client connections
except:
pass
def startstream(self):
try:
if not self.clients: #checks if list is empty
messagebox.showerror("No Connections!", "No clients connected to host!")
else:
for x in self.clients:
if self.ecdpower["text"] == "Off": #ecdpower button widget acts like a "power button"
self.ecdpower.configure(text = "On", fg_color = "Green")
x.send(("On").encode(self.FORMAT))
else:
self.ecdpower.configure(text = "Off", fg_color = "Red")
x.send(("Off").encode(self.FORMAT))
except:
print (traceback.format_exc())
Error is as follows:
Traceback (most recent call last):
File "f:\project\mainmenu.py", line 390, in startstream
File "F:\Program Files (x86)\Python\lib\tkinter\__init__.py", line 1681, in cget
return self.tk.call(self._w, 'cget', '-' + key)
_tkinter.TclError: unknown option "-text"
I have also tried if self.ecdpower.cget("text") == "Off: and tried other values like fg_color; both result in the same error. When I removed the if condition, the message sending works correctly so the only problem is how to verify the button "text" value.
Any help to fix this or possible other alternatives is greatly appreciated.
Per #jasonharper's comment above, CTkButton is
not actually a Tkinter Button at all (it's made from a Frame containing a Canvas and a Label), so the normal Tkinter attribute-getting functions don't apply.
Instead of using self.ecdpower["text"] or self.ecdpower.cget("text"): I should use
self.ecdpower.text
to get the CTKbutton's text value.
The same can be applied with fg_color; use self.ecdpower.fg_color to get the value.
I developed a simple chat app that allows users to connect to a server and chat. This is the code for the server.
import os
from datetime import datetime
def log_file_name():
n = str(datetime.now())
m = n.replace(':','_').replace(' ','---')
l = m.split('.')[0]
l = f'{l}.txt'
return l
HOST = '127.0.0.1'
PORT = 10001
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
#print(type(server_socket))
server.bind((HOST, PORT))
server.listen()
print('server_initiated...')
logfile = os.path.join('logs', log_file_name())
with open(logfile, 'w') as fh:
fh.write(f'{str(datetime.now())} log file initiated!\n\n')
clients = []
nicknames = []
#broadcast
def broadcast(message):
#print(clients)
for client in clients:
client.send(message)
def handle(client):
while True:
try:
message = client.recv(1024)
#print(f'{nicknames[clients.index(client)]} says {message}')
broadcast(message)
with open(logfile, 'a') as fh:
fh.write(f"{nicknames[clients.index(client)]} says {message.decode('utf-8')}\n")
except Exception:
index = clients.index(client)
clients.remove(client)
client.close()
left_nick = nicknames[index]
leaving_notes = f"{left_nick} just left the chat!! -- time {str(datetime.now()).split(' ')[1].split('.')[0]}"
broadcast(leaving_notes.encode('utf-8'))
with open(logfile,'a') as fh:
fh.write(f'{leaving_notes}\n')
nicknames.remove(left_nick)
break
#recieve message
def recieve():
while True:
client, address = server.accept()
#print(dir(client))
#print(client._io_refs)
#print(f'Connected with {str(address)}!!')
with open(logfile, 'a') as fh:
fh.write(f'Connected with {str(address)}!!\n')
client.send('Nickname'.encode('utf-8'))
nickname = client.recv(512).decode('utf-8')
nicknames.append(nickname)
clients.append(client)
#print(f'from 1st step clients are {clients}')
#print(f'Nickname of the client is {nickname}')
with open(logfile, 'a') as fh:
fh.write(f'Nickname of the client is {nickname}\n')
broadcast(f'Notice from server!! {nickname} just connected to the server!\n'.encode('utf-8'))
client.send(f'Connected to the server as {nickname}\n'.encode('utf-8'))
thread = threading.Thread(target=handle, args=(client,))
thread.start()
recieve()
Then I exposed that port to public using ngrok (ngrok http 10001), and it generated a public ip for me.
I coded a simple client gui using tkinter and I tried to connect the socket in to to above ngrok server I got. But I cannot broadcast messages. When I try to broadcast a message the GUI automatically closes. The reason is it meets a ConnectionAbortError.
Code for client-
import threading
import tkinter
import socket
import tkinter.simpledialog
import tkinter.scrolledtext
import os
#HOST = socket.gethostbyname(socket.gethostname())
#PORT = 10001
HOST = '3a7d-2402-4000-1245-cd8a-5d64-9c3f-25a3-79a4.in.ngrok.io'
PORT = 443 #or 80
class Client:
def __init__(self,host,port):
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.sock.connect((host, port))
msg = tkinter.Tk()
msg.withdraw()
self.nickname = tkinter.simpledialog.askstring('Nickname', 'Please enter a nickname', parent=msg)
self.gui_done = False
self.running = True
gui_t=threading.Thread(target=self.gui_loop)
recieve_t=threading.Thread(target=self.recieve)
gui_t.start()
recieve_t.start()
def gui_loop(self):
self.win = tkinter.Tk()
self.win.configure(bg='lightgray')
self.chat_label = tkinter.Label(self.win, text='Chat:', bg='lightgray')
self.chat_label.config(font=('Arial',12))
self.chat_label.pack(padx=20, pady=5)
self.text_area = tkinter.scrolledtext.ScrolledText(self.win)
self.text_area.pack(padx=20,pady=5)
#self.text_area.config(state='disabled')
self.msg_label = tkinter.Label(self.win, text='Message:', bg='lightgray')
self.msg_label.config(font=('Arial', 12))
self.msg_label.pack(padx=20, pady=5)
self.input_area = tkinter.Text(self.win, height=3)
self.input_area.pack(padx=20, pady=5)
self.send_button = tkinter.Button(self.win, text='Send', command=self.write)
self.send_button.config(font=('Arial', 12))
self.send_button.pack(padx=20, pady=5)
self.gui_done = True
self.win.protocol('WM_DELETE_WINDOW', self.stop)
self.win.mainloop()
def write(self):
message = f"{self.nickname}: {self.input_area.get('1.0', 'end')}"
#print(message)
self.sock.send(message.encode('utf-8'))
self.input_area.delete('1.0','end')
def recieve(self):
while self.running:
try:
message = self.sock.recv(1024).decode('utf-8')
print(message)
if message == 'Nickname':
self.sock.send(self.nickname.encode('utf-8'))
else:
if self.gui_done:
#print('I hit here often')
self.text_area.config(state='normal')
self.text_area.insert('end', message)
self.text_area.yview('end')
#self.text_area.config(status='disabled') #never use this inside a loop, disabled blocks the code....
except ConnectionAbortedError: #when closed the window I come here..
print('Am i here?')
#break
os._exit(0)
#break
except:
break
print('Error')
self.sock.close()
break
def stop(self):
self.running = False
self.win.destroy()
self.sock.close()
exit(0)
client = Client(HOST, PORT)
If you run this please make sure to create a directory called logs to save the log of communication. Or else it will give an error(You can try it on localhost). I think I am doing something that doesn't work here. Can you point it out to me? or can you give me an alternative way of doing it?
So, I have a server completely written in Python 2.7:
from socket import *
from select import *
HOST = "127.0.0.1"
PORT = 1993
server = socket(AF_INET, SOCK_STREAM)
server.bind((HOST, PORT))
server.listen(5)
clients = []
def getClients():
to_use = []
for client in clients:
to_use.append(client[0])
return to_use
while(True):
read, write, error = select([server],[],[],0)
if(len(read)):
client, address = server.accept()
clients.append([client, address, []])
to_use = getClients()
try:
read, write,error = select(to_use,[],[],0)
if(len(read)):
for client in read:
data = client.recv(1024)
print(bytes.decode(data))
if(data == 0):
for c in clients:
if c[0] == client:
clients.remove(c)
break
else:
for c in clients:
c[2].append(data)
except:
pass
try:
to_use = getClients()
read, write, error = select([], to_use, [], 0)
if(len(write)):
for client in write:
for c in clients:
if c[0] == client:
for data in c[2]:
sent = client.send(data)
if(sent == len(data)):
c[2].remove(data)
break
except:
pass
What I need to do is get constant updates for data (messages) from the
server and print them to a text box made in Tkinter.
The receiving code:
from socket import *
from select import *
HOST = "127.0.0.1"
PORT = 1993
sock = socket(AF_INET, SOCK_STREAM)
sock.connect((HOST, PORT))
while True:
data = bytes.decode(sock.recv(1024))
print data
It doesn't have to be Tkinter, but that's what I have been trying in; as long as it uses a GUI. Don't worry about sending messages I just need to be able to receive the data and print it to the text box/area.
The basic framework is to first create all of the widgets. Next, write a function that reads the data and updates the UI. Finally, arrange to have this function called every few milliseconds.
Roughly speaking, it looks something like this:
import Tkinter as tk
...
class Example(object):
def __init__(self):
self.root = tk.Tk()
self.text = tk.Text(root)
self.text.pack(fill="both", expand=True)
...
def start(self):
self.read_periodically()
self.root.mainloop()
def read_periodically(self):
# read the data
data = bytes.decode(sock.recv(1024))
# update the UI
self.text.insert("end", data)
# cause this function to be called again in 100ms
self.after(100, self.read_periodically)
example = Example()
example.start()
If the data is not a steady stream which causes sock.recv(1024) to block, your UI will freeze while it's waiting for data. If that's the case, you can move the reading of the socket to a thread, and have the thread communicate with the GUI via a thread-safe queue.
If the data is in a steady stream, or you set up a non-blocking socket, you don't have to do any of that.
I wanted to submit a comment first, but give this a try:
You can use something other than a start button to get things going I just put it there for ease of use
from Tkinter import *
import threading
from socket import *
from select import *
master = Tk() #create the GUI window
#put the test program in a seperate thread so it doesn't lock up the GUI
def test_program_thread():
thread = threading.Thread(None, test_program, None, (), {})
thread.start()
def test_program():
HOST = "127.0.0.1"
PORT = 1993
sock = socket(AF_INET, SOCK_STREAM)
sock.connect((HOST, PORT))
while True:
data = bytes.decode(sock.recv(1024))
terminal_listbox.insert(END, str(data))
master.update() #I don't think this line is necessary, but put it here just in case
# set the gui window dimensions and the title on the GUI
master.minsize(width=450, height=450)
master.wm_title("Stack Problem")
# Start button is set to y and starts the test program when hit
start_button = Button(master, text='START', command=test_program_thread)
start_button.place(x=5, y=5)
# scroll bar for the terminal outputs
scrollbar = Scrollbar(master)
scrollbar.place(x=420, y=150)
# Terminal output. Auto scrolls to the bottom but also has the scroll bar incase you want to go back up
terminal_listbox = Listbox(master, width=65, height=13)
terminal_listbox.place(x=5, y=100)
terminal_listbox.see(END)
scrollbar.config(command=terminal_listbox.yview)
#GUI loops here
master.mainloop()
I haven't been doing almost any programming before this so I apologize in advance for the quality of my code.
The problem I'm having is that I have a GUI and I need to open a server to receive internet traffic, but if I try to open it in a new process I get an error about a name not being defined (even though it works just fine if I open the server as a regular function and not a new process). The funny thing is that the GUI still opens even though I get the error.
I'll paste the error messages after the code.
Thank you in advance.
from Tkinter import *
import socket, re
import netifaces as ni
from multiprocessing import Process, Manager
class Application(Frame):
def __init__(self, master):
""" Initialize the Frame"""
Frame.__init__(self,master)
self.grid()
self.create_widgets()
def create_widgets(self):
self.label1 = Label(text = "Target IPv6 address")
self.label1.grid(row=1, column=0)
self.entry1 = Entry(bd = 5)
self.entry1.grid(row=1, column = 1)
self.button1 = Button(text = "Start", command = self.clientstart)
self.button1.grid(row=1, column = 2)
pr1 = Process(target=self.serverstart)
self.button2 = Button(text = "Start", command = pr1.start())
self.button2.grid(row=2, column=2)
self.label2 = Label(text = "Choose interface to listen")
self.label2.grid(row=2, column=0)
self.interfaces = Menubutton(text="------", relief=RAISED)
self.interfaces.grid(row=2, column=1)
self.interfaces.menu = Menu(self.interfaces, tearoff=0)
self.interfaces["menu"] = self.interfaces.menu
self.menubox()
def menubox(self):
self.interfaces.menu.add_command(label="------", command = lambda interface="------": self.callback(interface))
for interface in ni.interfaces():
if interface.startswith('eth'):
self.interfaces.menu.add_command(label=interface, command = lambda interface=interface: self.callback(interface))
else:
pass
def callback(self, interface):
if interface.startswith('eth'):
self.interfaces["text"] = interface
else:
self.interfaces["text"] = "------"
self._netint = interface
def serverstart(self):
import tcpServer
tcpServer.start(self._netint)
def clientstart(self):
targetip = self.entry1.get()
import tcpClient
tcpClient.startclient(targetip)
root = Tk()
root.title("IPv6 traffic generator")
root.geometry("400x600")
app = Application(root)
root.mainloop()
Process Process-1:
Traceback (most recent call last):
File "/usr/lib/python2.7/multiprocessing/process.py", line 258, in _bootstrap
self.run()
File "/usr/lib/python2.7/multiprocessing/process.py", line 114, in run
self._target(*self._args, **self._kwargs)
File "gui.py", line 57, in serverstart
tcpServer.start(netint)
NameError: global name 'netint' is not defined
EDIT:
I tried the advice in the first reply, but it still gives an error
Process Process-1:
Traceback (most recent call last):
File "/usr/lib/python2.7/multiprocessing/process.py", line 258, in _bootstrap
self.run()
File "/usr/lib/python2.7/multiprocessing/process.py", line 114, in run
self._target(*self._args, **self._kwargs)
File "gui.py", line 55, in serverstart
tcpServer.start(self._netint)
AttributeError: Application instance has no attribute '_netint'
Here is the code for tcpServer.py
import socket
import netifaces as ni
def start(self, _netint):
host = ni.ifaddresses(self._netint)[ni.AF_INET6][0]['addr']
port = 5000
s = socket.socket(socket.AF_INET6)
s.bind((host, port))
s.listen(1)
c, addr = s.accept()
print "Connection from: " + str(addr)
while True:
data = c.recv(1024)
if not data:
break
print "from connected user: " + str(data)
data = str(data).upper()
print "sending: " + str(data)
c.send(data)
c.close()
if __name__ == '__main__':
start()
And here for tcpClient.py
import socket
def startclient(targetip):
host = targetip
port = 5000
s = socket.socket(socket.AF_INET6)
s.connect((host,port))
message = raw_input('Send message: ')
while message != 'q':
s.send(message)
data = s.recv(1024)
print 'Recieved from server: ' + str(data)
message = raw_input('Send message: ')
s.close()
if __name__ == '__main__':
startclient()
Please note that my server and client programs are just for testing for now.
I can't actually run your code to check, but it looks like the error can be fixed like this:
def callback(self, interface):
if interface.startswith('eth'):
self.interfaces["text"] = interface
else:
self.interfaces["text"] = "------"
self._netint = interface
def serverstart(self):
import tcpServer
tcpServer.start(self._netint)
Generally, it's best to avoid using global as much as possible. One of the benefits of using classes is that it provides a shared namespace that all the methods of class instances can access via self.
I have created a chat system using sockets , select and tkinter , however if the client restarts , it would fail to connect again until i restart the server.
This is the client code:
from tkinter import *
import tkinter.scrolledtext as tkst
import socket
import threading
import time
class myChatProgram(threading.Thread):
def __init__(self):
self.root = Tk()
self.myFrame = Frame(master = self.root)
self.myFrame.pack(fill='both', expand='yes')
self.chatArea = tkst.ScrolledText(
master = self.myFrame,
wrap = WORD,
width = 50,
height = 20
)
self.chatArea.configure(state='disabled')
self.chatArea.pack(padx=10, pady=10, fill=BOTH, expand=True)
self.bottomFrame = Frame(master = self.root)
self.bottomFrame.pack(fill='x', expand='yes' , side = "bottom")
self.entryBox = Entry(self.bottomFrame)
self.entryBox.pack(padx=10, pady=10,fill='x', expand='yes' , side = "left")
self.entryButton = Button(self.bottomFrame, text = "Send", command = self.sendText ,padx=10)
self.entryButton.pack(side = "right")
self.host = '192.168.1.150'
self.port = 50003
threading.Thread.__init__(self)
self.start()
self.root.mainloop()
def addText(self,message):
if message != "":
self.chatArea.configure(state='normal')
self.chatArea.insert(END, str(message) + "\n")
self.chatArea.configure(state='disabled')
def sendText(self):
message = bytes(self.entryBox.get(),"utf-8")
self.addText(self.entryBox.get())
if message:
self.mySocket.send(message)
self.entryBox.delete(0, END)
def run(self):
self.mySocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.mySocket.connect((self.host,self.port))
time.sleep(1)
while True:
self.addText(str(self.mySocket.recv(4096).decode("utf-8")))
myClass = myChatProgram()
And the server code is:
import socket
import select
import threading
class server(threading.Thread):
def __init__(self):
host = '192.168.1.150'
port = 50003
self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.server.bind((host,port))
print("Your ip is {0} ".format(socket.gethostbyname(socket.gethostname())))
self.server.listen(5)
self.sockets = []
self.sockets.append(self.server)
def main(self):
while True:
inputList , outputList , errorList = select.select(self.sockets, [], self.sockets)
for mySocket in inputList:
if mySocket == self.server:
newClient , addr = self.server.accept()
print(addr , " Connected")
self.sockets.append(newClient)
else:
try:
data = mySocket.recv(4096)
if data:
self.broadcast(mySocket,data)
else:
print("Connection sent 0 bytes.")
mySocket.close()
self.sockets.remove(mySocket)
except socket.error , e:
print("Client disconnected while sending message.")
mySocket.close()
self.sockets.remove(mySocket)
continue
for mySocket in errorList:
print("Select flagged client as crashed.")
mySocket.close()
self.sockets.remove(mySocket)
continue
def broadcast(self,mySocket,message):
print("sending {0}".format(message))
for client in self.sockets:
if client != mySocket and socket != self.server:
try:
client.send(bytes(message,"utf-8"))
except:
client.close()
self.sockets.remove(client)
continue
myClass = server()
myClass.main()
The the error is :
Exception in thread Thread-1:
Traceback (most recent call last):
File "C:\Python33\lib\threading.py", line 901, in _bootstrap_inner
self.run()
File "F:\Sockets\chatClient.py", line 49, in run
self.mySocket.connect((self.host,self.port))
ConnectionRefusedError: [WinError 10061] No connection could be made because the target machine actively refused it
However it works fine unless the client restarts , then it crashes. Any ideas what is wrong?
I guess you have to set SO_REUSEADDR:
socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)