How to Solve Messaging, Leaving and Logging Problem - python

First, i ask a lot of questions i know it and i'm sorry... Anyway, i have a few problem on my Application.
I developed a TCP Chat Room with socket and thread modules. Everything is fine but when I write something I see it twice. I only want to see this once and like (ME : Message). Not only that, when I press CTRL + C I can't exit the application and even if I shut down the server, clients can message and the application stops. Finally, I want all messages from the user to be logged. How can I do that?
def broadcast(MESSAGE):
for CLIENT in CLIENT_LIST:
CLIENT.send(MESSAGE)
def handle(CLIENT):
while True:
try:
MESSAGE = CLIENT.recv(1024)
broadcast(MESSAGE)
except:
INDEX = CLIENT_LIST.index(CLIENT)
CLIENT.close()
USERNAME = USERNAME_LIST[INDEX]
broadcast (f'{USERNAME} Left The Chat!'.encode('utf-8'))
USERNAME_LIST.remove(USERNAME)
break
I will share my codes for you. I want learn it and solve with you. I know when i see a problem i'm writing here. Sorry, i'm writing there because i'm beginner so i'm a new in this world :)
import socket
import threading
HOST = "127.0.0.1"
PORT = 7777
ADDR = (HOST,PORT)
SERVER_SOCKET = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
SERVER_SOCKET.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
SERVER_SOCKET.bind((ADDR))
SERVER_SOCKET.listen()
CLIENT_LIST = []
USERNAME_LIST = []
def broadcast(MESSAGE):
for CLIENT in CLIENT_LIST:
CLIENT.send(MESSAGE)
def handle(CLIENT):
while True:
try:
MESSAGE = CLIENT.recv(1024)
broadcast(MESSAGE)
except:
INDEX = CLIENT_LIST.index(CLIENT)
CLIENT.close()
USERNAME = USERNAME_LIST[INDEX]
broadcast (f'{USERNAME} Left The Chat!'.encode('utf-8'))
USERNAME_LIST.remove(USERNAME)
break
def take():
while True:
CLIENT, ADDRESS = SERVER_SOCKET.accept()
print(f'Connected With {str(ADDRESS)}')
CLIENT.send("USERNAME".encode('utf-8'))
USERNAME = CLIENT.recv(1024).decode('utf-8')
USERNAME_LIST.append(USERNAME)
CLIENT_LIST.append(CLIENT)
print(f'Username Of The Client Is {USERNAME}!')
broadcast(f'{USERNAME} Joined The Chat! Welcome!'.encode('utf-8)'))
CLIENT.send("Connected To The Server!".encode('utf-8'))
thread = threading.Thread(target=handle, args=(CLIENT, ))
thread.start()
print("Server Is Listening...")
take()

Disclaimer: The following are direct solutions, but may not be the best design choice overall.
Seeing message twice:
The CLIENT sending MESSAGE is being broadcasted to again. Exclude sender from broadcast():
def broadcast(MESSAGE, sender):
for CLIENT in CLIENT_LIST:
if CLIENT == sender: continue
CLIENT.send(MESSAGE)
...
broadcast(MESSAGE, CLIENT)
Threads not stopping with CTRL+C:
You can set daemon=True to stop the thread with the parent process, but read the warning here
thread = threading.Thread(target=handle, args=(CLIENT, ), daemon=True)

Related

How to listen and connect multiple ports with python?

I'm working on a program that's basicly sending/recieving messages but I want to make a ranking system. The admins of this program can inform each other as well as the other users. I read so many articles already but I can't find the solution. Can anyone help me?
Here is the code for the server:
import socket,threading
HOST='127.0.0.1'
PORT=9134
PORT2=2233
server=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind((HOST,PORT))
server.bind((HOST,PORT2))
server.listen()
clients=[]
nicknames=[]
def broadcast(message):
for client in clients:
client.send(message)
def handle(client):
while 1:
try:
message = client.recv(1024)
print(f'{message}')
broadcast(message)
except:
index=clients.index(client)
clients.remove(client)
client.close()
nickname=nicknames[index]
nicknames.remove(nickname)
break
def receive():
while 1:
client, adress=server.accept()
print(f'Connected with {str(adress)}')
client.send("NICK".encode('utf-8'))
nickname=client.recv(1024)
nicknames.append(nickname)
clients.append(client)
broadcast(f'{nickname} connected to the server!\n'.encode('utf-8'))
thread = threading.Thread(target=handle, args=(client,))
thread.start()
print(clients,nicknames)
print("Server is running")
receive()

