How to close all threads and end connection - python

I am trying to implement the code as written here:
https://www.geeksforgeeks.org/simple-chat-room-using-python/
I can get it to run properly but cannot find a way to close the connection. The code simply runs until I enter a keyboard interrupt. I'l like to implement a keyword that will shut down the client and server and free the port.
I've implemented the client code to exit if the message is "quit" but the same technique isn't working in the server code. I keep getting caught on the "conn, addr = server.accept()" line and it returns the error
Traceback (most recent call last):
File "newServer.py", line 66, in <module>
conn, addr = server.accept()
File "/Users/######/anaconda3/lib/python3.7/socket.py", line 212, in accept
fd, addr = self._accept()
ConnectionAbortedError: [Errno 53] Software caused connection abort
Any help would be appreciated!
Edit: Adding code
server.py:
import socket
import select
from _thread import *
import threading
import sys
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
"""
the first argument AF_INET is the address domain of the socket. This is used when we have an Internet Domain
with any two hosts
The second argument is the type of socket. SOCK_STREAM means that data or characters are read in a continuous flow
"""
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
IP_address = "127.0.0.1"
Port = 12230
server.bind((IP_address, Port))
#binds the server to an entered IP address and at the specified port number. The client must be aware of these parameters
server.listen(100)
#listens for 100 active connections. This number can be increased as per convenience
list_of_clients=[]
def clientthread(conn, addr):
conn.send("Welcome to this chatroom!".encode())
#sends a message to the client whose user object is conn
while True:
try:
message = conn.recv(2048).decode()
if message:
print ("<" + addr[0] + "> " + message)
message_to_send = "<" + addr[0] + "> " + message
broadcast(message_to_send,conn)
#prints the message and address of the user who just sent the message on the server terminal
else:
remove(conn)
except:
continue
def broadcast(message,connection):
for clients in list_of_clients:
if clients!=connection:
try:
clients.send(message.encode())
except:
clients.close()
remove(clients)
def remove(connection):
if connection in list_of_clients:
list_of_clients.remove(connection)
while True:
conn, addr = server.accept()
"""
Accepts a connection request and stores two parameters, conn which is a socket object for that user, and addr which contains
the IP address of the client that just connected
"""
list_of_clients.append(conn)
print (addr[0] + " connected")
#maintains a list of clients for ease of broadcasting a message to all available people in the chatroom
#Prints the address of the person who just connected
start_new_thread(clientthread,(conn,addr))
#creates and individual thread for every user that connects
conn.close()
server.close()
client.py
import socket
import select
import sys
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
IP_address = "127.0.0.1"
Port = 12230
server.connect((IP_address, Port))
while True:
# maintains a list of possible input streams
sockets_list = [sys.stdin, server]
""" There are two possible input situations. Either the
user wants to give manual input to send to other people,
or the server is sending a message to be printed on the
screen. Select returns from sockets_list, the stream that
is reader for input. So for example, if the server wants
to send a message, then the if condition will hold true
below.If the user wants to send a message, the else
condition will evaluate as true"""
read_sockets,write_socket, error_socket = select.select(sockets_list,[],[])
for socks in read_sockets:
if socks == server:
message = socks.recv(2048).decode()
print (message)
else:
message = input("Message: ")
server.send(message.encode())
print("<You>")
print(message)
server.close()

Related

.how to add multiple clients on socket creating a console based server messanger with this code? In Python

