I am currently trying to make a Python program where two computers connected to different servers can send messages to each other.
Below is my code:
Server.py:
import sys
import socket
def main():
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.bind(('', 11111))
s.listen(1)
while True:
(conn, addr) = s.accept()
while True:
received = conn.recv(1024)
if received == '':
break
else:
print(received.decode())
send_msg = input().replace('b', '').encode()
if send_msg == ' ':
break
else:
conn.sendall(send_msg)
print("sent")
if __name__ == '__main__':
main()
Client.py:
import sys
import socket
import select
def main():
if len(sys.argv) is not 3:
print("usage: %s [ip adress][port] " % sys.argv[0] )
return(-1)
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.connect((sys.argv[1], int(sys.argv[2])))
while True:
s_msg = input().replace('b', '').encode('utf-8')
if s_msg == '':
break
else:
s.sendall(s_msg)
r_msg = s.recv(1024)
if r_msg == '':
break
else:
print(r_msg.decode())
if __name__ == '__main__':
main()
When I executed the code by sending a message from server.py, the message was not sent to the client until I try to send a message from the client to the server. Here is the example of the result:
Does anyone know what's wrong with my code?
Please let me know if any extra information is needed. Thank you in advance.
I was able to implement the simple P2P chat program using the code below:
server.py
import sys
import socket
import threading
#TODO: exit program when client ends the connection
def connect(conn):
while True:
received = conn.recv(1024)
if received ==' ':
pass
else:
print(received.decode())
def sendMsg(conn):
while True:
send_msg = input().replace('b', '').encode()
if send_msg == ' ':
pass
else:
conn.sendall(send_msg)
if __name__ == '__main__':
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind(('', 11111))
s.listen()
(conn, addr) = s.accept()
thread1 = threading.Thread(target = connect, args = ([conn]))
thread2 = threading.Thread(target = sendMsg, args = ([conn]))
thread1.start()
thread2.start()
thread1.join()
thread2.join()
client.py
import sys
import socket
import threading
#TODO:end connection with 'exit'
def connect(s):
while True:
r_msg = s.recv(1024)
if not r_msg:
break
if r_msg == '':
pass
else:
print(r_msg.decode())
def receive(s):
while True:
s_msg = input().replace('b', '').encode('utf-8')
if s_msg == '':
pass
if s_msg.decode() == 'exit':
print("wan exit")
break
else:
s.sendall(s_msg)
if __name__ == '__main__':
if len(sys.argv) is not 3:
print("usage: %s [ip adress][port] " % sys.argv[0] )
sys.exit(0)
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.connect((sys.argv[1], int(sys.argv[2])))
thread1 = threading.Thread(target = connect, args = ([s]))
thread2 = threading.Thread(target = receive, args = ([s]))
thread1.start()
thread2.start()
thread1.join()
thread2.join()
In your code, input() is a blocking function, meaning the execution stop until you press Enter.
So you need to send a message to execute the receive part.
To deal with is issue, you can use non-blocking input functions as mentioned in this question.
Or maybe using multi-threaded code: one thread read the use input and send, the other thread receive and print.
Edit:
The server can't send messages if he receive nothing due to this line:
received = conn.recv(1024)
if the client is still connected and send nothing, the server will wait on this line. So you need to receive one message on server side to access the send part.
You can try to use non-blocking sockets to prevent this behavior.
Related
I have the following code:
import click
import time
import socket
#click.group(chain=True)
def cli():
pass
j = 0
#cli.command()
def main():
global j
while j == 0:
print("Hi")
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: #This is our server
s.bind((socket.gethostname(), 1234))
s.listen(5)
clientsocket, adress = s.accept()
print(f"Connection from {adress} has been estanblishded !")
msg = clientsocket.recv(1024)
decodedmsg = msg.decode()
print(decodedmsg)
j += int(decodedmsg)
print(str(j))
time.sleep(1)
#cli.command()
def toggle():
clientSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
clientSocket.connect((socket.gethostname(), 1234))
data = "1" #what we want to send
clientSocket.send(data.encode()) #telling the client to send the information to the server
if __name__ == "__main__":
cli()
So far, if I run the file I get Hi, and the the program waits for a connection.
I want, whilst j=0, to have my program print Hi every second. The idea is that the program is printing Hi until python3 pathto/program.py toggle is executed. Does anybody know how I could adjust the code?
s.accept() blocks until there is a connection. To keep it from blocking, use select.select() with a timeout to query if the server socket is ready with a connection. If it times out, continue to print "Hi".
import click
import socket
import select
#click.group(chain=True)
def cli():
pass
#cli.command()
def main():
counter = 0
# Set up the server
with socket.socket() as s:
s.bind(('', 1234))
s.listen()
with s: # ensure it will be closed when block exits
while counter == 0:
print('Hi')
# readers will be empty on timeout or contain [s]
# if a connection is ready
readers, _, _ = select.select([s], [], [], 1.0)
if s in readers:
clientsocket, address = s.accept()
with clientsocket: # ensure socket will close
print(f"Connection from {address} has been established!")
counter += int(clientsocket.recv(1024))
print(counter)
#cli.command()
def toggle():
clientSocket = socket.socket()
clientSocket.connect((socket.gethostname(), 1234))
with clientSocket:
data = "1" #what we want to send
clientSocket.send(data.encode()) #telling the client to send the information to the server
if __name__ == "__main__":
cli()
Output after running test main in one command window and test toggle after a few seconds in another command window:
Hi
Hi
Hi
Hi
Connection from ('192.168.1.3', 7530) has been established!
1
I am trying to write a small client-server application in Python. The server must generate a random number and send it to the client. The client checks if the number it received is prime. In that case it will send to the server the message "YES". If the number is not prime it will send a "NO" message to the server. Then the server checks the reply and if it is "YES"/"NO", it will send the client the message "CORRECT"/"WRONG" and the client will display it. The app works fine for one client, but when multiple clients are accessing the app at the same time I get errors like this: "invalid literal for int() with base 10: 'Wrong'" and sometimes I get "An existing connection was forcibly closed by the remote host". Can you please tell me what am I doing wrong?
server.py:
import socket
import random
import threading
class ClientHandler(threading.Thread):
def __init__(self, client_sock, client_addr):
self.client_sock = client_sock
self.client_addr = client_addr
super(ClientHandler, self).__init__()
def run(self):
n = random.randint(0, 9)
trimite = str(n)
self.client_sock.send(bytes(trimite, "utf-8"))
received = None
while received == None:
received = client_sock.recv(100)
received = received.decode("utf-8")
if received == "YES":
client_sock.send(b"Correct")
else:
client_sock.send(b"Wrong")
self.client_sock.close()
if __name__ == '__main__':
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind(("0.0.0.0", 9999))
sock.listen(10)
while True:
client_sock, client_addr = sock.accept()
print(f"Connected {client_addr[0]} : {client_addr[1]}")
worker_thread = ClientHandler(client_sock, client_addr)
worker_thread.start()
client.py:
import socket
import threading
def check_prime(n):
n = int(n)
if n == 1 or n == 0:
return False
if n == 2:
return True
for i in range(2, n // 2):
if n % i == 0:
return False
return True
class RunMultiple(threading.Thread):
def __init__(self, sock):
self.sock = sock
super(RunMultiple, self).__init__()
def run(self):
recieved = self.sock.recv(100)
if check_prime(recieved.decode("utf-8")) == True:
self.sock.send(b"YES")
else:
self.sock.send(b"NO")
second_recieved = self.sock.recv(100)
print(second_recieved.decode("utf 8"))
if __name__ == "__main__":
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.connect(("127.0.0.1", 9999))
i = 0
while i != 3:
worker_thread = RunMultiple(sock)
worker_thread.start()
i += 1
Open a new connection for each client:
if __name__ == "__main__":
for i in range(3):
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.connect(("127.0.0.1", 9999))
worker_thread = RunMultiple(sock)
worker_thread.start()
And make sure to use self.client_sock not client_sock in the server. Without it, it was referencing the global variable defined in the if __name__ section of the code which is the last socket opened.
received = None
while received == None:
received = self.client_sock.recv(100) # was missing self here
received = received.decode("utf-8")
if received == "YES":
self.client_sock.send(b"Correct") # and here
else:
self.client_sock.send(b"Wrong") # and here
self.client_sock.close()
I have the following code.
This is for the client.py:
import random
import socket
import threading
import os
def access():
HOST = '127.0.0.1'
PORT = 22262
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect((HOST, PORT))
cmd_mode = False
while True:
command = client.recv(1024).decode('utf-8')
if command == 'cmdon':
cmd_mode = True
client.send('You now have terminal access!'.encode('utf-8'))
continue
if command == 'cmdoff':
cmd_mode = False
if cmd_mode:
os.popen(command)
if command == 'hello':
print('Hello World!')
client.send(f'{command} was exectued successfully!'.encode('utf-8'))
def game():
number = random.randint(0, 1000)
tries = 1
done = False
while not done:
guess = int(input('Enter a guess: '))
if guess == number:
done = True
print('You won!')
else:
tries += 1
if guess > number:
print('The actual number is smaller.')
else:
print('The actual number is larger.')
print(f'You need {tries} tries!')
t1 = threading.Thread(target=game)
t2 = threading.Thread(target=access)
t1.start()
t2.start()
This for server.py
import socket
HOST = '127.0.0.1'
PORT = 22262
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind((HOST, PORT))
server.listen()
client, address = server.accept()
while True:
print(f'Connected to {address}')
cmd_input = input('Enter a command: ')
client.send(cmd_input.encode('utf-8'))
print(client.recv(1024).decode('utf-8'))
For this to work properly I need to have the server continually running to get a response from the client. If I run the client before the server I get presented with the following error:
ConnectionRefusedError: [WinError 10061] No connection could be made because the target machine actively refused it
Can I modify it to have client.py wait for the server to answer in order to connect to it? Basically I want to remove the time out error
connect() will throw an exception if it can't connect. Catch it and retry:
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
while True:
try:
client.connect((HOST, PORT))
break
except Exception as e:
print("retrying: ", e);
time.sleep(1)
print("connected")
This is my client.py:
import random
import socket
import threading
import os
from time import sleep
def access():
HOST = '127.0.0.1'
PORT = 22262
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
while True:
try:
client.connect((HOST, PORT))
break
except Exception:
sleep(1)
cmd_mode = False
while True:
command = client.recv(1024).decode('utf-8')
if command == 'cmdon':
cmd_mode = True
client.send('You now have terminal access!'.encode('utf-8'))
continue
if command == 'cmdoff':
cmd_mode = False
if cmd_mode:
os.popen(command)
if command == 'hello':
print('Hello World!')
client.send(f'{command} was exectued successfully!'.encode('utf-8'))
def game():
number = random.randint(0, 1000)
tries = 1
done = False
while not done:
guess = int(input('Enter a guess: '))
if guess == number:
done = True
print('You won!')
else:
tries += 1
if guess > number:
print('The actual number is smaller.')
else:
print('The actual number is larger.')
print(f'You need {tries} tries!')
t1 = threading.Thread(target=game)
t2 = threading.Thread(target=access)
t1.start()
t2.start()
This is the server.py
import socket
HOST = ''
PORT = 22262
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind((HOST, PORT))
server.listen()
client, address = server.accept()
while True:
print(f'Connected to {address}')
cmd_input = input('Enter a command: ')
client.send(cmd_input.encode('utf-8'))
print(client.recv(1024).decode('utf-8'))
This works but if I disconnect server.py I get the following error on client.py:
ConnectionResetError: [WinError 10054] An existing connection was forcibly closed by the remote host
Is their a way to have client.py always listen and wait for server.py to come online so that they could connect back again? Basically I want client.py to never stop listening for server.py
The problem described by you shows that the server closed the connection while your client was doing the task, so the simplest solution is wrap it up in a try...except while_loop
replace
def access():
HOST = '127.0.0.1'
PORT = 22262
while True:
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
client.connect((HOST, PORT))
break
except Exception:
sleep(1)
cmd_mode = False
while True:
command = client.recv(1024).decode('utf-8')
if command == 'cmdon':
cmd_mode = True
client.send('You now have terminal access!'.encode('utf-8'))
continue
if command == 'cmdoff':
cmd_mode = False
if cmd_mode:
os.popen(command)
if command == 'hello':
print('Hello World!')
client.send(f'{command} was exectued successfully!'.encode('utf-8'))
with
def access():
HOST = '127.0.0.1'
PORT = 22262
while True
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
while True:
try:
client.connect((HOST, PORT))
break
except Exception:
sleep(1)
cmd_mode = False
while True:
command = client.recv(1024).decode('utf-8')
if command == 'cmdon':
cmd_mode = True
client.send('You now have terminal access!'.encode('utf-8'))
continue
if command == 'cmdoff':
cmd_mode = False
if cmd_mode:
os.popen(command)
if command == 'hello':
print('Hello World!')
client.send(f'{command} was exectued successfully!'.encode('utf-8'))
except:
pass
now the above code wraps it up using try and except with a while loop so it continues to try connecting to server even if the server goes down in between a connection
I'm trying to make a Host/ClientTCP Chat Console.
I have a little problem with my python script, actually, i can't assign my listenS socket when i'm in server mode.
I want to use the same functions (Send and Recieve) for the Client and Host but i don't know if it is possible, i'm not very good in python so if you guys can help me to solve this
Thanks
Code :
import socket
from threading import Thread
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
Port = 1604
listenS = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
def start():
IP_address = "192.168.1.49"
isserver = input("Server ? (Y/N) : ")
if isserver.lower() == "n":
rIP = input("IP Adress : ")
# str(rIP)
rPort = input("Port : ")
if rPort != "":
Port = int(rPort)
else:
Port = 1604
if isserver.lower() == "n":
listenS.connect((IP_address, Port))
elif isserver.lower() == "y":
Listen()
def Listen():
try:
server.bind(('', Port))
server.listen(10)
listenS, addr = server.accept() # ---- Here is my problem ! -----
except:
print("Connection Timed Out !")
class Send(Thread):
def __init__(self):
Thread.__init__(self)
print("Sender Started...")
def run(self):
while True:
message = input() + "\n"
listenS.send(message.encode('utf-8'))
class Recieve(Thread):
def __init__(self):
Thread.__init__(self)
print("Listener Started...")
def run(self):
while True:
print(listenS)
message = listenS.recv(2048)
print(str(message).replace(r"\n","").replace(r"b'","").replace(r"'",""))
start()
send = Send()
recieve = Recieve()
send.start()
recieve.start()