I've been stuck on this error for a week. OSError: [Errno 9] Bad file descriptor

Following some Python tutorials and memory with JavaScript I've made a working Python chatroom using sockets. Next up I wanted to add encryption to it, so I decided to encrypt all of the data using Base64. It worked, I was able to receive all encrypted messages from other clients. But when I try to decode the data from Base64 in the client I get OSError: [Errno 9] Bad file descriptor
How do I fix it?
Here's my code for the client:
import socket
import threading
import base64
# Choosing Nickname
nickname = input("Choose your nickname: ")
# Connecting To Server
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect(('127.0.0.1', 55554))
# Listening to Server and Sending Nickname
def write():
while True:
message = '{}: {}'.format(nickname, input(''))
message = message.encode('ascii')
message = base64.b64encode(message)
client.send(message)
def receive():
while True:
try:
# Receive Message From Server
# If 'NICK' Send Nickname
message1 = client.recv(1024).decode('ascii')
if message1 == 'NICK':
client.send(nickname.encode('ascii'))
else:
print(base64.b64decode(message1))
except:
# Close Connection When Error
print("An error occured!")
client.close()
break
# Starting Threads For Listening And Writing
receive_thread = threading.Thread(target=receive)
receive_thread.start()
write_thread = threading.Thread(target=write)
write_thread.start()
And the server:
import socket
import threading
import base64
# Connection Data
host = '127.0.0.1'
port = 55554
# Starting Server
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind((host, port))
server.listen()
# Lists For Clients and Their Nicknames
clients = []
nicknames = []
# Sending Messages To All Connected Clients
def broadcast(message):
for client in clients:
client.send(message)
# Handling Messages From Clients
def handle(client):
while True:
try:
# Broadcasting Messages
message = client.recv(1024)
broadcast(message)
except:
# Removing And Closing Clients
index = clients.index(client)
clients.remove(client)
client.close()
nickname = nicknames[index]
broadcast('{} left!'.format(nickname).encode('ascii'))
nicknames.remove(nickname)
break
# Receiving / Listening Function
def receive():
while True:
# Accept Connection
client, address = server.accept()
print("Connected with {}".format(str(address)))
# Request And Store Nickname
client.send('NICK'.encode('ascii'))
nickname = client.recv(1024).decode('ascii')
nicknames.append(nickname)
clients.append(client)
# Print And Broadcast Nickname
print("Nickname is {}".format(nickname))
joinmessage = "{} joined!".format(nickname).encode('ascii')
broadcast(base64.b64encode(joinmessage))
client.send('Connected to server!'.encode('ascii'))
# Start Handling Thread For Client
thread = threading.Thread(target=handle, args=(client,))
thread.start()
receive()
Looks like the issue was that I wasn't decoding the message before decoding with Base64.
else:
message1 = base64.b64decode(message1)
print(message1.decode('ascii'))

Python Socket Server Can Only Handle 1 Client at a time

