How to do UDP multi chat server socket program using threading? - multithreading

I am completely new to network and socket programming. I have tried some code; say I have 3 clients and a server c1 messages and it goes through server and reflected in c2 and c3.
My problem:
I don't want to see my own message (if I say "hi" it's showing for me also but it should be shown in c2 and c3 only).
is there a way like only c2 can see a message and not c3 when c1 sends it
unable to do this in Python and error is shown, so how can be it done in Python 3
server.py
import socket
import time
host = ''
port = 5020
clients = []
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
a=s.bind((host, port))
#s.setblocking(0)
quitting = False
print "Server Started."
print("socket binded to %s" % (port))
while not quitting:
try:
data, addr = s.recvfrom(1024)
if "Quit" in str(data):
quitting = True
if addr not in clients:
clients.append(addr)
#print clients
for client in clients:
if not a:# tried this for broadcasting to others not c1
s.sendto(data, client)
print time.ctime(time.time()) + str(addr) + ": :" + str(data)
except:
pass
s.close()
This is Python 2 code.
client.py
enter code hereimport socket
import threading
import time
shutdown = False
def receving(name, sock):
while not shutdown:
try:
while True:
data, addr = sock.recvfrom(1024)
print str(data)
except:
pass
host = ''
port = 5020
server = ('',5020)
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.bind((host, port))
#s.setblocking(0)
for i in range(5):
threading.Thread(target=receving, args=("RecvThread",s)).start()
alias = raw_input("Name: ")
message = raw_input(alias + "-> ")
while message != 'q':
if message != '':
s.sendto(alias + ": " + message, server)
message = raw_input(alias + "-> ")
time.sleep(0.1)
shutdown = True
s.close()
The output am getting in server is correct the time and server message, but my problem is client output c1 message is shown in c1 itself.
Name: c1
c1-> hi
c1-> c1: hi
see the 3rd line the message "hi" is shown to me also.

Instead of
for client in clients:
if not a:# tried this for broadcasting to others not c1
s.sendto(data, client)
You can do this:
for client in clients:
if client!=addr:# tried this for broadcasting to others not c1
s.sendto(data, client)
Because address of every connected client is stored in addr variable when you do this:
data, addr = s.recvfrom(1024)

Related

Detect (non-blocking) key press while accepting client connections

I am fairly new at programming in python. I am trying to code some form of simulation using sockets. I am able connect multiple clients to the server successfully. However I would like the server to accept client connections while waiting for some input (say enter key or a string input from the console/terminal). If the user presses the enter key or enters that string, then the server should stop accepting client connections and send the list of connected clients to all clients. I know how to code the rest of the part but I dont know where to detect this key press while accepting connections. This is what I have so far. I have tried looking for similar approaches taken, but I have not found something that fits my needs.
Server File:
import socket, sys, traceback, json, pygame, curses, time
from threading import Thread
clientList = {}
def initialize():
serverConnect()
def serverConnect():
local_hostname = socket.gethostname()
host = socket.gethostbyname(local_hostname)
port = 6666
sockfd = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sockfd.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
try:
sockfd.bind((host, port))
except:
print("Bind failed. Error : " + str(sys.exc_info()))
sys.exit()
sockfd.listen(3)
cid = 0
# infinite loop - do not reset for every requests
while True:
print("Awaiting client connection...")
clientSocket, address = sockfd.accept()
cid += 1
add_client_to_list(cid, address)
ip = str(address[0])
port = str(address[1])
print("Connected with " + ip + ":" + port)
try:
Thread(target=client_thread, args=(clientSocket, ip, port, cid, address)).start()
except:
print("Thread did not start.")
traceback.print_exc()
sockfd.close()
def client_thread(clientSocket, ip, port, cid, address, BUFSIZE = 5120):
clientAddress = address
clientID = cid
print("Sending client ID " + str(clientID) + " to " + ip + ":" + port)
clientSocket.sendall(str(clientID).encode("utf-8"))
threadActive = True
while threadActive:
recdData = receive_input(clientSocket, BUFSIZE)
if "--QUIT--" in recdData:
print("Client is requesting to quit")
clientSocket.close()
print("Connection " + ip + ":" + port + " closed")
threadActive = False
else:
print("\nReceived: {}".format(recdData) + " from %d" %clientID)
clientSocket.sendall("-".encode("utf8"))
def receive_input(clientSocket, BUFSIZE):
recdData = clientSocket.recv(BUFSIZE)
recdDataSize = sys.getsizeof(recdData)
if recdDataSize > BUFSIZE:
print("The input size is greater than expected {}".format(recdDataSize))
decodedData = recdData.decode("utf8").rstrip() # decode and strip end of line
result = process_input(decodedData)
return result
def process_input(input_str):
return str(input_str).upper()
def add_client_to_list(client_ID, client_address):
clientList[client_ID] = client_address
print(clientList)
def send_client_list(clientSocket, clientList):
jsonList = json.dumps(clientList)
clientSocket.sendall(str(jsonList).encode("utf-8"))
def keyPress(stdscr):
"""checking for keypress"""
stdscr.nodelay(True) # do not wait for input when calling getch
return stdscr.getch()
if __name__ == "__main__":
initialize()
Client File:
import socket
import sys
import json
def initialize():
sockfd = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
host = socket.gethostname()
port = 6666
try:
sockfd.connect((host, port))
except:
print("Connection error")
sys.exit()
# Receiving server assigned client ID
try:
myID = sockfd.recv(1024).decode("utf-8")
print("Received ID: " + myID + " from server.")
except:
print("Could not receive my ID from server")
sys.exit()
print("Enter 'quit' to exit and 'list' to receive client List")
message = input(" -> ")
while True:
if message == "list":
print("Receiving clientList from server...")
try:
jsonList = sockfd.recv(8192).decode("utf-8")
clientList = json.loads(jsonList)
print("Received list: %s" % clientList)
except:
print("Could not receive list from server")
sys.exit()
elif message != 'quit':
sockfd.sendall(message.encode("utf8"))
if sockfd.recv(5120).decode("utf8") == "-":
pass
message = input(" -> ")
else:
sockfd.send(b'--quit--')
break;
if __name__ == "__main__":
initialize()
This is what I have found. It is a small script which detects if the user inputs {a} on the console. And if he does, then a message is printed. Else it keeps listening for key presses.
import curses, time
def keyPress(stdscr):
# checking for keypress
stdscr.nodelay(True) # do not wait for input when calling getch
return stdscr.getch()
while True:
if curses.wrapper(keyPress) == 97:
print("You pressed 'a'")
else:
pass
time.sleep(0.1)
It would be great if you could guide me how I can use this concept to detect key press on the server side and stop accepting client connections and call the function to send client list to all clients. Or if you have any other approaches or suggestions.

