Python: How to send message to client from server at any time? - python

I'm building a discussion board style server/client application were the client connects to the server, is able to post messages, read messages, and quit.
See client code below:
import socket
target_host = "0.0.0.0"
target_port = 9996
#create socket object
client = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
#connect the client
client.connect((target_host,target_port))
#receiving user name prompt
print client.recv(1024)
usrname = str(raw_input())
#send username
client.send(usrname)
#check if username was unique
while client.recv(1024) == "NU": #should exit once "ACK" received
print client.recv(1024) #print username promt again
usrname = str(raw_input()) #client enters in another username
client.send(usrname)
#receive user joined message/welcome message/help menu
response = client.recv(1024)
print response
print client.recv(1024)
#loops until client disconnects
while True:
request = str(raw_input("\n\nWhat would you like to do? "))
client.send(request)
if request == "-h":
help_menu = client.recv(1024)
print help_menu
elif request == "-p":
#get subject
subject_request = client.recv(1024)
print subject_request
subject = str(raw_input())
client.send(subject)
#get contents of post
contents_request = client.recv(1024)
print contents_request
contents = str(raw_input())
client.send(contents)
#get post notification
message_post = client.recv(1024)
print message_post
elif request == "-r":
#get id value of post
id_request = client.recv(1024)
print id_request
message_id = str(raw_input())
client.send(message_id)
#get contents of post
message_contents = client.recv(2048)
print message_contents
elif request == "-q":
break
else:
print client.recv(1024)
When a client joins though, I wish to notify all other clients that are connected that a new client has joined, but each client may be at a different point in the code (some may be in the middle of a post, sitting idle at the "what would you like to do?" statement, etc).
So how would I set my client code up that it will be able to accept a message from the server the moment another client joins?

There are many ways to do it. Here an overview of how I would.
Are you familiar with "select" operations? They allow you to listen on multiple file descriptors and get notified whenever one becomes active. I would start by using that to both listen for keyboard inputs and server messages.
Then there are 2 things to be done. Branch depending on the active canal. If it's a keyboard input you can relay the command to the server. If it's a server message, you need to branch again on the message type to act accordingly.
Edit: Never assume what the server message is about. Even though you may have just sent a query, the server may be sending data about something else.

Related

How to take inputs and outputs properly from the same console as a client (connected to a remote server)?

I am currently working on a program in Python that works as a client, and needs to connect remotely to a server using the TCP/IP protocol. After the server receives the client's username, the client can send messages to other clients by typing "#<username> <message>", and this input will be further processed and the message that will be sent to the server will be constructed as "SEND <username> <message>", and this will be actually recognized by the server. Then the server will send back an acknowledgement to the sending client, and the actual message to the destination client.
My approach is to use a main function named chat_run(), used for input and constructing the message that will be sent to the server, and in parallel to run a function named OutputRecvMsg() in a different thread that will receive messages from the server and output them in the console.
The problem is, I want the beginning of all the input lines to start with username >, and the messages received from the server to be output immediately on a new line, and the client to wait for a new input.
My current implementation problem seems to be in receiving messages (the OutputRecvMsg() function). After it outputs a message to the console, I need to press Enter to ask for input, because it remains stuck.
For me, there are two questions regarding the current problem, maybe two threads try to access the same resource (console), maybe I made a mistake regarding the construction of the received message (because I know that sock.recv(4096) is blocking and I tried to avoid a blocking state).
import socket
import time
import re
import threading as th
SERVER_REPLY_1 = 'HELLO'
SERVER_REPLY_2 = 'IN-USE'
AT_SYMBOL = '#'
host_port = ('remote_server_add', 5378)
def build_loggin_msg(msg):
return 'HELLO-FROM ' + msg + ' \n'
def chat_run(sock, currentUser):
while True:
rawInput = input(currentUser + '> ')
if rawInput == '!who':
sock.sendall('WHO\n'.encode())
elif rawInput == '!quit':
sock.close()
break
else:
splittedMsg = re.split(r'\s', rawInput, maxsplit = 1)
if len(splittedMsg) > 1 and splittedMsg[0].startswith(AT_SYMBOL):
userNameToSend = splittedMsg[0][1:]
message = 'SEND ' + userNameToSend + ' ' + splittedMsg[1] + ' \n'
sock.sendall(message.encode())
def OutputRecvMsg(sock, currentUser):
OutMsg =''
chunk = ''
while True:
try:
chunk = sock.recv(4096).decode()
if not chunk:
pass
else:
OutMsg += chunk
except BlockingIOError as e:
if OutMsg:
print(OutMsg)
OutMsg = ''
if __name__ == '__main__':
loggedIn = False
currentUser = None
_data = ''
while not loggedIn:
currentUser = input('Add a username please: ')
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect(host_port)
sock.sendall(build_loggin_msg(currentUser).encode())
data = sock.recv(4096).decode()
print(data)
if data.startswith(SERVER_REPLY_1):
loggedIn = True
else:
print('Close connection for retry another username')
sock.close()
time.sleep(1)
sock.setblocking(0)
th.Thread(target=OutputRecvMsg, args=(sock, currentUser)).start()
chat_run(sock, currentUser)
As an example:
Add a username please: Nickname
HELLO Nickname
Nickname> #Nickname hello man -> send to me
Nickname> DELIVERY Nickname hello man
SEND-OK -> here I have to press enter to get the next lines
Nickname>

