Python Socket - Send/Receive messages at the same time - python

Basically I have been working on a simple chat room using socket and thread. In my client I can receive and send messages, my issue is that one comes before another in a loop, so if I am sending a message I will only receive data once I have sent a message. I want it to work like any other chat room, where I could receive a message when I am sending a message, any help will help greatly. This is my basic client:
import socket
import sys
###########
HOST = '25.0.18.52'
PORT = 9999
###########
name = input("Enter your name: ")
s = socket.socket()
s.connect((HOST,PORT))
while 1:
message = input("Message: ")
s.send("{}: {}".format(name, message).encode('utf-8'))
data = s.recv(1024)
a = data.decode("utf-8")
print(a)

You should keep 2 threads: one for listening and the other for receiving. In your while loop, you should remove the listener part, and keep the code in a different thread. This way you can receive and type on the console at the same time.
def recv():
while True:
data = s.recv(1024).decode()
if not data: sys.exit(0)
print data
Thread(target=recv).start()

Related

Client that communicates with multiple servers concurrently

I am trying to learn multithreading programming with Python and specifically I am trying to build a programm that 1 Client sends data to multiple servers and get some messages back. In the first version of my programm I want my client to communicate back and forth with each server that I have spawned with each thread, till I type 'bye'. Now I have 2 issues with my implementation that I don't understand how to deal with. The first one is that I don't want the connection with the server to close after I type 'bye' (I want to add extra functionality after that) and the second one is that the servers doesn't get the messages that I type at the same type but I can communicate with the second server only if the first thread terminates (which as I said, I don't want to terminate). Any suggestions would be appreciated. Cheers!
Client.py
import sys
import threading
from _thread import *
import socket
host_1 = '127.0.0.1'
port_1 = 6000
host_2 = '127.0.0.2'
port_2 = 7000
def connect_to_server(host, port):
client_socket = socket.socket() # instantiate
client_socket.connect((host, port)) # connect to the server
message = input(" -> ") # take input
while message.lower().strip() != 'bye':
client_socket.send(message.encode()) # send message
data = client_socket.recv(1024).decode() # receive response
print('Received from server: ' + data) # show in terminal
message = input(" -> ") # again take input
threads_dict = {}
th_1 = threading.Thread(target=connect_to_server, args=(host_1, port_1))
th_2 = threading.Thread(target=connect_to_server, args=(host_2, port_2))
th_1.start()
th_2.start()
th_1.join()
th_2.join()
Server.py
import socket
import sys
def server_program():
host = sys.argv[1] # '127.0.0.1', '127.0.0.2'
port = int(sys.argv[2]) # 6000, 7000
server_socket = socket.socket() # get instance
server_socket.bind((host, port)) # bind host address and port together
# configure how many client the server can listen simultaneously
server_socket.listen(2)
conn, address = server_socket.accept() # accept new connection
print("Connection from: " + str(address))
while True:
# receive data stream. it won't accept data packet greater than 1024 bytes
data = conn.recv(1024).decode()
if not data:
# if data is not received break
break
print("from connected user: " + str(data))
data = input(' -> ')
conn.send(data.encode()) # send data to the client
if __name__ == '__main__':
server_program()

Is there any way to send a message to everyone except the sender?