Why this Python3 chat fails after a few messages?

That's what happens: After the client sends some messages, it gives ConnectionAbortedError: [WinError 10053] and the server keeps running
Images:
server socket:
client socket:
Here's my server code:
from socket import *
def server(address, port):
sock = socket(AF_INET, SOCK_STREAM)
sock.bind((address, port))
sock.listen(10)
while True:
clientsock, addr = sock.accept()
ip, _ = addr
msg = input('YOU: ')
clientsock.send(bytes(msg, 'utf-8'))
data = clientsock.recv(2048)
print('%s - ' % ip, data.decode('utf-8'))
if not data:
break
clientsock.shutdown(SHUT_WR)
clientsock.close()
sock.close()
if __name__ == '__main__':
server('192.168.0.101', 5000)
Client:
from socket import *
def client(address, port):
sock = socket(AF_INET, SOCK_STREAM)
sock.connect((address, port)) #0.0.0.0 isnt valid
while True:
data = sock.recv(2048)
print('%s - ' % address, data.decode('utf-8'))
msg = input('YOU: ')
sock.send(bytes(msg, 'utf-8'))
sock.close()
if __name__ == '__main__':
client('192.168.0.101', 5000)
Server in each loop accept new client sends one message receive one message and disconnect client. Then it waits for another client.
You need another loop for handling client.
That another loop could be placed in another thread.
If you nest that loop in this loop, you will be able to handle just one client at the time. I modified your server like that:
def server(address, port):
sock = socket(AF_INET, SOCK_STREAM)
sock.bind((address, port))
sock.listen(10)
while True: # server loop
clientsock, addr = sock.accept()
ip, _ = addr
msg = "Hello to client from %s" % ip
# next line is here because your client need message from server to send message
clientsock.send(bytes(msg, 'utf-8'))
while True: # client loop
data = clientsock.recv(2048)
msg = '%s - %s' % (ip, data.decode('utf-8'))
print(msg)
if not data:
break
clientsock.send(bytes(msg, 'utf-8')) # for multiple clients you need send msg to all
clientsock.shutdown(SHUT_WR)
clientsock.close()
sock.close()
To handle multiple clients you do not want to block server loop until client loop ends. You could run client loop in another thread and continue waiting for next client clientsock, addr = sock.accept().
Similarly you might want to separate receiving messages from server and waiting for client input.

Python 3 socket client not connecting to server

