First as a disclaimer: I'm not the greatest at Python(or programming in general).
Having said that, I am having issues with Python Sockets. I am trying to build a simple chat client/server program, however, I am unable to have the server send the corresponding message(s) received from one client's socket, to the rest of the connected clients.
Here is the server code:
#!/usr/bin/python
import socket
import fnmatch
import thread
serverSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
## Allow socket to be reused by application - doesn't force timeout.
serverSocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
host = socket.gethostname()
port = 9000
serverSocket.bind((host,port))
connectedUsers = []
serverSocket.listen(5)
def threadedClient(clientStream):
while True:
clientMessage = clientStream.recv(1024).decode()
print clientMessage
if "Username:" in clientMessage:
username = clientMessage.replace("Username:","")
print str(username) + " has connected!"
connectedUsers.append(clientAddress)
print str(username) + "" + str(clientAddress) + " has connected to server"
for users in connectedUsers:
clientStream.sendto(str(username) + " has connected!", users)
if "Text:" in clientMessage:
receievedText = clientMessage.replace("Text:","")
for users in connectedUsers:
clientStream.sendto(receievedText.encode(), users)
print "Sending message " + str(receievedText) +" to:" + str(users)
if not clientMessage:
break
while True:
clientStream, clientAddress = serverSocket.accept()
thread.start_new_thread(threadedClient,(clientStream,))
Here is the client code:
#!/usr/bin/python
import socket
clientSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
host = "127.0.0.1"
port = 9000
username = raw_input("Please enter username: ")
clientSocket.connect((host, port))
clientSocket.send("Username:" + username)
def receiveServerMessage():
serverMessage = clientSocket.recv(1024).decode()
print serverMessage + '\n'
while True:
receiveServerMessage()
command = raw_input(username + " > ")
if command != None:
clientSocket.send("Text:" + str.encode(command))
if command == str("q"):
exit()
clientSocket.close()
The iteration seems to be awry when attempting to send the message to the other connected clients. I'm not sure if "sendto" is the proper way of handling this situation...especially since I believe it is UDP based. Any suggestions on how to handle socket stream correctly?
the problem is that the client is listening to the keyboard input before listening to the server socket , the best way to solve this is by using select() which similar to select() in c
here is a good example https://pymotw.com/2/select/
Related
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)
I'm stuck on this socket communication, I've looked everywhere but I haven't found an answer yet.
THE PROBLEM: I can only send 1 message from the client before it either gives me an error or ends the script.
I need to be able to send multiple messages to the server.
The server side (shown below) should be fine:
# Echo server program
import socket
import time
import os
#-----------------------------------------------------------------------------------------------------------------------
today = time.strftime('%Y.%m.%d')
logFileName = "log - " + today + ".txt"
HOST = '10.0.0.16'
PORT = 8080 # Reserve a port for your service
BUFFER_SIZE = 1024
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # Create a socket object
s.bind((HOST, PORT)) # Bind to the port
def print_write(text):
log.write(time.strftime("%H:%M:%S") + " | " + text)
log.write("\n")
print text
#-----------------------------------------------------------------------------------------------------------------------
if os.path.isfile(logFileName) is True:
log = open(logFileName, 'a+')
print_write("[SERVER] Log for " + today + " already exists.")
print_write("[SERVER] Starting comms")
else:
print "[SERVER] Log doesn't exist"
log = open(logFileName, 'a+') # Create file -> log - %date%.txt
print_write("[SERVER] Log created")
while True:
s.listen(1)
conn, addr = s.accept()
data = conn.recv(BUFFER_SIZE)
if data == "Comms Shutdown":
print_write("------ REMOTE SHUTDOWN ------")
conn.close()
raise SystemExit
else:
print_write("[COMMS] " + str(addr) + " says: " + data)
log.close()
Sorry if it's very messy and confusing but i don't have much time to finish this project, if you have any question just ask.
For the client side I don't have much but here, I'll give you this:
import socket
HOST = '10.0.0.16' # The remote host
PORT = 8080 # The same port as used by the server
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))
while True:
msg = raw_input()
s.sendall(msg)
print msg
I know it doesn't work, it's just to give you an idea of what I need.
Thank you in advance.
The problem is, that you only read the first message from each open connection before moving on to the next. The accept() methods waits for a new connection and gives you the information needed when a new one comes in. the recv() method on the other hand, receives data from a existing connection and waits if there is none. If you want to receive multiple messages from a single client, you can just wait for the first connection and then wait for data with recv(). This could look like this:
s.listen(1)
conn, addr = s.accept()
while True:
data = conn.recv(BUFFER_SIZE)
if data == "Comms Shutdown":
print_write("------ REMOTE SHUTDOWN ------")
conn.close()
raise SystemExit
else:
print_write("[COMMS] " + str(addr) + " says: " + data)
If you want to be able to also manage multiple clients, you will have to create a thread for each one from a while loop waiting for new connections. This is a bit more complicated:
def client_handler(conn):
while True:
data = conn.recv(BUFFER_SIZE)
if data == "Comms Shutdown":
print_write("------ REMOTE SHUTDOWN ------")
conn.close()
raise SystemExit
# this will kill the server (remove the line above if you don't want that)
else:
print_write("[COMMS] " + str(addr) + " says: " + data)
while True:
s.listen(1)
conn, addr = s.accept()
recv_thread = threading.Thread(target=client_handler, args=(conn, ))
recv_thread.start()
All this code is untested. Be aware, that I omitted the logging part and the socket creation part as well as all imports.
I am making a game in python. It uses sockets. It is my first time using sockets.
Here is part of my code:
serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
serversocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
# get local machine name
host = socket.gethostname()
port = 9999
# bind to the port
serversocket.bind((host, port))
# queue up to 5 requests
serversocket.listen(5)
player = 1
keys = []
playerSockets = []
print "Waiting for players..."
while True:
# establish a connection
clientsocket, addr = serversocket.accept()
key = id_generator()
keys.append(key)
playerSockets.append(clientsocket)
clientsocket.send(str(player)+"\r\n")
clientsocket.send(str(key)+"\r\n")
print "Player " + str(player) + " connected."
player = player + 1
if player > 3 or currentEpochtime() > endConn:
break
print str(player-1) + " active players.\n"
if(player < 3):
print "Not enough Players. Closing..."
serversocket.close()
quit()
#Other Stuff Continues
Now, it only sends the above data (player and key) only after the next send statement comes in my code. But then, that next send statement never sends because it is waiting for a reply from the client. But the client is not sending anything as it still hasn't received the data from the previous send statement in the server.
I have been trying to find a solution for a very long time, but cannot do so.
Please help!
Not quite sure about your question, do you mean client couldn't receive info from server?
I try with the following client code:
import socket
s = socket.socket()
host = socket.gethostname()
port = 9999
s.connect((host, port))
print s.recv(1024)
input = raw_input('type anything and click enter... ')
s.send(input)
print "the message has been sent"
It seems to receive data sent by server and be able to send data back to server.
Does this help?
I am creating a simple chat in python 3 using socket
here are the code
CLIENT
#!/bin/python
import socket
import threading
import time
tLock = threading.Lock()
poweroff = False
def receving(name, sock):
while not poweroff:
try:
tLock.acquire()
while True:
data, addr = sock.recvfrom(1024)
print (str(data))
except:
pass
finally:
tLock.release()
host = '127.0.0.1'
port = 0
server = ('127.0.0.1', 5000)
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.bind((host, port))
s.setblocking(0)
rT = threading.Thread(target=receving, args=("RecvThread", s))
rT.start()
alias = input("Username: ")
time.sleep(0.2)
message = input(alias + ">>> ")
while message != 'q':
if message != "":
s.sendto(str(alias + ": " + message).encode('utf-8'), server)
tLock.acquire()
message = input(alias + ">>> ")
tLock.release()
time.sleep(0.2)
poweroff = True
rT.join()
s.close()
SERVER
#!/bin/python
import socket
import time
hostname = '127.0.0.1'
port = 5000
clients = []
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.bind((hostname, port))
s.setblocking(0)
iQuit = False
print ("Server Started.")
while not iQuit:
try:
data, addr = s.recvfrom(1024)
if addr not in clients:
clients.append(addr)
print (time.ctime(time.time()) + str(addr) + ": :" + str(data))
for client in clients:
s.sendto(data, client)
except:
pass
s.close()
How do i print a string to the server when a user connect?
I have tried to add this string after you have insert the name
s.sendto(str(alias + " Connected").encode('utf-8'), server)
but the output is orrible for me
Another Question:
Why i get something like this when seding a message?
Username: User_A
User_A>>> Hello
User_A>>> How Are you?
b'User:A: Hello'
User_A>>>
b'User_A: How Are you?'
b'User_B: Hi'
Concerning your second question: You are printing binary strings, see here for more information.
Use str(data.decode('utf-8')) instead of str(data) when printing the message on the server or the client.
Concerning the first question: This should work if you send the "Connected" string just after asking for the user name.
The string is decoded the same way as a common message if you include the decode('utf-8') and looks normal to me.
i have to press enter to see if user_B send something to me.
You enforced this behavior by locking out the receiving thread during the input of a message. You have to make up your mind whether you want this or want incoming data to be printed while typing.
You might want to cf. Simultaneous input and output for network based messaging program.
Here is my server code.
# chat_server.py
import sys, socket, select
HOST = ''
SOCKET_LIST = []
RECV_BUFFER = 4096
PORT = 9009
def chat_server():
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server_socket.bind((HOST, PORT))
server_socket.listen(10)
# add server socket object to the list of readable connections
SOCKET_LIST.append(server_socket)
print "Chat server started on port " + str(PORT)
while 1:
# get the list sockets which are ready to be read through select
# 4th arg, time_out = 0 : poll and never block
ready_to_read,ready_to_write,in_error = select.select(SOCKET_LIST,[],[],0)
for sock in ready_to_read:
# a new connection request recieved
if sock == server_socket:
sockfd, addr = server_socket.accept()
SOCKET_LIST.append(sockfd)
print "Client (%s, %s) connected" % addr
broadcast(server_socket, sockfd, "[%s:%s] entered our chatting room\n" % addr)
# a message from a client, not a new connection
else:
# process data recieved from client,
try:
# receiving data from the socket.
data = sock.recv(RECV_BUFFER)
if data:
# there is something in the socket
broadcast(server_socket, sock, "\r" + '[' + str(sock.getpeername()) + '] ' + data)
else:
# remove the socket that's broken
if sock in SOCKET_LIST:
SOCKET_LIST.remove(sock)
# at this stage, no data means probably the connection has been broken
broadcast(server_socket, sock, "Client (%s, %s) is offline\n" % addr)
# exception
except:
broadcast(server_socket, sock, "Client (%s, %s) is offline\n" % addr)
continue
server_socket.close()
# broadcast chat messages to all connected clients
def broadcast (server_socket, sock, message):
for socket in SOCKET_LIST:
# send the message only to peer
if socket != server_socket and socket != sock :
try :
socket.send(message)
except :
# broken socket connection
socket.close()
# broken socket, remove it
if socket in SOCKET_LIST:
SOCKET_LIST.remove(socket)
if __name__ == "__main__":
sys.exit(chat_server())
Here is my client code.
# chat_client.py
import sys, socket, select
def chat_client():
if(len(sys.argv) < 3) :
print 'Usage : python chat_client.py hostname port'
sys.exit()
host = sys.argv[1]
port = int(sys.argv[2])
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(2)
# connect to remote host
try :
s.connect((host, port))
except :
print 'Unable to connect'
sys.exit()
# TEST
person = raw_input ('Please enter your username: ')
print 'Connected to remote host. You can start sending messages.'
sys.stdout.write( person + '[Me]: ' ); sys.stdout.flush()
while 1:
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:
if sock == s:
# incoming message from remote server, s
data = sock.recv(4096)
if not data :
print '\nDisconnected from chat server'
sys.exit()
else :
#print data
sys.stdout.write(data)
sys.stdout.write( person + '[Me]: '); sys.stdout.flush()
else :
# user entered a message
msg = sys.stdin.readline()
s.send(msg)
sys.stdout.write( person + '[Me]: '); sys.stdout.flush()
if __name__ == "__main__":
sys.exit(chat_client())
I'm currently trying to work on adding sort of a "handle" system into the chat client. If you were to run this code, you'll notice that the handle you choose is only displayed on your client, and not anybody else's. I've done hours of research already, and I can't for the life of me figure out how to have a client's chosen handle displayed onto other clients.
I'm still relatively new to Python, and especially new to TCP/IP programming. Any help, advice, and constructive criticism will be welcomed. Thanks in advance!
You can do it on the server or the client side
Server side
To implement it server side, you need to maintain some kind of mapping in the server between client sockets and handles, so that when you broadcast a message from a socket, you can retrieve its handle and prepend it to the message before sending.
In order to know the handle of the clients, they can send it to the server as the first message when they connect. The server will interpret this first message as the handle, and store it mapping it to the socket from what it has been received.
The advantage of this approach is that the server can validate the handle before it accepts it from the clients, and if it is already in use, reject the handle or abort the connection. Also, the clients cannot fake their handle later in the conversation, as it is the server that sends them.
Client side
This is the easiest implementation, as you only need to modify the client and prepend the handle before sending each message.
# user entered a message
msg = sys.stdin.readline()
s.send(person + ": " + msg)
sys.stdout.write( person + '[Me]: '); sys.stdout.flush()
The drawbacks of this approach are that a malicious client can fake the handle to pretend to be another person, and that two clients can have the same handle at the same time, making them indistinguishable from each other.