I am trying to build a small chat server/client using python. So far I think I managed to set it up but I am running into issues. I wanted to set the program up to be multithreaded to keep the server listening for connections, and to also continue to listen for data and then have the main program loop stay in the client send. Here is my code, and I am running into an issue when starting the listen function, it tells me the argument must be an iterable not socket.
import socket
import platform
import os
import threading
'''Define Globals'''
HOST = ""
PORT = 25000
ADDR = (HOST, PORT)
BUF = 1024
def client_send():
server_ip = input("[+] Server's IP to connect to: ")
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client_socket.connect((server_ip, 25000))
data_thread = threading.Thread(target=client_listen, args=(client_socket))
data_thread.start()
while True:
data = input("[%s] => " % os.getlogin())
client.send(str.encode("[%s] => " + data % os.getlogin()))
def client_listen(client):
while True:
print(client.recv(BUF))
def server_loop():
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind(ADDR)
server.listen(10)
print("[+] Server started on %s" %platform.node())
print("[+] Awaitiing connection from client..")
while True:
client_socket, client_addr = server.accept()
print("[+] New Connection from %s" %client_addr[0])
def main():
server_thread = threading.Thread(target=server_loop)
while True:
try:
print("Select Operating Mode")
print("---------------------")
print("1. Server Mode")
print("2. Client Mode")
mode = int(input("Enter mode of operation: "))
print("")
print("")
if mode in [1,2]:
break
else:
raise ValueError
except ValueError:
print("Enter either (1) for Server or (2) for Client")
if mode == 1:
server_thread.start()
elif mode == 2:
client_send()
main()
You need to make the arguments a tuple.
You should supply an extra comma after the argument list as in:
data_thread = threading.Thread(target=client_listen, args=(client_socket,))
The difference can be seen when you look into the types of both:
>>> type((client_socket))
<class 'socket._socketobject'>
>>> type((client_socket,))
<type 'tuple'>
Related
I'm running a python script on a raspberry pi that reads keyboard input to a string and will be sending that string through TCP. I've made two script one that reads the input and one that can send the string if needed. How can i use one string and use it in both scripts for readings and writings?
I've used an text document. Only becaue of the sd card i wanne achieve an connecting between the two scripts
Reading part:
#loops for Barcode_Data
def Create_File():
file = open("Barcode_data.txt", "w")
file.write(" // ")
file.close()
empty = ''
def Barcode_Read():
Barcode_Data= input("Input: ",)
print(Barcode_Data)
file = open("Barcode_data.txt", "a")
file.write(Barcode_Data)
file.write(" // ")
file.close()
#Loop that will only run once
Create_File()
#Loop that will run continuesly
while True:
Barcode_Read()
TCP Server:
#TCP server
def TCP_Connect(socket):
socket.listen()
conn, addr = socket.accept()
with conn:
data = conn.recv(1024)
if data == b'Barcode_Data':
tcp_file = open("Barcode_data.txt", "r")
Barcode_Data = tcp_file.read()
tcp_file.close()
conn.sendall(Barcode_Data.encode('utf-8'))
elif data == b'Clear Barcode_Data':
tcp_file = open("Barcode_data.txt", "w")
tcp_file.write(" // ")
tcp_file.close()
#TCP Socket setup
HOST = '' # Standard loopback interface address (localhost)
PORT = 1025 # Port to listen on (non-privileged ports are > 1023)
import socket
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.bind((HOST, PORT))
#Loop that wil run continuesly
while True:
TCP_Connect(s)
You can use the code from this question as is: Interprocess communication in Python
Server process:
from multiprocessing.connection import Listener
address = ('localhost', 6000) # family is deduced to be 'AF_INET'
listener = Listener(address, authkey='secret password')
conn = listener.accept()
print 'connection accepted from', listener.last_accepted
while True:
msg = conn.recv()
# do something with msg
if msg == 'close':
conn.close()
break
listener.close()
Client process:
from multiprocessing.connection import Client
address = ('localhost', 6000)
conn = Client(address, authkey='secret password')
conn.send('close')
# can also send arbitrary objects:
# conn.send(['a', 2.5, None, int, sum])
conn.close()
Documentation is available here: https://docs.python.org/3.7/library/multiprocessing.html#multiprocessing-listeners-clients
I am writing a client and server app in Python and I have a problem with received data. In the first "loop" I received good data but in the next "loop" I received bad data. What do I have to do? Maybe you have a better idea to send and receive data.
This is Client:
import socket
import pickle
import sys
host = socket.gethostname()
port = 2004
BUFFER_SIZE = 100000
print("What you want to do:\r1. Select from base\r2.Insert into base")
MESSAGE, MESSAGE1 = input("tcpClientA: Enter message/ Enter exit:").split(",")
tcpClientA = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tcpClientA.connect((host, port))
while MESSAGE != 'exit':
tcpClientA.send(MESSAGE.encode())
tcpClientA.send(MESSAGE1.encode())
lista=pickle.loads(tcpClientA.recv(BUFFER_SIZE).strip())
print(lista)
print("Variables 1 and 2 are: ", MESSAGE, MESSAGE1)
MESSAGE, MESSAGE1 = input("tcpClientA: Enter message to continue/ Enter exit:").split(",")
tcpClientA.close()
This is Server:
import socket
from threading import Thread
import pyodbc
import pickle
# Multithreaded Python server : TCP Server Socket Thread Pool
class ClientThread(Thread):
def __init__(self,ip,port):
Thread.__init__(self)
self.ip = ip
self.port = port
print ("[+] New server socket thread started for " + ip + ":" + str(port) )
def run(self):
while True :
connsql = pyodbc.connect('DRIVER={SQL Server};SERVER=I7-KOMPUTER\SQLEXPRESS;DATABASE=test')
cursor = connsql.cursor()
data = conn.recv(2048)
#datasplitx, datasplity = data.decode().split(",", 1)
try:
xy = []
xy = data.decode().split(" ")
print("dat: ",data.decode())
print("After del:",xy)
x=str(xy[0])
#y=str(xy[1])
#x, y = [str(x) for x in data.decode().split()]
#y=str(datasplit[1])
#x = str(datasplit[0])
#y = str(datasplit[1])
except ValueError:
print("List does not contain value")
print ("Server received data:", xy)
if x == 'exit':
break
if x == '1':
#if data.decode() == '1':
cursor.execute("select rtrim(name) from client")
rows = cursor.fetchall()
zap=pickle.dumps(rows)
conn.send(zap)
print(pickle.loads(zap))
if x == '2':
#if data.decode() == '2':
cursor.execute("insert into dbo.klient values('"+y+"')")
connsql.commit()
zro=pickle.dumps("Done.")
conn.send(zro)
del xy[:]
print ("cleared list: xy",xy)
# Multithreaded Python server : TCP Server Socket Program Stub
TCP_IP = '0.0.0.0'
TCP_PORT = 2004
BUFFER_SIZE = 1024 # Usually 1024, but we need quick response
tcpServer = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tcpServer.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
tcpServer.bind((TCP_IP, TCP_PORT))
threads = []
while True:
tcpServer.listen(4)
print ("Multithreaded Python server : Waiting for connections from TCP clients...\r" )
(conn, (ip,port)) = tcpServer.accept()
newthread = ClientThread(ip,port)
newthread.start()
threads.append(newthread)
print("Client IP: " +str(ip))
for t in threads:
t.join()
I'm trying to create a simple chat application using sockets (python). Where a client can send a message to server and server simply broadcast the message to all other clients except the one who has sent it.
Client has two threads, which are running forever
send: Send simply sends the cleints message to server.
receive: Receive the message from the server.
Server also has two threads, which are running forever
accept_cleint: To accept the incoming connection from the client.
broadcast_usr: Accepts the message from the client and just broadcast it to all other clients.
But I'm getting erroneous output (Please refer the below image). All threads suppose to be active all the times but Some times client can send message sometimes it can not. Say for example Tracey sends 'hi' 4 times but its not broadcasted, When John says 'bye' 2 times then 1 time its message gets braodcasted. It seems like there is some thread synchronization problem at sever, I'm not sure. Please tell me what's wrong.
Below is the code.
chat_client.py
import socket, threading
def send():
while True:
msg = raw_input('\nMe > ')
cli_sock.send(msg)
def receive():
while True:
sen_name = cli_sock.recv(1024)
data = cli_sock.recv(1024)
print('\n' + str(sen_name) + ' > ' + str(data))
if __name__ == "__main__":
# socket
cli_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# connect
HOST = 'localhost'
PORT = 5023
cli_sock.connect((HOST, PORT))
print('Connected to remote host...')
uname = raw_input('Enter your name to enter the chat > ')
cli_sock.send(uname)
thread_send = threading.Thread(target = send)
thread_send.start()
thread_receive = threading.Thread(target = receive)
thread_receive.start()
chat_server.py
import socket, threading
def accept_client():
while True:
#accept
cli_sock, cli_add = ser_sock.accept()
uname = cli_sock.recv(1024)
CONNECTION_LIST.append((uname, cli_sock))
print('%s is now connected' %uname)
def broadcast_usr():
while True:
for i in range(len(CONNECTION_LIST)):
try:
data = CONNECTION_LIST[i][1].recv(1024)
if data:
b_usr(CONNECTION_LIST[i][1], CONNECTION_LIST[i][0], data)
except Exception as x:
print(x.message)
break
def b_usr(cs_sock, sen_name, msg):
for i in range(len(CONNECTION_LIST)):
if (CONNECTION_LIST[i][1] != cs_sock):
CONNECTION_LIST[i][1].send(sen_name)
CONNECTION_LIST[i][1].send(msg)
if __name__ == "__main__":
CONNECTION_LIST = []
# socket
ser_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# bind
HOST = 'localhost'
PORT = 5023
ser_sock.bind((HOST, PORT))
# listen
ser_sock.listen(1)
print('Chat server started on port : ' + str(PORT))
thread_ac = threading.Thread(target = accept_client)
thread_ac.start()
thread_bs = threading.Thread(target = broadcast_usr)
thread_bs.start()
Ok I lied in my comment earlier, sorry. The issue is actually in the broadcast_usr() function on the server. It is blocking in the recv() method and preventing all but the currently selected user from talking at a single time as it progresses through the for loop. To fix this, I changed the server.py program to spawn a new broadcast_usr thread for each client connection that it accepts. I hope this helps.
import socket, threading
def accept_client():
while True:
#accept
cli_sock, cli_add = ser_sock.accept()
uname = cli_sock.recv(1024)
CONNECTION_LIST.append((uname, cli_sock))
print('%s is now connected' %uname)
thread_client = threading.Thread(target = broadcast_usr, args=[uname, cli_sock])
thread_client.start()
def broadcast_usr(uname, cli_sock):
while True:
try:
data = cli_sock.recv(1024)
if data:
print "{0} spoke".format(uname)
b_usr(cli_sock, uname, data)
except Exception as x:
print(x.message)
break
def b_usr(cs_sock, sen_name, msg):
for client in CONNECTION_LIST:
if client[1] != cs_sock:
client[1].send(sen_name)
client[1].send(msg)
if __name__ == "__main__":
CONNECTION_LIST = []
# socket
ser_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# bind
HOST = 'localhost'
PORT = 5023
ser_sock.bind((HOST, PORT))
# listen
ser_sock.listen(1)
print('Chat server started on port : ' + str(PORT))
thread_ac = threading.Thread(target = accept_client)
thread_ac.start()
#thread_bs = threading.Thread(target = broadcast_usr)
#thread_bs.start()
I tried to get around the bug you said #Atinesh. The client will be asked a username once and this 'uname' will be included in the data to be sent. See what I did to the 'send' function.
For easier visualization, I added a '\t' to all received messages.
import socket, threading
def send(uname):
while True:
msg = raw_input('\nMe > ')
data = uname + '>' + msg
cli_sock.send(data)
def receive():
while True:
data = cli_sock.recv(1024)
print('\t'+ str(data))
if __name__ == "__main__":
# socket
cli_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# connect
HOST = 'localhost'
PORT = 5023
uname = raw_input('Enter your name to enter the chat > ')
cli_sock.connect((HOST, PORT))
print('Connected to remote host...')
thread_send = threading.Thread(target = send,args=[uname])
thread_send.start()
thread_receive = threading.Thread(target = receive)
thread_receive.start()
You also have to modify your server code accordingly.
server.py
import socket, threading
def accept_client():
while True:
#accept
cli_sock, cli_add = ser_sock.accept()
CONNECTION_LIST.append(cli_sock)
thread_client = threading.Thread(target = broadcast_usr, args=[cli_sock])
thread_client.start()
def broadcast_usr(cli_sock):
while True:
try:
data = cli_sock.recv(1024)
if data:
b_usr(cli_sock, data)
except Exception as x:
print(x.message)
break
def b_usr(cs_sock, msg):
for client in CONNECTION_LIST:
if client != cs_sock:
client.send(msg)
if __name__ == "__main__":
CONNECTION_LIST = []
# socket
ser_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# bind
HOST = 'localhost'
PORT = 5023
ser_sock.bind((HOST, PORT))
# listen
ser_sock.listen(1)
print('Chat server started on port : ' + str(PORT))
thread_ac = threading.Thread(target = accept_client)
thread_ac.start()
The things that changed in the server side are: the user who connected and the user who spoke is not seen anymore. I don't know if it would mean that much if your purpose is to connect clients. Maybe if you want to strictly monitor clients via the server, there could be another way.
so right now in order to receive your message you need to receive one
my teachers instructions are (in the main)"Modify the loop so that it only listens for keyboard input and then sends it to the server."
I did the rest but don't understand this, ... help?
import socket
import select
import sys
import threading
'''
Purpose: Driver
parameters: none
returns: none
'''
def main():
host = 'localhost'
port = 5000
size = 1024
#open a socket to the client.
try:
clientSock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
clientSock.connect((host,port))
#exit on error
except socket.error, (value,message):
if clientSock :
clientSock.close()
print "Could not make connection: " + message
sys.exit(1)
thread1 = ClientThread()
thread1.start()
while True:
#wait for keyboard input
line = raw_input()
#send the input to the server unless its only a newline
if line != "\n":
clientSock.send(line)
#wait to get something from the server and print it
data = clientSock.recv(size)
print data
class ClientThread(threading.Thread):
'''
Purpose: the constructor
parameters: the already created and connected client socket
returns: none
'''
def __init__(self, clientSocket):
super(ClientThread, self).__init__()
self.clientSocket = clientSocket
self.stopped = False
def run(self):
while not self.stopped:
self.data = self.clientSocket.recv(1024)
print self.data
main()
I assume your purpose is to create a program that starts two threads, one (client thread) receives keyboard input and sends to the other (server thread), the server thread prints out everything it received.
Based on my assumption, you first need to start a ServerThread listen to a port (it's not like what your 'ClientThread' did). Here's an example:
import socket
import threading
def main():
host = 'localhost'
port = 5000
size = 1024
thread1 = ServerThread(host, port, size)
thread1.start()
#open a socket for client
try:
clientSock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
clientSock.connect((host,port))
except socket.error, (value,message):
if clientSock:
clientSock.close()
print "Could not connect to server: " + message
sys.exit(1)
while True:
#wait for keyboard input
line = raw_input()
#send the input to the server unless its only a newline
if line != "\n":
clientSock.send(line)
# Is server supposed to send back any response?
#data = clientSock.recv(size)
#print data
if line == "Quit":
clientSock.close()
break
class ServerThread(threading.Thread):
def __init__(self, host, port, size):
super(ServerThread, self).__init__()
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.sock.bind((host, port))
self.sock.listen(1)
self.data_size = size
self.stopped = False
def run(self):
conn, addr = self.sock.accept()
print 'Connected by', addr
while not self.stopped:
data = conn.recv(self.data_size)
if data == 'Quit':
print 'Client close the connection'
self.stopped = True
else:
print 'Server received data:', data
# Is server supposed to send back any response?
#conn.sendall('Server received data: ' + data)
conn.close()
if __name__ == '__main__':
main()
And these are the output:
Connected by ('127.0.0.1', 41153)
abc
Server received data: abc
def
Server received data: def
Quit
Client close the connection
You may check here for more details about Python socket: https://docs.python.org/2/library/socket.html?#example
I am writing a echo server and client in Python, that implements a simple number guessing game. I know how to multiplex using select, that's fine. The other server I wrote achieves this. But now I am writing a new server (which is fairly similar), however it accepts connections from two ports rather than one, one port for player client, and one for admin which I will use eventually for the who command, returning all connected players.
My problem is, that after sending the initial greetings message, the clients receive feedback from the server on the first send, recv. But after that I cannot send any more messages to server (nothing gets sent from the clients), I have been searching and playing around for hours, to no avail. Any help would be appreciated. Thanks!
# MULTIPLEX SERVER
import socket, select, time, random, ssl, sys, os
# VARS
EXP = 1
HOST = '127.0.0.1'
PORT_P = 4000
PORT_A = 4001
BUFFSZ = 1024
BKLOG = 5
GREETS = 'Greetings'
INPUTS = []
OUTPUTS = []
CLIENT_ADDRS = {}
CLIENT_ANS = {}
CLIENTS = ""
_adm_rtnMSG = 'Admin_Greetings'
# Function to determine how far the player is
# from the chosen random number
def Within(value, target):
diff = abs(target - value)
if diff > 3:
return 'Not even close, youth!'
else:
return 'Ooh, not to far: ' + str(diff) + ' away, keep trying...'
# END_FUNCTION
print('Server up and running...\n')
try:
for p in PORT_P, PORT_A:
INPUTS.append(socket.socket(socket.AF_INET, socket.SOCK_STREAM))
INPUTS[-1].setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
INPUTS[-1].bind((HOST, p))
INPUTS[-1].listen(BKLOG)
except socket.error(value, message):
if INPUTS[-1]:
INPUTS[-1].close()
INPUTS = INPUTS[:-1]
print('Failure to open socket: ' + message)
sys.exit(1)
while True:
READ_IO, WRITE_IO, ERROR = select.select(INPUTS, OUTPUTS, INPUTS)
for r in READ_IO:
for p in INPUTS:
if r is p:
(acpt_sock, addr) = p.accept()
print('Connection established with ', acpt_sock.getsockname())
CLIENT_ADDRS[acpt_sock] = addr
CLIENT_ANS[acpt_sock] = random.randrange(1, 20)
else:
data = acpt_sock.recv(BUFFSZ).decode()
acpt_sock.setblocking(0)
if data:
if 'Hello' in data:
print(CLIENT_ADDRS[acpt_sock], ' random number is: ', CLIENT_ANS[acpt_sock])
acpt_sock.send(b'Greetings\nGuess a random number between 1 & 20')
# drop elif here for admin cmd
elif 'Hi' in data:
acpt_sock.send(_adm_rtnMSG.encode())
else:
if int(data) == CLIENT_ANS[acpt_sock]:
acpt_sock.send(b'That was correct, Well done!')
else:
acpt_sock.send(str(Within(int(data), CLIENT_ANS[acpt_sock])).encode())
else:
print('Closing Connection # ', addr)
INPUTS.remove(acpt_sock)
acpt_sock.close()
del CLIENT_ADDRS[acpt_sock]
# PLAYER CLIENT
import socket
import re
# INIT VARS
HOST = '127.0.0.1'
PORT = 4000
INITSTR = 'Hello'
BUFF = 1024
# Set up socket
sender = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sender.connect((HOST, PORT))
sender.send(bytes((INITSTR), "ascii"))
print("Kirby Prompt FTW!\nConnected to Server via", HOST, "::", PORT, '\n')
rtnMSG = sender.recv(BUFF).decode()
print(rtnMSG)
# Simple loop to keep client alive
# to send and receive data from the server
while 'correct' not in rtnMSG:
_guess = input("(>',')> ")
sender.send(bytes((_guess), "ascii"))
rtnMSG = sender.recv(BUFF).decode()
print(rtnMSG)
sender.close()
# ADMIN CLIENT
import socket
import re
import ssl
# INIT VARS
HOST = '127.0.0.1'
PORT = 4001
INITSTR = 'Hi'
BUFF = 1024
# Set up socket
adm_sender = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
adm_sender.connect((HOST, PORT))
adm_sender.send(bytes((INITSTR), "ascii"))
print("Connected to Server as Admin via", HOST, "::", PORT, '\n')
rtnMSG = adm_sender.recv(BUFF).decode()
print(rtnMSG)
while True:
cmd = input('$ ')
adm_sender.send(bytes((cmd), "ascii"))
rtnMSG = adm_sender.recv(BUFF).decode()
print(rtnMSG)
adm_sender.close()