I have a server.py and client.py pair. When I run the server on my machine and open multiple terminals to runs clients, I can connect fine. But when I try to run clients on another computer, the client never connects to the server. I'm pretty sure I tested this code a few months ago on multiple computers and it worked fine (though maybe I'm remembering wrong), but I think I updated my python version, so maybe that's why? How can I change my code below so it works?
server.py
import socket
from threading import Thread
import sys
clients = []
def recv(clientsocket):
while True:
msg = clientsocket.recv(1024) # wait for message from any of the clients.
print("\n" + msg.decode())
for c in clients: # send to all the clients.
c.send(msg)
def send(clientsocket):
while True:
msg = "[Server] %s" % input("\n") # wait for input
print(msg)
for c in clients: # send to all the clients.
c.send(msg.encode())
clientsocket.close()
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # Create a socket object
host = socket.gethostname() # Get local machine name
#port = 3001 # Reserve a port for your service.
port = int(input("Enter port: "))
print ('Server started at [%s]' % socket.gethostbyname(host))
print ('Waiting for clients...')
#s.bind((host, port)) # Bind to the port
s.bind((socket.gethostbyname(host), port))
s.listen(5) # Now wait for client connection.
while True:
#Waits until someone new to accept
c, addr = s.accept()
print(addr, "connected.")
clients.append(c)
thread_recv = Thread(target=recv, args=((c,)))
thread_recv.start()
thread_send = Thread(target=send, args=((c,)))
thread_send.start()
s.close()
client.py
import socket
from threading import Thread
hostname = input("Enter hostname/IP to connect to: ")
# port = 3001
port = int(input("Enter port: "))
clientsocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
clientsocket.connect((hostname, port))
def recv():
while True:
print("\n" + clientsocket.recv(2048).decode())
def send(username):
while True:
msg = "[%s] %s" % (username, input(""))
clientsocket.send(msg.encode()) # send message to the server.
username = input("Choose a username: ")
msg = "[%s has just connected]" % (username)
clientsocket.send(msg.encode())
thread_send = Thread(target=send, args=(username,))
thread_send.start()
thread_recv = Thread(target=recv, args=())
thread_recv.start()
while True:
# keep the threads going.
pass
Edit
Every time I start the server, it says my ip address is the same: 192.168.56.1. Even though I've turned my computer off and tried again. But when I go to Google and ask what is my ip address, it is something totally different. Why does the socket keep choosing 192.168.56.1? Is there something special about it? Is this something related to my problem?
Just bind you server to 0.0.0.0 and bind it to all network interfaces:
server.py
s.bind(('0.0.0.0', port))
Then the code in server.py will end up being something like this:
import socket
from threading import Thread
import sys
clients = []
def recv(clientsocket):
while True:
msg = clientsocket.recv(1024) # wait for message from any of the clients.
print("\n" + msg.decode())
for c in clients: # send to all the clients.
c.send(msg)
def send(clientsocket):
while True:
msg = "[Server] %s" % input("\n") # wait for input
print(msg)
for c in clients: # send to all the clients.
c.send(msg.encode())
clientsocket.close()
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # Create a socket object
host = socket.gethostname() # Get local machine name
#port = 3001 # Reserve a port for your service.
port = int(input("Enter port: "))
print ('Server started at [%s]' % socket.gethostbyname(host))
print ('Waiting for clients...')
#s.bind((host, port)) # Bind to the port
s.bind(('0.0.0.0', port))
s.listen(5) # Now wait for client connection.
while True:
#Waits until someone new to accept
c, addr = s.accept()
print(addr, "connected.")
clients.append(c)
thread_recv = Thread(target=recv, args=((c,)))
thread_recv.start()
thread_send = Thread(target=send, args=((c,)))
thread_send.start()
s.close()

s.recv hang in python sockets