This question is similar to this one, but that was for JavaScript whereas mine is for Python.
How do I send a message to every connected client from the server except a selected client in Python using the sockets library?
I am making a simple game, where I want to detect the first person to press a button among three clients, and then notify the other two clients that they lost while notifying the winner that they won.
Usually, to send information to a client you do (on a new thread):
connected_client.sendall(data)
To receive, you do:
data = socket.recv()
But from what I searched, I couldn't find a way to send data to every connected client except a certain client.
I thought I could get around this by creating an 'identifying name' for each thread which ran the receiving function, but I couldn't find a good way to do this due to which I decided to search for a better option.
How can I do this?
Inserting them into a list can help. For example...
For the server side:
import socket
import threading
# This is where you store all of your Client IP's
client_list = []
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_ip = "yourip"
server_port = 8888
server.bind((server_ip, server_port))
def check_client(client_ip):
while True:
data = client_ip.recv(1024).decode()
if "condition" in data:
for ip in client_list:
if ip != client_ip:
ip.send("something".encode())
def check_connection():
server.listen()
while True:
client_ip, client_address = server.accept()
client_list.append(client_ip)
threading.Thread(target=check_client, args=(client_ip,), daemon=True).start()
check_connection()
So what happens is you call the check_connection function to check for incoming connections. After it receives one, it appends the connection inside the client_list variable. At the same time, it creates a thread to the current connection, check_client, which checks for any info being sent. If there's an info being sent by one of your clients, it checks if the "condition" string is inside your sent data. If so, it sends "something" string into all of your clients with exception to itself. Take note that when you send data, it must be in bytes.
For the client side:
import socket
import threading
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_ip = "serverip"
server_port = 8888
server.connect((server_ip, server_port))
def receive_info():
while True:
data = server.recv(1024).decode()
if "something" in data:
print("Someone already sent something")
threading.Thread(target=receive_info, daemon=True).start()
while True:
user_input = input("Type 'condition': ")
server.send(user_input.encode())
What this only does is, it sends your input into the server. If you typed "condition" on your input, it will send "something" on the other clients except you. So you need to setup 2 more clients in order to see the results.
Don't forget to set server_ip and server_port's values!

python socket recv in multithread

I have python script with only one socket object that is connect to a java server.
I started a thread for sending heart beat message to server per 5 secs.
And another thread for receiving message from server.
BTW, all the data send/recv is in protobuffer format.
# socket_client.py
def recv_handler():
global client_socket
while True:
try:
# read 4 bytes first
pack_len = client_socket.recv(4)
pack_len = struct.unpack('!i', pack_len)[0]
# read the rest
recv_data = client_socket.recv(pack_len)
# decode
decompressed_data = data_util.decompressMessage(recv_data)
sc_pb_message = data_util.decodePBMessage(decompressed_data)
sc_head = data_util.parseHead(sc_pb_message)
except:
print 'error'
def heart_handler():
global client_socket
while True:
if client_socket:
message = data_util.makeMessage('MSG_HEART_BEAT')
compressed_data = data_util.compressMessage(message)
send_data = data_util.makeSendData(compressed_data)
try:
client_socket.send(send_data)
except:
print 'except'
pass
time.sleep(5)
def connect(address, port):
global client_socket
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client_socket.connect((address, port))
# thread sending heart beat message
th = threading.Thread(target = heart_handler)
th.start()
# thread recving message
tr = threading.Thread(target = recv_handler)
tr.start()
The code above works just fine. The script will send a heart beat message per 5 secs and receive the message from server and the message can be decoded successfully.
And here comes the trigger part than I do not know how to implement.
My python script need to receive input from the browser at the same time, so I started a BaseHTTPServer, to handle the POST request from the browser.
When a request come, I would like to call the client_socket.send method to send a specific message to the server and of course I need to return the data from server back to the browser.
# http_server.py
def do_POST(self):
# ...
result = socket_client.request(message)
self.send_response(200)
self.end_headers()
self.wfile.write(...)
And here is what I tried to do in request:
def request(message):
global client_socket
client_socket.send(message)
pack_len = client_socket.recv(4)
pack_len = struct.unpack('!i', pack_len)[0]
recv_data = client_socket.recv(pack_len)
return recv_data
The problem I am having is the data I received in the request method after calling the send method seems to be disturbed by the data of heart beat in the thread.
If I comment out the heart beat thread and the receive thread, than the request method will work just fine. The data from server can decoded with no error and it can be sent back to the browser successfully.
My solution now might be wrong and I really do not know how to get this work.
Any advice will be appreciated, thanks :)
socket object in Python is not thread-safe, you need to access the shared resources (in this case the client_socket object) with the help of some synchronization primitives, such as threading.Lock in Python 2. Check here for a similar problem: Python: Socket and threads?

Client socket not receiving data correctly