Receiving messages off the same socket in different threads - Python

I'm looking to build a chat room in python at the moment and am struggling with direct messages as I'm using client.recv(2048) function in both my thread listening for messages from the server and trying to use client.recv() in my main function to receive a list of active users on the server. It seems the program will work sometimes and others will shift to the clientreceive function.
Thread started
# Starts thread for client receive
receive_thread = threading.Thread(target=client_receive)
receive_thread.start()
receive block
def client_receive():
while True:
try:
message = client.recv(2048).decode()
print(message)
except:
client.close()
break
main method (DM)
if msg_type == "DM":
# Sends C DM message to server
dm_msg = "C DM"
client.send(dm_msg.encode())
# Receives list of online users from server in client_receive
users = client.recv(2048).decode()
print(users)
# Client inputs username and message to server
target = input("Select user: ")
chat = input("> ")
chat_msg = "D " + target + "|||||" + chat
I attempted using locks in my main method, which did not seem to work. I expected my method to stay with my socket when I used lock.acquire(), however it still broke to the clientreceive function
Thanks

How to check if bytes are received from the client?

I am making a chat interface, and currently, the server has to send a message first in order for the chatting to work.
If the client sends a message first, then the server cannot see the message until the server sends a message to the client.
My question:
How can I check if the client has sent anything to me? Then I can simply print it out.
Here is the server code:
serv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
serv.bind(("", 8080))
serv.listen(5)
while True:
c, addr = serv.accept()
print("Connection recieved from", addr)
while True:
strig = str(input("Enter your message to the client: "))
c.send(strig.encode())
thing = c.recv(1024)
message = list(str(thing))
message.remove("b")
printable = ""
for item in message:
printable += item
print(printable)
strig = str(input("Enter your message to the client: "))
c.send(strig.encode())
thing = c.recv(1024)
message = list(str(thing))
message.remove("b")
printable = ""
for item in message:
printable += item
print(printable)
And here is the client code:
from time import sleep
s = socket.socket()
port = 8080
s.connect(("10.0.0.92", port))
while True:
thing = str(s.recv(1024))
message = list(thing)
message.remove("b")
#message.remove("/")
printable = ""
for item in message:
printable += item
print(printable)
your = str(input("Enter your message to the server: "))
s.send(your.encode())
thing = str(s.recv(1024))
message = list(thing)
message.remove("b")
#message.remove("/")
printable = ""
for item in message:
printable += item
print(printable)
your = str(input("Enter your message to the server: "))
s.send(your.encode())
Thanks in advance!!
p.s. I want one person to be the server, and one person to be the client. Please don't tell me to make both people clients.
Your server is single-threaded. input waits for input so will never get to recv without user input. Create a thread to read client input and a thread to ask for and send messages. You'll need something similar on the client side.