I have a client and server machine.
From client I am sending a linux command which replies after 80 sec.
As the server does not reply initial80 seconds the (s.recv) and a timeout error occurs.
Please help how to proceed here?
s= socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(300)
s.connect((hostname, self.port))
s.sendall(self.msg)) # where msg is some linux command or script which replies after 80 seconds
#s.shutdown(socket.SHUT_WR)
while 1:
data = s.recv(1024)
if data == b"":
break
datai = datai + data.decode()
self.result[hostname.decode()] = datai
I couldn't reproduce it. Here's server and client code that is almost what you have - it works as desired:
client:
#!/usr/bin/env python3
import socket #for sockets
import sys #for exit
try:
#create an AF_INET, STREAM socket (TCP)
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
except socket.error, msg:
print 'Failed to create socket. Error code: ' + str(msg[0]) + ' , Error message : ' + msg[1]
sys.exit();
print 'Socket Created'
host = 'localhost'
port = 8888
try:
remote_ip = socket.gethostbyname( host )
except socket.gaierror:
#could not resolve
print 'Hostname could not be resolved. Exiting'
sys.exit()
print 'Ip address of ' + host + ' is ' + remote_ip
message = "The message \n"
#Code from Stackoverflow question
#s= socket.socket(socket.AF_INET, socket.SOCK_STREAM) # this is already done
s.settimeout(300)
#Connect to remote server
#s.connect((hostname, self.port)) # different variable name
s.connect((remote_ip , port))
print 'Socket Connected to ' + host + ' on ip ' + remote_ip
s.sendall(message) # where msg is some linux command or script which replies after 80 seconds
#s.shutdown(socket.SHUT_WR)
while 1:
data = s.recv(1024)
print("Ok, I get the response :)")
if data == b"":
break
datai = "DATAI: "
datai = datai + data.decode()
#self.result[hostname.decode()] = datai
print("Datai: " + str(datai))
#End
break
s.close()
server:
#!/usr/bin/env python3
'''
Simple socket server using threads.
Taken from: https://www.binarytides.com/python-socket-server-code-example/
'''
#Code for reproduce stackoverflow question
from time import sleep
#End
import socket
import sys
HOST = '' # Symbolic name, meaning all available interfaces
PORT = 8888 # Arbitrary non-privileged port
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print 'Socket created'
#Bind socket to local host and port
try:
s.bind((HOST, PORT))
except socket.error as msg:
print 'Bind failed. Error Code : ' + str(msg[0]) + ' Message ' + msg[1]
sys.exit()
print 'Socket bind complete'
#Start listening on socket
s.listen(10)
print 'Socket now listening'
while 1:
#wait to accept a connection - blocking call
conn, addr = s.accept()
print 'Connected with ' + addr[0] + ':' + str(addr[1])
while True:
#Receiving from client
data = conn.recv(1024)
#Code for reproduce stackoverflow question
print("Waiting 80secs...")
sec = 0
while(sec < 80):
sleep(10)
sec = sec + 10
print(str(sec))
print("Ok, I'll reply...")
#End
if not data:
reply = ""
else:
reply = 'OK...' + data
conn.sendall(reply)
break
conn.close()
s.close()

How can Python's socket (UDP) be used to connect different machines on different WiFi?

I've been trying to set up a game to play with my friends. We all live in different places and have different IP, WiFi etc. I started coding on my own computer using socket using SOCK_DGRAM. It worked fine when I ran the server and client code on my own computer, but when my friends tried to run the client code they couldn't send anything to my server. No error was thrown, what they sent just wasn't picked up by my server.
Here is the server code:
import socket
host = "192.168.88.191"
port = 2000
connections = Connections() # Where I store my friends' way of contacting the server
player_list = [] # A list of players to be used by my Players class
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.bind((host, port))
s.setblocking(False)
print("Server started")
while True:
try:
data, addr = s.recvfrom(1024)
got_data = True
except OSError:
got_data = False
if got_data:
if not addr in connections.addresses:
connections.addresses.append(addr) # Store all new addresses
player_list.append(Players(len(player_list))) # Append to player list (don't worry about this part)
data = data.decode("utf-8")
print("Message from " + str(addr) + ": " + data)
player_list[int(addr[1] - 2001)].move(data, player_list) # Function for game logic
message = ""
for player in player_list:
message += str(player.number) + " " + str(player.x) + " " + str(player.y) + "," # Make the message that I want to send
message = message[:-1]
print("Sending: " + message)
for address in connections.addresses:
s.sendto(message.encode("utf-8"), address)
Here is the client code:
class Sock():
def __init__(self):
self.host = "192.168.88.191"
self.port = 2000
self.server = (self.host, 2000)
self.s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
while True:
try:
print("Trying to connect on port " + str(self.port))
self.s.bind((self.host, self.port))
except OSError:
self.port += 1
else:
self.s.setblocking(False)
print("Connected on port " + str(self.port) + "!")
break
def send_data(self, message):
print("Sending: " + message)
self.s.sendto(message.encode("utf-8"), self.server)
def recieve_data(self):
try:
data, addr = self.s.recvfrom(1024)
data = data.decode("utf-8")
print("Recieved from server: " + data)
return data
except socket.error:
pass
My IP is 192.168.88.191. I would assume that my friends need to use their IP in the client code, but where? I know that you can find your IP by doing socket.gethostbyname(socket.gethostname())
EDIT: This client code didn't actually work, it tried every port until it reached the highest port possible and threw an error. We did some adjustments to the code and got it to connect, but the server still didn't recieve anything. The client could send just fine, but the server didn't recieve. I'm not 100% about the adjustment in question, but I think we replaced: self.server = (self.host, 2000) with: self.server = (socket.gethostbyname(socket.gethostname()), 2000) although as I said I don't know if that's exacly what we did.

Resources