I am trying to make a server-client program using threads to handle each client, but the server will only accept one client at a time. If the first client disconnects, then the second client is accepted. Furthermore, each client can only send data once, then the program fails to send any more.
Prior to posting, I have looked at MANY other Stack Overflow posts, including the following:
how can I make a server communicate with more than 1 client at the same time?
python multithreaded server
My Python socket server can only receive one message from the client
But through looking at these posts I have found no solution.
Here is the server code:
import socket
from threading import *
def main():
s=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(('172.20.3.62', 5000))
s.listen(1)
clients = []
print("listening")
def clienthandler(c):
clients.append(c)
try:
while True:
data = c.recv(1024).decode("UTF-8")
if not data:
break
else:
print(data)
for client in clients:
client.send(data.encode("UTF-8"))
except:
clients.remove(c)
c.close()
while True:
c, addr = s.accept()
print("accepted a client")
Thread(target=clienthandler(c)).start()
if __name__ == '__main__':
main()
Here is the client code:
import socket
from threading import *
def main():
s=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('172.20.3.62', 5000))
print("connected")
def send():
msg = input("ENTER:")
s.send(msg.encode("UTF-8"))
def receive():
while True:
data = s.recv(1024).decode("UTF-8")
if data:
print(data)
else:
break
Thread(target=send).start()
Thread(target=receive).start()
if __name__ == '__main__':
main()
Thanks to user Rawing. His/Her solution was: Thread(target=clien‌​thandler(c)) -> Thread(target=clien‌​thandler, args=(c,))
This allowed for more than one thread, and I was able to solve the only one message problem by putting the client send block in a while loop.

create multi-thread tcp server python 3

Hello I tried to make a simple server that accept multiple clients simultaneously I'm new to python and I have a difficult to understand it....I try to change my code in multi-thread applications but without positive result...here is the code:
import socket, threading
def message():
while 1:
data = connection.recv(1024)
if not data: break
#connection.sendall(b'-- Message Received --\n')
print(data.decode('utf-8'))
connection.close()
def connection():
address = input("Insert server ip")
port = 44444
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((address, port))
s.listen(1)
print("Server started! Waiting for connections...")
def accept connection():
connection, address = s.accept()
print('Client connected with address:', address)
t=thread.Threading(target=message,args=(connection))
t.run()
I know that there are many errors but I'm new in python sorry :(
The original non-threaded code is:
import socket
address = input("Insert server ip:")
port = 44444
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((address, port))
s.listen(1)
print("Server started! Waiting for connections...")
connection, address = s.accept()
print('Client connected with address:', address)
while 1:
data = connection.recv(1024)
if not data: break
#connection.sendall(b'-- Message Received --\n')
print(data.decode('utf-8'))
connection.close()
Your basic design is close, but you've got a whole lot of little problems making it hard to move forward.
First, you have a function name with a space in it, which isn't allowed. And you have an IndentationError because you didn't indent its contents.
Next, inside that accept_connection function, you're using threading wrong.
thread.Threading doesn't exist; you probably meant threading.Thread.
args has to be a sequence (tuple, list, etc.) of values. You probably expected (connection) to be a tuple of one value, but it's not; tuples are defined by commas, not parentheses, and what you have is just the value connection with superfluous parentheses around it. You wanted (connection,) here.
Also, calling run on a thread object just runs the thread's code in the current thread. You want to call start, which will start a new thread and call the run method on that thread.
Meanwhile, you're never actually calling this function anywhere, so of course it can't do anything. Think about where you want to call it. After creating the listener socket, you want to loop around accept, kicking off a new client thread for each accepted connection, right? So, you want to call it in a loop, either inside connection, or at the top level (in which case connection has to return s).
And finally, your accept_connection function can't access local variables from some other function; if you want it to use a socket named s, you have to pass it as a parameter.
So:
def connection():
address = input("Insert server ip")
port = 44444
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((address, port))
s.listen(1)
print("Server started! Waiting for connections...")
while True:
accept_connection(s)
def accept_connection(s):
connection, address = s.accept()
print('Client connected with address:', address)
t=thread.Threading(target=message, args=(connection,))
t.start()
As a side note, be careful with using sock.recv(1024) and assuming you're going to get the whole message that the other side sent with send(msg). You might get that, or you might get half the message, or the whole message plus half of another message the client sent later. Sockets are just streams of bytes, like files, not streams of separate messages; you need some kind of protocol to separate messages.
The simplest possible protocol is to send each message on its own line. Then you can just do socket.makefile() and for line in f:, just like you would for a real file. Of course this doesn't work if your messages can have newlines, but you can, e.g., backslash-escape them on one side and unescape them on the other.
This is a pretty old post but there's a nice way to do what you're talking about. Here's a link to an example I posted a little while back:
https://bitbucket.org/matthewwachter/tcp_threadedserver/src/master/
And the script:
from datetime import datetime
from json import loads, dumps
from pprint import pprint
import socket
from threading import Thread
class ThreadedServer(Thread):
def __init__(self, host, port, timeout=60, debug=False):
self.host = host
self.port = port
self.timeout = timeout
self.debug = debug
Thread.__init__(self)
# run by the Thread object
def run(self):
if self.debug:
print(datetime.now())
print('SERVER Starting...', '\n')
self.listen()
def listen(self):
# create an instance of socket
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
# bind the socket to its host and port
self.sock.bind((self.host, self.port))
if self.debug:
print(datetime.now())
print('SERVER Socket Bound', self.host, self.port, '\n')
# start listening for a client
self.sock.listen(5)
if self.debug:
print(datetime.now())
print('SERVER Listening...', '\n')
while True:
# get the client object and address
client, address = self.sock.accept()
# set a timeout
client.settimeout(self.timeout)
if self.debug:
print(datetime.now())
print('CLIENT Connected:', client, '\n')
# start a thread to listen to the client
Thread(target = self.listenToClient,args = (client,address)).start()
# send the client a connection message
# res = {
# 'cmd': 'connected',
# }
# response = dumps(res)
# client.send(response.encode('utf-8'))
def listenToClient(self, client, address):
# set a buffer size ( could be 2048 or 4096 / power of 2 )
size = 1024
while True:
try:
# try to receive data from the client
data = client.recv(size).decode('utf-8')
if data:
data = loads(data.rstrip('\0'))
if self.debug:
print(datetime.now())
print('CLIENT Data Received', client)
print('Data:')
pprint(data, width=1)
print('\n')
#send a response back to the client
res = {
'cmd': data['cmd'],
'data': data['data']
}
response = dumps(res)
client.send(response.encode('utf-8'))
else:
raise error('Client disconnected')
except:
if self.debug:
print(datetime.now())
print('CLIENT Disconnected:', client, '\n')
client.close()
return False
if __name__ == "__main__":
ThreadedServer('127.0.0.1', 8008, timeout=86400, debug=True).start()
Here is some example code I have showing a threaded socket connection.
def sock_connection( sock, host ):
"Handle socket"
pass
while 1:
try:
newsock = sock.accept()
thread = Thread( target=sock_connection, args=newsock )
thread.start()
except Exception, e:
print "error on socket connection: " % e)