What can I do with the "Socket Error number 10053"

I started to learn networks and in one of the exercises I was asked
to write a server which response multiple time to the same client
and I got this error
socket.error: [Errno 10053] An established connection was aborted by the software in your host machine
I wanted to ask whether the problem is with the software and not my program, or its with my program.
Here are my server and client (I'm warning that they're pretty long :D)
Server:
import socket
import time
import random
def message_init(client_socket):
"""
this method gets the socket of the client
and waiting for a command from the client
if the command is one of the commands the
server is familiar with, the method returns
a proper message. if its not a known command
to the server, the server sends to the client
'null' in order that it'll enter a new valid
command.
"""
# starting message with 'Garbage' in case when
# the client will insert unsupported commands
message = 'Garbage'
while message == 'Garbage':
# waiting for a command from the client
client_command = client_socket.recv(1024)
length = client_command[0: 2:]
request = client_command[2::]
# message is the proper reply for the request from the client
if request == 'TIME':
# message is the local time
message = time.asctime(time.localtime(time.time()))
elif request == 'NAME':
# message is the name of the server
message = "Daniel's Server"
elif request == 'RAND':
# message is a random integer between 1 - 10
message = str(random.randint(1, 10))
elif request == 'EXIT':
# message is exit and closing the connection with the client
message = 'EXIT'
client_socket.send(message)
client_socket.close()
if request == 'Garbage':
# sending 'null' to the client
# in order that he'll sent a valid command
client_socket.send('null')
# returns a message in proper to the command
return message
def send_message(client_socket, message):
"""
Gets a message and the socket of the client
sending to the client the number of bytes
in the message and afterwards sending the
message itself
"""
new_message = ''
length = len(message)
if length < 10:
new_message += '0'
new_message += str(length) + message
# sending the message to the client
client_socket.send(new_message)
def main():
"""
binding with every client that tries to connect.
getting a command from him, and if the command is
valid, the server does what the command asks for.
The proper Commands:
TIME: returns a string of the local time.
NAME: returns a string of the name of the server.
RAND: returns a string of number between 1 - 10.
EXIT: closing the connection with the client
"""
# creates a new socket
server_socket = socket.socket()
try:
# binding with every client who asks for
server_socket.bind(('0.0.0.0', 1729))
# waiting to get connection from a client
server_socket.listen(1)
except socket.error, e:
print e
connected = False
# an infinite loop of connecting with a client
# getting a command from a client and sending
# him proper response
while True:
if not connected:
# getting the client socket and his address
# and accepting the new connection
(client_socket, client_address) = server_socket.accept()
connected = True
# message gets a valid message using message_init function
message = message_init(client_socket)
if message != 'EXIT':
# if there's still connection:
send_message(client_socket, message)
else:
connected = False
client_socket.close()
# closing the socket of the server
# (although on the current server and client it won't happened)
server_socket.close()
if __name__ == '__main__':
main()`
Client:
import socket
def valid_cmd(command, commands):
"""
getting a command and a list of
approved commands. returning the
command when its one of the commands
"""
while command not in commands:
# waiting until the client enters a valid command
command = raw_input("Please enter one command of the following:"
" TIME, NAME, RAND or EXIT ")
# returns the command if its in commands
return command
def send_request_to_server(my_socket, request):
"""
getting a request and the socket
sending to the server the request
when there is its length before him
in two digits.
for example: 04RAND
04EXIT
"""
length = len(request)
message = ''
# putting a zero before so the length will
# be in two digits form
if length < 10:
message += '0'
message += str(length) + request
# sending the message to the server
my_socket.send(message)
def handle_server_response(my_socket, commands):
"""
Receive the response from the server
and handle it, according to the request
"""
# data gets the response from the server
data = my_socket.recv(1024)
# if the server returned null there was
# a problem with the message so we ask
# from the client to give us other message
while data == 'null':
message = raw_input("Please enter one command of the following:"
"TIME, NAME, RAND or EXIT")
# checks whether the message is valid
message = valid_cmd(message, commands)
# sending the message to the server
send_request_to_server(my_socket, message)
# waiting for the server's response
data = my_socket.recv(1024)
# returns the data when it has valid value
return data
def main():
"""
connecting to the home server
sending it a command
and printing the server's answer
"""
# creating a new socket
my_socket = socket.socket()
try:
# connecting the client to the home server
my_socket.connect(('127.0.0.1', 1729))
except Exception, e:
print e
my_socket.close()
# a list of the approved commands
commands = ['TIME', 'NAME', 'RAND', 'EXIT']
stopped = False
while not stopped:
# asking for an input of command
message = raw_input()
try:
# making sure that message is one of the valid commands
message = valid_cmd(message, commands)
# sending the message to the server
send_request_to_server(my_socket, message)
except Exception, e:
my_socket.close()
print e
# data gets a valid response from the server
data = handle_server_response(my_socket, commands)
# checking it the server disconnected from the client
if data == 'EXIT':
stopped = True
# keeping the length of the upcoming data
# although there is no use for that on that program
length = data[0: 2]
# printing the data from the server
print data[2::]
# disconnecting from the server
my_socket.close()
lst = ['a', 'b', 'c']
assert valid_cmd('b', lst) == 'b', 'valid_cmd should return' \
' the given value if its ' \
'already in the given list'
if __name__ == '__main__':
main()

How to change command line for execution

I wrote a simple code for a chat client and chat server (a separate code for the client and one for the server). My server currently executes with the command line
python chatserve.py <port number>
Just found out that class requirement is that the program starts with the following command line:
./chatclient <portnumber>
How do I convert? I would greatly appreciate any tips/help. Thank you!
(To clarify any confusion, the execution of my chat client also needs a ./chatclient in its command line, but since that part of the code was written in C, I was able to figure out how to get it to execute with specific command lines. I'm not as familiar with Python unfortunately.)
Here is the code:
#!/bin/python
from socket import *
import sys
#initiate chat with client
def chat(connectionsocket, clientname, username):
to_send = ""
while 1: # continue chat until break
# get characters from the user
received = connectionsocket.recv(501)[0:-1]
# if we received nothing, print close message and break
if received == "":
print "Closed connection. Wait for new connection..."
break
# print client username and message
print "{}> {}".format(clientname, received)
# get server input and send to client
to_send = ""
while len(to_send) == 0 or len(to_send) > 500:
to_send = raw_input("{}> ".format(username))
# special "\quit" message
if to_send == "\quit":
print "Closed connection. Wait for new connection..."
break
connectionsocket.send(to_send)
#initiate handshake with client
def handshake(connectionsocket, username):
# get the client username
clientname = connectionsocket.recv(1024)
# send server username to the client
connectionsocket.send(username)
return clientname
#execution
if __name__ == "__main__":
# If wrong number of arguments, print error message and exit
if len(sys.argv) != 2:
print "Error: no port number input"
exit(1)
# get port number and create TCP socket
serverport = sys.argv[1]
serversocket = socket(AF_INET, SOCK_STREAM)
# bind socket to port
serversocket.bind(('', int(serverport)))
# listen on port for incoming messages
serversocket.listen(1)
# get username
username = ""
while len(username) == 0 or len(username) > 10:
username = raw_input("Enter username (10 characters or less): ")
print "Receiving incoming messages..."
# continue receiving incoming messages until close
while 1:
# create new socket for incoming connection
connectionsocket, address = serversocket.accept()
# print connection message
print "Receiving connection on address {}".format(address)
# initiate handshake and chat with incoming connection
chat(connectionsocket, handshake(connectionsocket, username), username)
# close connection
connectionsocket.close()
Follow these steps:
Rename the filename to: chatserve
Add the following command in the first line of your code: #!/usr/bin/python or #!/usr/bin/python2 or #!/usr/bin/python3
Give him permission to execute: chmod +x chatserve

Categories