I'm new to socket programming in Python and I'm trying to write a chatroom application, but I have a problem which is it each client should press enter in order to receive messages from other clients.
#my client side code
import socket
import sys
client_sock = socket.socket()
port = int(sys.argv[1])
client_sock.connect(('127.0.0.1', port))
print("Connected to server. start sending messages")
while True:
sending_message = input('> ')
if sending_message:
client_sock.send(sending_message.encode())
receiving_message = client_sock.recv(1024)
if receiving_message:
print(receiving_message.decode())
input pauses your program. Thus, either you can't use input blindly, or you have to use threads. Using threads is easier than the alternative (using select to figure out what to do next). Have one thread for input and sending, one thread for receiving and printing.
Here's a trivial rewrite of your code:
import threading
import socket
import sys
client_sock = socket.socket()
port = int(sys.argv[1])
client_sock.connect(('127.0.0.1', port))
print("Connected to server. start sending messages")
def sender():
while True:
sending_message = input('> ')
if sending_message:
client_sock.send(sending_message.encode())
def receiver():
while True:
receiving_message = client_sock.recv(1024)
if receiving_message:
print(receiving_message.decode())
sender_thread = threading.Thread(target=sender)
receiver_thread = threading.Thread(target=receiver)
sender_thread.start()
receiver_thread.start()
sender_thread.join()
receiver_thread.join()
Related
Hi I am trying to create a very simple peer-to-peer chatting program in python. The first user can runs the server.py program below to bind to a socket.
import sys
import socket
import select
import threading
# Bind to socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind(('127.0.0.1', 11111))
s.listen()
def chat(conn, addr):
# Set blocking to false so that program can send and receive messages at the same time
conn.setblocking(0)
# Receive messages using select
while conn in select.select([conn], [], [], 0)[0]:
text = conn.recv(4096)
if text:
print("{}: {}".format(addr, text))
else:
return
# get user input and send message
while True:
msg = input(">>>")
conn.send(msg.encode())
if __name__ == '__main__':
## Accept connections and start new thread
(conn, addr) = s.accept()
threading.Thread(target=chat, args=([conn, addr])).start()
Then another user can use netcat to connect to the server and communicate. However, the program is only able to get the user's input and send to the other side. The user from the other side is unable to send messages.
input() blocks, so you are falling through your chat function and entering the input() loop and never checking for receiving again. Receive on the thread and enter the input loop on the main thread. TCP is full duplex so you can send/recv at the same time on two threads without turning off blocking.
I also needed to add a newline to the send() as my netcat was line-buffering.
import socket
import threading
# Bind to socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind(('', 11111))
s.listen()
def chat(conn, addr):
while True:
text = conn.recv(4096)
if not text: break
print("{}: {}".format(addr, text))
if __name__ == '__main__':
## Accept connections and start new thread
conn, addr = s.accept()
threading.Thread(target=chat, args=(conn, addr), daemon=True).start()
# get user input and send message
while True:
msg = input(">>>")
conn.sendall(msg.encode() + b'\n')
So I'm trying to create a python script that will allow multiple TCP connections from different computers and allow talking over the serial from the TCP client. Here is what I was playing with
import sys
import os
import time
import fileinput
import socket
import serial
import thread
serialData = serial.Serial('/dev/ttyS0',9600)
import argparse
def on_new_client(clientsocket,addr):
while True:
msg = clientsocket.recv(1024)
#do some checks and if msg == someWeirdSignal: break:
print addr, ' >> ', msg
serialData.write(msg)
#msg = raw_input('SERVER >> ')
#Maybe some code to compute the last digit of PI, play game or
anything else can go here and when you are done.
clientsocket.send(msg)
clientsocket.close()
def on_Send_client(clientsocket,addr):
while True:
x = serialData.readline()
clientsocket.send(x)
clientsocket.close()
s = socket.socket()
host = '' #ip of raspberry pi
port = 12345
s.bind((host, port))
s.listen(5)
serialData.isOpen()
serialData.write("This is a test")
while True:
c, addr = s.accept()
thread.start_new_thread(on_new_client,(c,addr))
#thread.start_new_thread(on_Send_client,(c,addr))
s.close()
Right now I can connect with multiple TCP clients and eco their data. Their data also gets sent out the serial port. How should I go about buffering the serial data and sending it back out any and all connections that are active? Seems like nothing I look for online can do this correctly and Socat command even fails for multiple connections to serial.
Consider the following example.
from socket import *
msg = input("Please enter your name ")
msg = msg.encode()
myHostIp = ''
myHostPort = 54040
socket_obj = socket(AF_INET, SOCK_STREAM)
socket_obj.bind((myHostIp,myHostPort))
socket_obj.listen(5)
while True:
connection,address = socket_obj.accept()
print("Client : ",address)
connection.send(msg)
print(socket.getsockname(socket_obj))
print(socket.getsockname(connection))
print(socket.getpeername(socket_obj))
print(socket.getpeername(connection))
while True:
data = connection.recv(1024)
print("This was received from ", data)
connection.close()
In this simple program the output of line print(socket.getsockname(socket_obj)) was (0.0.0.0)
and of the print(socket.getpeername(socket_obj)) was socket_obj is not connected.
My question is: once connection,address = socket_obj.accept() is executed, is the control from socket_obj transferred to connection?
The socket you call .listen() on is a server socket; about all you can do with it is to call .accept() to produce a client socket, which handles all actual communications. One server socket can produce any number of client sockets over its lifetime.
I am trying to make a server-client program using threads to handle each client, but the server will only accept one client at a time. If the first client disconnects, then the second client is accepted. Furthermore, each client can only send data once, then the program fails to send any more.
Prior to posting, I have looked at MANY other Stack Overflow posts, including the following:
how can I make a server communicate with more than 1 client at the same time?
python multithreaded server
My Python socket server can only receive one message from the client
But through looking at these posts I have found no solution.
Here is the server code:
import socket
from threading import *
def main():
s=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(('172.20.3.62', 5000))
s.listen(1)
clients = []
print("listening")
def clienthandler(c):
clients.append(c)
try:
while True:
data = c.recv(1024).decode("UTF-8")
if not data:
break
else:
print(data)
for client in clients:
client.send(data.encode("UTF-8"))
except:
clients.remove(c)
c.close()
while True:
c, addr = s.accept()
print("accepted a client")
Thread(target=clienthandler(c)).start()
if __name__ == '__main__':
main()
Here is the client code:
import socket
from threading import *
def main():
s=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('172.20.3.62', 5000))
print("connected")
def send():
msg = input("ENTER:")
s.send(msg.encode("UTF-8"))
def receive():
while True:
data = s.recv(1024).decode("UTF-8")
if data:
print(data)
else:
break
Thread(target=send).start()
Thread(target=receive).start()
if __name__ == '__main__':
main()
Thanks to user Rawing. His/Her solution was: Thread(target=clienthandler(c)) -> Thread(target=clienthandler, args=(c,))
This allowed for more than one thread, and I was able to solve the only one message problem by putting the client send block in a while loop.
I am trying to make a group chat program, where an unlimited amount of clients may join the server using the same script, it'll work by the server receiving the clients message and sending it to all the connected clients including the sender. I have only managed to make it so that the sender only gets his own message back, but not what another client sends.
I was thinking of storing all the connected client IP's in a list, and sending it to each IP, but I do not know how to change the recpient of socket.send
Server code:
from threading import *
import socket
s = socket.socket()
host = socket.gethostbyname(socket.gethostname())
port = 1337
s.bind((host, port))
s.listen(5)
print("Server host is", host)
def getMainThread():
for thread in enumerate():
if thread.name == 'MainThread':
return thread
return None
class client(Thread):
def __init__(self, socket, address):
Thread.__init__(self)
self.socket = socket
self.address = address
self.start()
def run(self):
main = getMainThread()
while main and main.isAlive():
print(self.address, "has connected!")
message = self.socket.recv(8192).decode('utf-8')
self.socket.send(bytes(message, 'UTF-8'))
self.socket.close()
while True:
c, addr = s.accept()
client(c, addr)
clients = [] #list for all client IP's
clients.append(addr)
Also, is there a way so that the client can establish a connection with the server so it doesn't keep poping up on the server.py that client has connected each time it sends a message?
Client code:
import socket
import os
import sys
host = '25.154.84.23'
print("""
=======================================================
=Welcome to Coder77's local internet messaging service=
=======================================================
The current soon to be encrypted server is {0}
You can enter the command /help for a list of commands available
""".format(host))
#username = input("Enter username: ")
username = 'Smile'
print("Now connecting to {0}....".format(host))
def printhelp():
print("""
The following commands are in the current version of this program:
/clear to clear the screen
/username to change your username
/exit to exit
/help for a list of commands
""")
def main():
global username
global host
sock = socket.socket()
try:
sock.connect((host, 1337))
while True:
message2 = input("{0}: ".format(username))
message = ('{0}: {1}'.format(username,message2))
if '/quit' in message:
sys.exit()
if '/clear' in message:
os.system('cls')
if '/help' in message:
printhelp()
if '/username' in message:
username = input("What would you like as your new username? ")
sock.send(bytes(message, 'UTF-8'))
received = sock.recv(8192).decode('utf-8')
print(received)
except socket.error:
print("Host is unreachable")
if __name__ == '__main__':
main()
#
Corrected Server code:
import sys
print(sys.version)
from threading import *
import socket
s = socket.socket()
host = socket.gethostbyname(socket.gethostname())
port = 1337
s.bind((host, port))
s.listen(5)
print("Server host is", host)
def getMainThread():
for thread in enumerate(): # Imported from threading
if thread.name == 'MainThread':
return thread
return None
class Client(Thread):
def __init__(self, socket, address):
Thread.__init__(self)
self.socket = socket
self.address = address
self.start()
def run(self):
main = getMainThread()
print(self.address, "has connected!")
while main and main.isAlive():
message = self.socket.recv(8192).decode('utf-8')
print(message)
self.socket.send(bytes(message, 'UTF-8'))
for each_client in clients:
each_client.socket.send(bytes(message, 'UTF-8'))
while True:
c, addr = s.accept()
this_client = Client(c, addr)
clients = []
clients.append(this_client)
The new code, adapted by gravetii is causing a lot of format errors. What happens now, is the user gets back what he sent, he does not get back what other users send and the user gets back what his previous message was, its terribly confusing. Please run the code, and you'll see as it's very hard to explain.
Example
In your server code, you are doing only a self.socket.send(bytes(message, 'UTF-8')). How can you then expect the server to send the message to all the clients? To do that you would need to iterate through the list of clients and call the send() method on each of their sockets.
while True:
c, addr = s.accept()
client(c, addr)
clients = [] #list for all client IP's
clients.append(addr)
In this code, you are creating a client object but never adding it to the list, then what's the point of creating one?
I think what you want is this:
while True:
c, addr = s.accept()
this_client = client(c, addr)
clients = [] #list for all client IP's
clients.append(this_client)
Then, you can send the message to all the clients by modifying the relevant part of your server code:
def run(self):
main = getMainThread()
while main and main.isAlive():
print(self.address, "has connected!")
message = self.socket.recv(8192).decode('utf-8')
self.socket.send(bytes(message, 'UTF-8'))
for each_client in clients:
each_client.socket.send(bytes(message, 'UTF-8'))
Also, why are you closing the connection after sending just one message? I believe your intention is to send more than one message to the server, and in that case, you don't need to close the connection.
Also, it's a better idea to create a class with its name starting with an upper case letter. So you may want to use Client instead of client for the class name.
Now coming to the issue of the message popping up everytime a client says something in your server.py, look at the run() method for the client thread:
def run(self):
main = getMainThread()
while main and main.isAlive():
print(self.address, "has connected!")
message = self.socket.recv(8192).decode('utf-8')
self.socket.send(bytes(message, 'UTF-8'))
The thread starts executing as soon as you create the client object, and so the first time when it connects to the server, it is right in showing that message. But then it's incorrect to place the print(self.address, "has connected!") in the while loop. So everytime the client says something, the server sends it back to the client and then the loop runs again, thus displaying the message back again. You need to modify it like so:
def run(self):
print(self.address, "has connected!")
main = getMainThread()
while main and main.isAlive():
message = self.socket.recv(8192).decode('utf-8')
self.socket.send(bytes(message, 'UTF-8'))
Hope this helps!