I've tried looking about for an answer but I can't seem to find one that answers my specific problem.
Perhaps I don't know how to articulate the problem correctly.
I think I've pinpointed what it is, but the thing is I just don't know how to fix it.
EDIT: I was trying to use two clients on one TCP Socket. Can't do that. I'll have to think of another way. Solved, I guess.
So what I've got is are
1: Two Clients
2: One Server
The objective is this:
Have the server distribute new usernames to all the clients as they connect.
This is what happens when I run the program:
Server: Define Host, and Port, initialize it. Check
Client 1: Connects to the server. Check
Client 1: Once connected, sends a string to the server. Check
Server: Receives a string, checks if the string is in a list is created. If it is: Pass, if it's not, send to everyone the new string. Check
Client 1: [Now waiting to receive data] Recieves data, checks if the string received matches the one it sent. If it does, print("It's one of ours!"), else, make the new string = to Client 2 Username. Check
Client 2: Connects to server: Check
Server: [If it receives a string, prints it.] (Works) Checks if the new string is in the list. [It isn't] So It sends the new username to everyone, and then prints ("Sent to everyone") Check
But, when client 2 receives the string, it prints it. However, client 1 never recives the string.
And when running client one in IDLE, I noticed something went wrong as Client 1 tried to receive the data. (The while loop that the data = s.recv began looping real fast, instead of waiting)
I've asked around in chat, but it seems nobody's around right now. I've tried looking this up but I really can't find an answer. What I suspect is happening is that when my server sends to 'connection' the second time, it somehow overrides the original client connection.
Here's my server code:
from socket import *
import threading
import os
import csv
Username_List = []
host = input("Host: ")
port = input("Port: ")
ss = socket(AF_INET,SOCK_STREAM)
ss.bind((host,int(port)))
ss.listen(2)
while True:
try:
connection,address = ss.accept()
data = connection.recv(1024)
if data:
translated_data = data.decode()
print(translated_data)
if translated_data in Username_List:
pass
else:
Username_List.append(translated_data)
connection.sendall(translated_data.encode())
print("Sent new username to everyone")
except IOError:
connection.close()
print("An exception with a connected user occured")
break
And here is my client code: [The only difference between client 1 and 2 is I changed the username variable]
# Sample Username Client Service Handler.
from socket import *
import threading
import os
import csv
Username = ("Owatch")
host = input("Host: ")
port = input("Port: ")
try:
ss = socket(AF_INET,SOCK_STREAM)
ss.connect((host,int(port)))
except IOError:
print("Aw no man")
ss.send(Username.encode())
while True:
try:
print("Waiting to Recieve Data")
data = ss.recv(1024)
if data:
translated_data = data.decode()
print(translated_data)
if translated_data == Username:
print("It's one of ours!")
else:
Client_Username = translated_data
print (Client_Username)
except Exception as e:
print (vars(e))
If you could please help I'd be grateful.
If you know of an answer to my question that's already been asked, please tell me and I'll remove this post to avoid breaking rules. Thanks!
Right then I started with what you had then changed it till it worked what I've done is created a client class which starts a thread with each connection and adds it to a list of threads (please if I'm doing something horribly wrong smarter people correct me), the thread runs gets some data checks if that's in the list of user names if its not sends out a message to all the clients in the thread list with that name then the thread just chills out. Anyway on to the code.
SERVER!!!
import csv
class client(threading.Thread):
Username_List = []
def __init__(self, conn):
super(client, self).__init__()
self.conn = conn
def run(self):
print "Client thread started"
data = self.conn.recv(1024)
print "Received: {0}".format(data)
if data in client.Username_List:
self.send_msg("Welcome Back!")
else:
for cnt in threadz:
cnt.send_msg(data)
print("Sent new username to everyone")
client.Username_List.append(data)
while True:
# dont need nothing now
pass
def send_msg(self,msg):
self.conn.send(msg)
host = input("Host: ")
port = input("Port: ")
ss = socket() #AF_INET,SOCK_STREAM)
ss.bind((host,int(port)))
print "Server Opening on port: {0}".format(port)
ss.listen(2)
threadz = []
print "Begining Wait for connections"
while True:
try:
connection, address = ss.accept()
print "Got ONE!"
c = client(connection)
print "Recevied connection from:{0} On port:{1}".format(address[0],address[1])
c.start()
threadz.append(c)
print "Client appended to threadz, currently {0} threadz active".format(len(threadz))
except IOError,KeyboardInterrupt:
connection.close()
print("An exception with a connected user occured")
break
The CLIENT:
# Sample Username Client Service Handler.
from socket import *
import threading
import os
import csv
Username = ("ShyGuy")
host = input("Host: ")
port = input("Port: ")
try:
ss = socket() #AF_INET,SOCK_STREAM)
ss.connect((host,int(port))) #I was using ("localhost",1234) for testing
ss.send(Username)
except IOError:
print("Aw no man")
print("Waiting to Recieve Data")
while True:
try:
data = ss.recv(1024)
if data:
translated_data = data.decode()
print(translated_data)
if translated_data == Username:
print"Name: {0} has been registered on server!".format(translated_data)
else:
Client_Username = translated_data
print "New client name received: {0}".format(Client_Username)
except Exception as e:
print (vars(e))
That works on python 2.7 with two clients locally. Needs to use a semaphore to stop the threads printing at the same time as the main server loop prints: http://en.wikipedia.org/wiki/Semaphore_(programming)
This code does nothing graceful with client disconnects, but once you can work with the exceptions that a raised when that happens I'm sure you'll learn some more.

