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
Related
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>
when I send message from client 1 , the message does not appear immediately in client 2 ,Although it appears immediately on the server, on client 2 i should double press "enter" to show other messages.
when I send message from client 1 , the message does not appear immediately in client 2 ,Although it appears immediately on the server, on client 2 i should double press "enter" to show other messages.
the server code :
import socket
import select
import sys
from _thread import *
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
if len(sys.argv) != 3:
print ("Correct usage: script, IP address, port number")
exit()
IP_address = str(sys.argv[1])
Port = int(sys.argv[2])
server.bind((IP_address, Port))
server.listen(5)
list_of_clients = []
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)
def clientthread(conn, addr):
# sends a message to the client whose user object is conn
conn.send(b'chat made by galal')
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)
else:
remove(conn)
except:
continue
while True:
conn, addr = server.accept()
list_of_clients.append(conn)
print (addr[0] + " connected")
start_new_thread(clientthread,(conn,addr))
conn.close()
server.close()
the client code :
import socket
import select
import sys
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
if len(sys.argv) != 3:
print ("Correct usage: script, IP address, port number")
exit()
IP_address = str(sys.argv[1])
Port = int(sys.argv[2])
server.connect((IP_address, Port))
while True:
# maintains a list of possible input streams
sockets_list = [socket.socket(), server]
read_sockets,write_socket, error_socket = select.select(sockets_list,[],[])
for socks in read_sockets:
if socks != server:
message = sys.stdin.readline()
server.send(message.encode())
sys.stdout.write("<You>")
sys.stdout.write(message)
sys.stdout.flush()
else:
message = socks.recv(2048).decode()
print (message)
server.close()
Your client code waits until pressed enter since there is a
sys.stdin.readline() in your client code (Line 17).
sys.stdin.readline() waits for the press of your enter key, since it tries to read a newline from your stdin (Your input), therefore blocking the whole execution of your client application.
What you have to do is using separate threads for:
Recieving messages + print them
Read from stdin (e.g. through sys.stdin.readline() or input()) and send that message to the server like you're already doing
I think the issue is the client's for loop.
sys.stdin.readline() stops the flow until Enter is pressed, so when you send a message from client1, client2 is still waiting for the user to write its own message. Basically since the first item in read_sockets is always socket.socket() every client's first action will be to wait for user input to send a message. The server on the other hand is always listening and never waits, so it receives it immediately.
To solve this you can either have an async connection, meaning you send 1 message then wait to receive 1 message and so on, or use multithreading and dedicate a thread to receiving and one to sending.
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()
I am trying to design a multithreaded server. client1 send data to server and server forwards data to client2 for processing. client2 sends processed data to server and then server forwards it to client1.
Data from client1 is received by client2 through server while execution, but my server program after sending data to client2 terminates with error
[10054] An existing connection was forcibly closed by remote host.
client1.py
from socket import *
import thread
ip='127.1.1.2'
port=5554
s=socket(AF_INET, SOCK_STREAM)
s.connect((ip,port))
data=raw_input("Input lowercase :: ")
while data!="#close":
s.send(data)
data=raw_input("Input next word or type #close to exit: ")
s.close()
client2.py
from socket import *
import thread
ip='127.1.1.2'
port=5554
s=socket(AF_INET, SOCK_STREAM)
s.connect((ip,port))
m=s.recv(1024)
k=m.upper()
print "Uppercase of ",m," in System--> ",k
s.close()
server.py
from socket import *
import thread
ip='127.1.1.2'
port=5554
data=''
def multi_threading(c,a):
while True:
global data
print "Inside client 1 thread"
data= c.recv(1024)
if not data:
break
if "close"==data.rstrip():
break
c.close()
print a,"--terminates connection"
def multi_threading2(c,a):
while True:
print "Inside client 2 thread"
c.send(data)
if not data:
break
if "close"==data.rstrip():
break
c.close()
print a,"--terminates connection"
if __name__=='__main__':
s=socket(AF_INET, SOCK_STREAM)
s.setsockopt(SOL_SOCKET, SO_REUSEADDR,1)
s.bind((ip,port))
s.listen(4)
count=0
while True:
print "Server is listening on port number ",port
c,a=s.accept()
count=count+1
print "--------------------------------------------------"
print "Server connected to system having ip address --> ",a
if(count==1):
thread.start_new_thread(multi_threading,(c,a))
else:
thread.start_new_thread(multi_threading2,(c,a))
What i might be doing wrong?
I'm trying to help by changing your code as little as possible. It isn't how I would write it but should allow you to follow along. This is also not very idomatic Python. I just want you to see how to get the basic interaction going.
Some comments about my changes:
Remove the indent in client1.py so you don't always close the
socket with s.close(). I suspect this was a typo in your post?
In server.py it isn't safe to access the global data between two
threads. At the very least you need a semaphore to protect it.
Every time around multi_threading loop you destroy the last value of
data. You need to append the incoming bytes to a data structure
like a list. I renamed the threads to make it easier to understand.
You are expecting to see close in the server but you don't ever send this because your loop terminates when you type #close. You need to adjust for this.
Your code is order dependent because both client 'sender' and client 'receiver' use the same port. You need to put something into the protocol to distinguish between these two roles so you can start them in either order. This makes the system more robust.
Due to the sender not necessarily having any data I do a crude sleep. This can be avoided by using a shared queue between the threads which would block one end
You need some framing because you can't guarantee the speed at which the independent processes send and receive to the socket. I use \n for this.
There is an edge case if you sent very large strings (and removed the 1024 read) you could not get a full word with the \n through. I ignore this case.
I adjust the loopback address
I wrote this in PyCharm CE. I recommend using an IDE (PyCharm is excellent) with breakpoints. You can step through all the processes bit by bit. Put breakpoints in the threads and step through the actions.
Result:
server.py
from socket import *
import thread
from threading import Lock
import time
ip = '127.0.0.1'
port = 5554
data = []
data_lock = Lock()
def multi_threading_recv(sock, a):
should_run = True
while should_run:
global data
print "Inside client 1 thread"
_data = sock.recv(1024)
if _data:
with data_lock:
for word in _data.split('\n'):
data.append(word)
if "#close" == word:
should_run = False
break
else:
break
sock.close()
print a, "--terminates connection"
def multi_threading_send(sock, a):
while True:
print "Inside client 2 thread"
with data_lock:
if len(data) == 0:
time.sleep(1) # Not ideal. Ideally block on a shared queue
continue
else:
_data = data.pop(0)
if _data == "#close":
break
sock.send(_data + '\n')
c.close()
print a, "--terminates connection"
if __name__ == '__main__':
s = socket(AF_INET, SOCK_STREAM)
s.setsockopt(SOL_SOCKET, SO_REUSEADDR,1)
s.bind((ip,port))
s.listen(4)
count = 0
while True:
print "Server is listening on port number ", port
c, a = s.accept()
print "--------------------------------------------------"
print "Server connected to system having ip address --> ", a
role = c.recv(4)
if role == 'PUSH':
thread.start_new_thread(multi_threading_recv, (c, a))
elif role == 'PULL':
thread.start_new_thread(multi_threading_send, (c,a))
else:
print('invalid role: ' + role)
c.close()
client1.py
from socket import *
ip = '127.0.0.1'
port = 5554
s = socket(AF_INET, SOCK_STREAM)
s.connect((ip,port))
s.send('PUSH')
while True:
data = raw_input("Input word or type #close to exit: ")
s.send(data + '\n')
if data == "#close":
break
s.close()
client2.py
from socket import *
ip = '127.0.0.1'
port = 5554
s = socket(AF_INET, SOCK_STREAM)
s.connect((ip, port))
s.send('PULL')
while True:
data = s.recv(1024)
if data:
words = data.split('\n')
for w in words:
print(w)
else:
break
s.close()
Output:
client1
Input word or type #close to exit: hello
Input word or type #close to exit: world
Input word or type #close to exit: #close
client2:
hello
world
server:
Server is listening on port number 5554
--------------------------------------------------
Server connected to system having ip address --> ('127.0.0.1', 62605)
Server is listening on port number 5554
Inside client 1 thread
('127.0.0.1', 62605) --terminates connection
--------------------------------------------------
Server connected to system having ip address --> ('127.0.0.1', 62614)
Server is listening on port number 5554
Inside client 2 thread
Inside client 2 thread
Inside client 2 thread
('127.0.0.1', 62614) --terminates connection
There is one final comment that the server will go around the loop again and keep on accepting clients. The code doesn't cope with this and I leave it as an exercise for you. You can multiplex multiple senders and receivers if you add a channel number to the PUSH and PULL initiation of the protocol (e.g. PUSH3, PULL3). This will then allow you to store the incoming data in a dictionary keyed by this integer and then send it out to the correct client.
This is probably very simple, but I am having trouble with it.
This is code I am using for the server.
I've searched for this but I only found different kinds of sockets to the one I am using.
server = socket.socket()
server.bind(("localhost", 6969))
server.listen(1)
socket_client, datos_client = server.accept()
print ("Wainting message...")
data = socket_client.recv(1000)
print ("Message:", data)
send1 = bytes("Bye","utf-8")
socket_client.send(send1)
print ("Closing..." )
socket_client.close()
server.close()
And this is the code for the client:
import socket
def main():
my_socket_client = socket.socket()
my_socket_client.connect(("localhost", 6969))
bufsize = 1000
print("Send message")
message=input()
data2 = bytes(mensaje,"utf-8")
#enviar los datos
my_socket_client.send(data2)
data_received= my_socket_client.recv(bufsize)
print (data_received)
I am not sure what your problem is since you didn't ask a question so i will just show you a client + basic command server that i have built in the same way you built yours you said "I only found different kinds of sockets to the one I am using." so i hope this is what you are looking for
Here is an example of a simple command server:
if you run the server code and then run the client you will be able to type in the client and send to the server. if you type TIME you will get from the server a respons which contains a string that has the date of today and the other commands work in the same way. if you type EXIT it will close the connection and will send from the server the string closing to the client
server:
import socket
import random
from datetime import date
server_socket = socket.socket() # new socket object
server_socket.bind(('0.0.0.0', 8820)) # empty bind (will connect to a real ip later)
server_socket.listen(1) # see if any client is trying to connect
(client_socket, client_address) = server_socket.accept() # accept the connection
while True: # main server loop
client_cmd = client_socket.recv(1024) # recive user input from client
# check waht command was entered
if client_cmd == "TIME":
client_socket.send(str(date.today())) # send the date
elif client_cmd == "NAME":
client_socket.send("best server ever") # send this text
elif client_cmd == "RAND":
client_socket.send(str(random.randrange(1,11,1))) # send this randomly generated number
elif client_cmd == "EXIT":
client_socket.send("closing")
client_socket.close() # close the connection with the client
server_socket.close() # close the server
break
else :
client_socket.send("there was an error in the commend sent")
client_socket.close() # just in case try to close again
server_socket.close() # just in case try to close again
client:
import socket
client_socket = socket.socket() # new socket object
client_socket.connect(('127.0.0.1', 8820)) # connect to the server on port 8820, the ip '127.0.0.1' is special because it will always refer to your own computer
while True:
try:
print "please enter a commend"
print "TIME - request the current time"
print "NAME - request the name of the server"
print "RAND - request a random number"
print "EXIT - request to disconnect the sockets"
cmd = raw_input("please enter your name") # user input
client_socket.send(cmd) # send the string to the server
data = client_socket.recv(1024) # recive server output
print "the server sent: " + data # print that data from the server
print
if data == "closing":
break
except:
print "closing server"
break
client_socket.close() # close the connection with the server
you have a typo .
edit this line in client from
data2 = bytes(mensaje,"utf-8")
to
data2 = bytes(message,"utf-8")
I tried your code, and made a couple of changes:
Server side:
import socket
server = socket.socket()
server.bind(("localhost", 6969))
server.listen(1)
socket_client, datos_client = server.accept()
print ("Waiting message...")
data = socket_client.recv(1000)
print ("Message:", data )
# Same change made as with client side
send1 = bytes("Bye") #,"utf-8")
socket_client.send(send1)
print ("Closing..." )
socket_client.close()
server.close()
Client side:
import socket
my_socket_client = socket.socket()
my_socket_client.connect(("localhost", 6969))
bufsize = 1000
print("Send message")
# I changed it to raw_input(); input() does not for string input with python 2.7
message=raw_input()
# Are you trying to encode the message? To make it simple, skip it
data2 = bytes(message) # ,"utf-8")
#enviar los datos
my_socket_client.send(data2)
data_received= my_socket_client.recv(bufsize)
print (data_received)
Sample output from server side:
Waiting message...
('Message:', 'message from client')
Closing...
Sample output from client side:
Send message
message from client
Bye