Choosing recepient of socket.send - Python socket module

I am trying to make a group chat program, where an unlimited amount of clients may join the server using the same script, it'll work by the server receiving the clients message and sending it to all the connected clients including the sender. I have only managed to make it so that the sender only gets his own message back, but not what another client sends.
I was thinking of storing all the connected client IP's in a list, and sending it to each IP, but I do not know how to change the recpient of socket.send
Server code:
from threading import *
import socket
s = socket.socket()
host = socket.gethostbyname(socket.gethostname())
port = 1337
s.bind((host, port))
s.listen(5)
print("Server host is", host)
def getMainThread():
for thread in enumerate():
if thread.name == 'MainThread':
return thread
return None
class client(Thread):
def __init__(self, socket, address):
Thread.__init__(self)
self.socket = socket
self.address = address
self.start()
def run(self):
main = getMainThread()
while main and main.isAlive():
print(self.address, "has connected!")
message = self.socket.recv(8192).decode('utf-8')
self.socket.send(bytes(message, 'UTF-8'))
self.socket.close()
while True:
c, addr = s.accept()
client(c, addr)
clients = [] #list for all client IP's
clients.append(addr)
Also, is there a way so that the client can establish a connection with the server so it doesn't keep poping up on the server.py that client has connected each time it sends a message?
Client code:
import socket
import os
import sys
host = '25.154.84.23'
print("""
=======================================================
=Welcome to Coder77's local internet messaging service=
=======================================================
The current soon to be encrypted server is {0}
You can enter the command /help for a list of commands available
""".format(host))
#username = input("Enter username: ")
username = 'Smile'
print("Now connecting to {0}....".format(host))
def printhelp():
print("""
The following commands are in the current version of this program:
/clear to clear the screen
/username to change your username
/exit to exit
/help for a list of commands
""")
def main():
global username
global host
sock = socket.socket()
try:
sock.connect((host, 1337))
while True:
message2 = input("{0}: ".format(username))
message = ('{0}: {1}'.format(username,message2))
if '/quit' in message:
sys.exit()
if '/clear' in message:
os.system('cls')
if '/help' in message:
printhelp()
if '/username' in message:
username = input("What would you like as your new username? ")
sock.send(bytes(message, 'UTF-8'))
received = sock.recv(8192).decode('utf-8')
print(received)
except socket.error:
print("Host is unreachable")
if __name__ == '__main__':
main()
#
Corrected Server code:
import sys
print(sys.version)
from threading import *
import socket
s = socket.socket()
host = socket.gethostbyname(socket.gethostname())
port = 1337
s.bind((host, port))
s.listen(5)
print("Server host is", host)
def getMainThread():
for thread in enumerate(): # Imported from threading
if thread.name == 'MainThread':
return thread
return None
class Client(Thread):
def __init__(self, socket, address):
Thread.__init__(self)
self.socket = socket
self.address = address
self.start()
def run(self):
main = getMainThread()
print(self.address, "has connected!")
while main and main.isAlive():
message = self.socket.recv(8192).decode('utf-8')
print(message)
self.socket.send(bytes(message, 'UTF-8'))
for each_client in clients:
each_client.socket.send(bytes(message, 'UTF-8'))
while True:
c, addr = s.accept()
this_client = Client(c, addr)
clients = []
clients.append(this_client)
The new code, adapted by gravetii is causing a lot of format errors. What happens now, is the user gets back what he sent, he does not get back what other users send and the user gets back what his previous message was, its terribly confusing. Please run the code, and you'll see as it's very hard to explain.
Example
In your server code, you are doing only a self.socket.send(bytes(message, 'UTF-8')). How can you then expect the server to send the message to all the clients? To do that you would need to iterate through the list of clients and call the send() method on each of their sockets.
while True:
c, addr = s.accept()
client(c, addr)
clients = [] #list for all client IP's
clients.append(addr)
In this code, you are creating a client object but never adding it to the list, then what's the point of creating one?
I think what you want is this:
while True:
c, addr = s.accept()
this_client = client(c, addr)
clients = [] #list for all client IP's
clients.append(this_client)
Then, you can send the message to all the clients by modifying the relevant part of your server code:
def run(self):
main = getMainThread()
while main and main.isAlive():
print(self.address, "has connected!")
message = self.socket.recv(8192).decode('utf-8')
self.socket.send(bytes(message, 'UTF-8'))
for each_client in clients:
each_client.socket.send(bytes(message, 'UTF-8'))
Also, why are you closing the connection after sending just one message? I believe your intention is to send more than one message to the server, and in that case, you don't need to close the connection.
Also, it's a better idea to create a class with its name starting with an upper case letter. So you may want to use Client instead of client for the class name.
Now coming to the issue of the message popping up everytime a client says something in your server.py, look at the run() method for the client thread:
def run(self):
main = getMainThread()
while main and main.isAlive():
print(self.address, "has connected!")
message = self.socket.recv(8192).decode('utf-8')
self.socket.send(bytes(message, 'UTF-8'))
The thread starts executing as soon as you create the client object, and so the first time when it connects to the server, it is right in showing that message. But then it's incorrect to place the print(self.address, "has connected!") in the while loop. So everytime the client says something, the server sends it back to the client and then the loop runs again, thus displaying the message back again. You need to modify it like so:
def run(self):
print(self.address, "has connected!")
main = getMainThread()
while main and main.isAlive():
message = self.socket.recv(8192).decode('utf-8')
self.socket.send(bytes(message, 'UTF-8'))
Hope this helps!

Categories