these codes are mostly taken from a yt tutorial.
this code gives a console based chat server .
the problem is I can't use it in two computers.
I can't add more clients from computers other than my computer.
this is server
import socket
import select
HEADER_LENGTH = 10
IP = "127.0.0.1"
PORT = 1234
# Create a socket
# socket.AF_INET - address family, IPv4, some otehr possible are AF_INET6, AF_BLUETOOTH, AF_UNIX
# socket.SOCK_STREAM - TCP, conection-based, socket.SOCK_DGRAM - UDP, connectionless, datagrams, socket.SOCK_RAW - raw IP packets
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# SO_ - socket option
# SOL_ - socket option level
# Sets REUSEADDR (as a socket option) to 1 on socket
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
# Bind, so server informs operating system that it's going to use given IP and port
# For a server using 0.0.0.0 means to listen on all available interfaces, useful to connect locally to 127.0.0.1 and remotely to LAN interface IP
server_socket.bind((IP, PORT))
# This makes server listen to new connections
server_socket.listen()
# List of sockets for select.select()
sockets_list = [server_socket]
# List of connected clients - socket as a key, user header and name as data
clients = {}
print(f'Listening for connections on {IP}:{PORT}...')
# Handles message receiving
def receive_message(client_socket):
try:
# Receive our "header" containing message length, it's size is defined and constant
message_header = client_socket.recv(HEADER_LENGTH)
# If we received no data, client gracefully closed a connection, for example using socket.close() or socket.shutdown(socket.SHUT_RDWR)
if not len(message_header):
return False
# Convert header to int value
message_length = int(message_header.decode('utf-8').strip())
# Return an object of message header and message data
return {'header': message_header, 'data': client_socket.recv(message_length)}
except:
# If we are here, client closed connection violently, for example by pressing ctrl+c on his script
# or just lost his connection
# socket.close() also invokes socket.shutdown(socket.SHUT_RDWR) what sends information about closing the socket (shutdown read/write)
# and that's also a cause when we receive an empty message
return False
while True:
# Calls Unix select() system call or Windows select() WinSock call with three parameters:
# - rlist - sockets to be monitored for incoming data
# - wlist - sockets for data to be send to (checks if for example buffers are not full and socket is ready to send some data)
# - xlist - sockets to be monitored for exceptions (we want to monitor all sockets for errors, so we can use rlist)
# Returns lists:
# - reading - sockets we received some data on (that way we don't have to check sockets manually)
# - writing - sockets ready for data to be send thru them
# - errors - sockets with some exceptions
# This is a blocking call, code execution will "wait" here and "get" notified in case any action should be taken
read_sockets, _, exception_sockets = select.select(sockets_list, [], sockets_list)
# Iterate over notified sockets
for notified_socket in read_sockets:
# If notified socket is a server socket - new connection, accept it
if notified_socket == server_socket:
# Accept new connection
# That gives us new socket - client socket, connected to this given client only, it's unique for that client
# The other returned object is ip/port set
client_socket, client_address = server_socket.accept()
# Client should send his name right away, receive it
user = receive_message(client_socket)
# If False - client disconnected before he sent his name
if user is False:
continue
# Add accepted socket to select.select() list
sockets_list.append(client_socket)
# Also save username and username header
clients[client_socket] = user
print('Accepted new connection from {}:{}, username: {}'.format(*client_address, user['data'].decode('utf-8')))
# Else existing socket is sending a message
else:
# Receive message
message = receive_message(notified_socket)
# If False, client disconnected, cleanup
if message is False:
print('Closed connection from: {}'.format(clients[notified_socket]['data'].decode('utf-8')))
# Remove from list for socket.socket()
sockets_list.remove(notified_socket)
# Remove from our list of users
del clients[notified_socket]
continue
# Get user by notified socket, so we will know who sent the message
user = clients[notified_socket]
print(f'Received message from {user["data"].decode("utf-8")}: {message["data"].decode("utf-8")}')
# Iterate over connected clients and broadcast message
for client_socket in clients:
# But don't sent it to sender
if client_socket != notified_socket:
# Send user and message (both with their headers)
# We are reusing here message header sent by sender, and saved username header send by user when he connected
client_socket.send(user['header'] + user['data'] + message['header'] + message['data'])
# It's not really necessary to have this, but will handle some socket exceptions just in case
for notified_socket in exception_sockets:
# Remove from list for socket.socket()
sockets_list.remove(notified_socket)
# Remove from our list of users
del clients[notified_socket]
and this is client
import socket
import select
import errno
import sys
HEADER_LENTH = 10
IP = "127.0.0.1"
PORT = 1234
my_username = input("Username : ")
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client_socket.connect((IP, PORT))
client_socket.setblocking(False)
username = my_username.encode('utf-8')
username_header = f"{len(username):<{HEADER_LENTH}}".encode('utf-8')
client_socket.send(username_header + username)
while True:
message = input(f"{my_username} > ")
if message:
message = message.encode('utf-8')
message_header = f"{len(message) :< {HEADER_LENTH}}".encode('utf-8')
client_socket.send(message_header + message)
try:
while True:
# receive things
username_header = client_socket.recv(HEADER_LENTH)
if not len(username_header):
print("Connection closed by the server")
sys.exit()
username_length = int(username_header.decode('utf-8').strip())
username = client_socket.recv(username_length).decode('utf-8')
message_header = client_socket.recv(HEADER_LENTH)
message_length = int(message_header.decode('utf-8').strip())
message = client_socket.recv(message_length).decode('utf-8')
print(f"{username} > {message}")
except IOError as e:
if e.errno != errno.EAGAIN and e.errno != errno.EWOULDBLOCK:
print('Reading error: {}'.format(str(e)))
sys.exit()
continue
except Exception as e:
print('General error', str(e))
sys.exit()
so this is it guys pls help me .
I need this for my school project.
pls guys.