My chat client freezes up after beginning threads

I made a better chat client following help from people:
They told me that if I didn't want to be blocked on .recv when waiting for messages, I would need to use threads, classes, functions, and queues to do so.
So I followed some help a specific person gave me where I created a thread from a class and then defined a function that was supposed to read incoming messages and print them.
I also created a function that allows you to enter stuff to be sent off.
Thing is, when I run the program. Nothing happens.
Can somebody help point out what is wrong? (I've asked questions and researched for 3 days, without getting anywhere, so I did try)
from socket import *
import threading
import json
import select
print("Client Version 3")
HOST = input("Connect to: ")
PORT = int(input("On port: "))
# Create Socket
s = socket(AF_INET,SOCK_STREAM)
s.connect((HOST,PORT))
print("Connected to: ",HOST,)
#-------------------Need 2 threads for handling incoming and outgoing messages--
# 1: Create out_buffer:
Buffer = []
rlist,wlist,xlist = select.select([s],Buffer,[])
class Incoming(threading.Thread):
# made a function a thread
def Incoming_messages():
while True:
for i in rlist:
data = i.recv(1024)
if data:
print(data.decode())
# Now for outgoing data.
def Outgoing():
while True:
user_input=("Your message: ")
if user_input is True:
Buffer += [user_input.encode()]
for i in wlist:
s.sendall(Buffer)
Buffer = []
Thanks for taking a look, thanks also to Tony The Lion for suggesting this
Take a look at this revised version of your code: (in python3.3)
from socket import *
import threading
import json
import select
print("client")
HOST = input("connect to: ")
PORT = int(input("on port: "))
# create the socket
s = socket(AF_INET, SOCK_STREAM)
s.connect((HOST, PORT))
print("connected to:", HOST)
#------------------- need 2 threads for handling incoming and outgoing messages--
# 1: create out_buffer:
out_buffer = []
# for incoming data
def incoming():
rlist,wlist,xlist = select.select([s], out_buffer, [])
while 1:
for i in rlist:
data = i.recv(1024)
if data:
print("\nreceived:", data.decode())
# now for outgoing data
def outgoing():
global out_buffer
while 1:
user_input=input("your message: ")+"\n"
if user_input:
out_buffer += [user_input.encode()]
# for i in wlist:
s.send(out_buffer[0])
out_buffer = []
thread_in = threading.Thread(target=incoming, args=())
thread_out = threading.Thread(target=outgoing, args=())
thread_in.start() # this causes the thread to run
thread_out.start()
thread_in.join() # this waits until the thread has completed
thread_out.join()
in your program you had various problems, namely you need to call the threads; to just define them isn't enough.
you also had forgot the function input() in the line: user_input=input("your message: ")+"\n".
the "select()" function was blocking until you had something to read, so the program didn't arrive to the next sections of the code, so it's better to move it to the reading thread.
the send function in python doesn't accept a list; in python 3.3 it accepts a group of bytes, as returned by the encoded() function, so that part of the code had to be adapted.

Categories

Resources