Socket Messaging Client/Server: Client not sending message

I am trying to create a simple chat program using Python and Socket. The server handles the connection between two clients. Whenever I run the program, for one of the clients, every message after the first one does not send. The message does not even reach the server.
This is on Windows, Python3. I've integrated threading so messages can be sent and received at the same time; however, the problem persists.
Server.py
conns = [] # list that stores both connections
def accept(sk):
while True:
conn, addr = sk.accept()
conns.append(conn)
print(addr, "has connected")
t = threading.Thread(target=accept, args=(sk,))
t.start() #start accept thread
def send(conn):
while True:
message = conn.recv(2048)
print(message)
for conn in conns:
conn.send(message) #sends message to every connection
print("Sent message")
t = threading.Thread(target=send, args=(conn,))
t.start() #start threading for send
Client.py
def recvMessages(s):
while True:
message = s.recv(2048)
print(message)
message = message.decode()
messages.append(message)
os.system("cls")
for message in messages:
print(message)
def sendMessage(s):
while True:
message = input()
message = message.encode()
s.send(message)
s = socket.socket()
host = socket.gethostname()
port = 8080
s.connect((host, port))
messages = []
print("Connected")
connected = True
threading.Thread(target=sendMessage, args=(s,)).start()
threading.Thread(target=recvMessages, args=(s,)).start()
All the messages should be sent from both clients, but one client can never send multiple messages, the other works fine.
Your server code is missing it's socket, and accept is not being run in your example, you also have invalid indentation as James pointed out, next time provide a minimal reproducible example.
I also cleaned up your files a bit, as you followed some bad practice, specifically with broadcasting the messages to all clients "def send" which actually receives, avoid confusing naming :)
in your server code you also sent only to one connection (which in your example doesn't exist) which it should be running the receive and send each time a new message is received
server.py
import socket
import threading
conns = [] # list that stores both connections
def accept(sk):
while True:
conn, addr = sk.accept()
conns.append(conn)
print(addr, "has connected")
# receive from new client
receive_t = threading.Thread(target=receive, args=(conn,))
receive_t.start() # start threading for send
def send(s, msg):
# change message ..
s.send(msg)
def broadcast(msg):
for conn in conns:
send(conn, msg)
def receive(conn):
try:
while True:
message = conn.recv(2048)
if not message: # detects if socket is dead, by testing message
print("client sent Nothing, removing")
conns.remove(conn)
break
broadcast(message) # send to all clients
except ConnectionResetError as e:
print('Could not send must be disconnected ')
conns.remove(conn) # remove dead socket
# added missing socket
sock = socket.socket()
sock.bind(('127.0.0.1', 8080))
sock.listen(1) # needs to bind and listen
t = threading.Thread(target=accept, args=(sock,))
t.start() # start accept thread
client.py
import os
import socket
import threading
messages = []
def recvMessages(s):
while True:
message = s.recv(2048)
message = message.decode()
print('new message= ', message)
messages.append(message)
os.system("cls")
for message in messages:
print(message)
def send_message(s):
while True:
message = input()
message = message.encode()
s.send(message)
s = socket.socket()
host = '127.0.0.1'
port = 8080
s.connect((host, port))
print("Connected")
connected = True
# added missing receive
receive = threading.Thread(target=recvMessages, args=(s,)) # missed receive thread in example
receive.start()
send_message(s)

UDP Python: How to make the server broadcast messages the clients send in the UDP Chatroom

I'm making a small chatroom application in Python using UDP sockets. I've set it up to where the user would choose their username and then send messages to the server. The server would then broadcast the message to every client connected. I managed to get the server working and the client is able to send messages to the server. The problem is the server isn't broadcasting the messages to the other clients connected.
Here is the server code:
from socket import *
import socket
port = 1234
localhost='127.0.0.1'
#Create a socket
try :
s = socket.socket(AF_INET, SOCK_DGRAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
print ('Socket created')
except socket.error:
print ('Error creating socket.')
sys.exit()
#Bind the socket to port and localhost.
try:
s.bind((localhost, port))
except socket.error:
print ('Error while binding.')
sys.exit()
print ('Bind complete.')
while 1:
# receive data from client (data, addr)
d = s.recvfrom(2048)
data = d[0]
addr = d[1]
if not data:
break
print('Client connected at ' + addr[0] + ':' + str(addr[1]))
print('Message[' + addr[0] + ':' + str(addr[1]) + '] - ' +
data.strip().decode("utf-8"))
s.close()
Client Code:
from socket import *
import socket
import sys
port=1234
localhost='127.0.0.1'
try:
s = socket.socket(AF_INET, SOCK_DGRAM)
except socket.error:
print ('Error creating socket.')
sys.exit()
print ("Connected to chat")
Username= input('Please choose a username: ')
while(1) :
msg = input ('Enter message to send : ')
try :
#Set the whole string
s.sendto('{}: {}'.format(Username,msg).encode('utf-8'), (localhost,port))
# receive data from server (data, addr)
data = s.recvfrom(2048)
reply = data[0]
addr = data[1]
print ( + reply.decode())
except socket.error:
print ('Error sending message ' )
sys.exit()
Any suggestions?
I think you are confused about what socket.SO_BROADCAST does. It doesn't cause all received messages to be broadcasted to all clients. It is used to let the network stack on the machine know that a socket can be used to send broadcast packets (by this I mean a packet with a destination address that is a deemed to be a "broadcast address" - this includes the network and broadcast addresses for a subnet, such as 192.168.0.0 or 192.168.0.255 for the subnet 192.168.0.0/24).
To make your chat app work as you intend, you need to keep a log of all conncected clients and then whenever you receive a message you then can re-send it to all clients using s.sendto().
Hey mate you really should be using asyncio for this:
(49mins) https://www.youtube.com/watch?v=ZzfHjytDceU
But what you need to do is create an object of users and then send them the data
Additionally you don't appear to be doing any sanitisation of the data: length and content should be limited. Basically:
from html import escape
clients = {}
...
msg = escape(msg_received[:2048])
for c in clients:
c.send(msg)

Send messages received by server to multiple clients in python 2.7 with socket programming

So I have created a socket program for both client and server as a basic chat. I made it so the server accepts multiple clients with threading, so that is not the problem. I am having trouble sending messages to each client that is connected to the server. I am not trying to have the server send a message it created but rather have client1 sending a message to client2 by going through the server. For some reason it will only send it back to client1.
For example, client1 will say hello and the server will send the same message back to client1 but nothing to client2. I fixed this slightly by making sure the client doesn't receive its own message but client2 is still not receiving the message from the client1.
Any help will be appreciated.
I have tried multiple changes and nothing seems to work. You can look at my code for specifics on how I did things but ask if there are any questions.
Also, there is a question where someone has asked that is similar and I thought it would give me an answer but the responses stopped going through and a solution was never fully given, so please don't just refer me to that question. that is located here: Python 3: Socket server send to multiple clients with sendto() function.
Here's the code:
CLIENT:
import socket
import sys
import thread
#Create a socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
#Enter username to identify self to others
name = raw_input("Enter username: ") + ": "
#Connect socket to ip and port
host = socket.gethostname()
#host = '192.168.1.10'
server_address = (host, 4441)
sock.connect(server_address)
#function waiting to receive and print a message
def receive(nothing):
while True:
data = sock.recv(1024)
if message != data:
print data
# Send messages
while True:
#arbitrary variable allowing us to have a thread
nothing = (0, 1)
message = name + raw_input("> ")
sock.sendall(message)
#thread to receive a message
thread.start_new_thread(receive, (nothing,))
SERVER:
import socket
import sys
import thread
# Create a TCP/IP socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# Bind the socket to the port
host = socket.gethostname()
server_address = (host, 4441)
sock.bind(server_address)
#Listen for incoming connections
sock.listen(5)
print "Waiting for connection..."
#Variable for the number of connections
numbOfConn = 0
#Name of list used for connections
addressList = []
#Function that continuosly searches for connections
def clients(connection, addressList):
while True:
message = connection.recv(1024)
print message
#connection.sendall(message)
#for loop to send message to each
for i in range(0,numbOfConn - 1):
connection.sendto(message, addressList[i])
connection.close()
while True:
#accept a connection
connection, address = sock.accept()
print 'Got connection from', address
numbOfConn += 1
addressList.append((address))
#Thread that calls the function: clients and stores them in a tuple called connection
thread.start_new_thread(clients, (connection, addressList))
sock.close()
Please help me if you can!
EDIT:
I was able to fix it to a certain extent. It is still a little buggy but I am able to send messages back and forth now. I needed to specify the connection socket as well as the address. Here's the updated code:
SERVER
import socket
import sys
import thread
# Create a TCP/IP socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# Bind the socket to the port
host = socket.gethostname()
server_address = (host, 4441)
sock.bind(server_address)
#Listen for incoming connections
sock.listen(5)
print "Waiting for connection..."
#Variable for the number of connections
numbOfConn = 0
#Name of list used for connections
addressList = []
connectionList = []
#Function that continuosly searches for connections
def clients(connectionList, addressList):
while True:
for j in range(0,numbOfConn):
message = connectionList[j].recv(1024)
print message
#for loop to send message to each
for i in range(0,numbOfConn):
connectionList[i].sendto(message, addressList[i])
connection.close()
while True:
#accept a connection
connection, address = sock.accept()
print 'Got connection from', address
numbOfConn += 1
addressList.append((address))
connectionList.append((connection))
#Thread that calls the function: clients and stores them in a tuple called connection
thread.start_new_thread(clients, (connectionList, addressList))
sock.close()

using select() method for client/ server chat in Python

I am writing a client/ server program in Python where, once the client and server have successfully connected via a socket, they may exchange messages. Below is my server and client code. When compiled, the connection is established correctly and the messages are sent successfully, but one cannot send a second message until it has received a response from the other party.
For example:
Client sends: "Hello, server!"
Server sends: "I have received your message, client!"
Client sends: "great, here's another one"
Client sends: "and a second one!"
At this point, the server terminal window has received the message saying "great, here's another one", but must first reply to this message before receiving "and a second one!".
I think my issue is that I need to use the select() method, but do not understand how to do so. How can I fix this?
#The server code
HOST = ''
PORT = 9999
s = socket(AF_INET, SOCK_STREAM)
s.bind((HOST, PORT))
print("Now listening...")
s.listen(1) #only needs to receive one connection (the client)
conn, addr = s.accept() #accepts the connection
print("Connected by: ", addr) #prints the connection
i = True
while i is True:
data = conn.recv(1024) #receives data
print('Received:' , repr(data)) #prints the message from client
reply = raw_input() #server types a response
conn.sendall(reply) #server now sends response back to client
close()
below is the client code (client.py)
The client code
from socket import*
HOST = '192.168.41.1'
PORT = 9999
s = socket(AF_INET, SOCK_STREAM)
s.connect((HOST, PORT))
while True:
message = raw_input() #client's message to the server
s.send(message) #sends message to the server
print("Waiting for response...")
reply = s.recv(1024) #receives message from server
print("New message: " + repr(reply)) #prints the message received
close()
Look at the following examples:
http://code.activestate.com/recipes/531824-chat-server-client-using-selectselect/
and
http://www.binarytides.com/code-chat-application-server-client-sockets-python/
also some similar answer here:
Python client side in chat
What you are missing is select on client side where its select if to handle input from server or from command line.
So in that case, you don't have to wait for server response and can send 2 calls one after another from the client.
Freely adapting the answers above to what you wished to accomplish.
(I didn't test it - so make sure to check it)
from socket import*
import sys
import select
HOST = '192.168.41.1'
PORT = 9999
s = socket(AF_INET, SOCK_STREAM)
s.connect((HOST, PORT))
while True:
socket_list = [sys.stdin, s]
# Get the list sockets which are readable
read_sockets, write_sockets, error_sockets = select.select(
socket_list, [], [])
for sock in read_sockets:
#incoming message from remote server
if sock == s:
data = sock.recv(1024)
if not data:
print('\nDisconnected from server')
break
else:
#print data
sys.stdout.write(data)
# prints the message received
print("New message: " + repr(data))
prompt()
#user entered a message
else:
msg = sys.stdin.readline()
s.send(msg)
prompt()
s.close()
I would strongly suggest reading and familiarizing with this document and especially the non-blocking sockets part.
Your code now blocks when waiting for the data to arrive from the user. You want to instruct your program to wait for the data from the socket and at the same time allow user to type input.

Categories

Resources