I am building a simple network chat in Python using UDP, however, when I run the server code on one machine and the client on another, no message is received by the server and no message is sent back to the client by the server script. Here is my code:
Server:
import socket, sys
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind(('', 9997)) #need higher port
while True:
x = raw_input("Enter your message: ")
sent = sock.sendto(x, ('', 9997))
data, address = sock.recvfrom(4096)
print data, " ", address
sock.close()
Client:
import socket
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
while True:
print "Waiting to receive"
data, server = sock.recvfrom(4096)
print data
x = raw_input("Enter message: ")
sent = sock.sendto(x, server)
sock.close()
Does anyone know what I am doing wrong here? Is is possible that code is fine, but the UDP is not reliable enough and is dropping the message?
As I said, since your code seems a little unclear (to me, at least), I'm posting you a very similar working example.
Here's the Server:
import socket
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
server_address = ('localhost', 1932)
sock.bind(server_address)
BUFFER_SIZE = 4096
try:
while True:
data, address = sock.recvfrom(BUFFER_SIZE)
print "Client sends: ", data
reply = raw_input("Your response:\n")
sock.sendto(reply,address)
except KeyboardInterrupt:
sock.close()
The server creates a socket and binds it to its address and the port it's listening to, 1932 in our case. He waits for an incoming message, asks for a reply, then sends it back to the sender.
Here's the Client:
import socket
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
client_address = ('localhost', 1931)
server_address = ('localhost', 1932)
sock.bind(client_address)
BUFFER_SIZE = 4096
try:
first_msg = raw_input("Your first message:\n")
sock.sendto(first_msg,server_address)
while True:
data, address = sock.recvfrom(BUFFER_SIZE)
print "Client sends: ", data
reply = raw_input("Your response:\n")
sock.sendto(reply,address)
except KeyboardInterrupt:
sock.close()
It's very similar to the server, the only difference is that it sends a message before the while loop, in order to start the conversation. Then it just enters the receive/reply loop, just as the server does. It has the server address too, that is different (different port, since I'm on localhost)
The try/catch block is here just to close gracefully the whole process.
I used localhost and different ports on my computer and tested it, and it works. You should just change the addresses to get it working over LAN, and you could keep the same port if the addresses are different, it should work.
Related
I'm creating a program that uses threads to handle sockets and input at the same time. I've narrowed down the errors I'm getting to be replicable in these couple dozen lines of code. What happens to anyone else who runs the code below? I encounter a hang-up in waiting for the recv in the client. If I further try to send() more data in the server, I get a Broken Pipe error. And, even more weirdly, if I comment out the line that calls input(), the sockets work just fine.
What kind of weird interaction is going on between input(), sockets, and threading? And does anyone have a solution to this? Here's some code that generates the error.
Server:
import socket
import threading
def handle_connection(conn, addr):
data = conn.recv(1024)
message = data.decode('ascii').split()
s = "TEST"
conn.send(bytes(s, 'ascii')) #
conn.close()
def handle_input():
while True:
s = input()
print(s)
HOST = "127.0.0.1" # The server's hostname or IP address
PORT = 2000 # The port used by the server
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.bind((HOST, PORT)); #Empty first string = INADDR_ANY
s.listen();
w = threading.Thread(target=handle_input)
w.start()
while True:
conn, addr = s.accept()
x = threading.Thread(target=handle_connection, args=(conn, addr))
x.start()
s.close()
Client:
import socket
HOST = "127.0.0.1" # The server's hostname or IP address
PORT = 2000 # The port used by the server
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
message = "find_successor a"
s.connect((HOST, PORT))
s.sendall(bytes(message, 'ascii'))
data = s.recv(1024)
print(f"Received {data!r}")
I appreciate any help or insight!
I would like to write a very simple rock-paper-scissors game in Python. I would like to have 1 server and 2 clients. After connecting to the server, the server should send a message to each client to choose (r/p/s). After this, each client should send back their choice and the server then decides about the winner, and then it informs the clients about the winner.
This is what I have so far:
This is the server.py
import socket
from threading import Thread
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:
data = conn.recv(1024).decode()
print("Server received data:", data)
MESSAGE = input("Server response: ")
if MESSAGE == 'exit':
break
conn.send(MESSAGE.encode())
TCP_IP = '0.0.0.0'
TCP_PORT = 2004
BUFFER_SIZE = 1024
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...")
(conn, (ip, port)) = tcpServer.accept()
newthread = ClientThread(ip, port)
newthread.start()
threads.append(newthread)
for t in threads:
t.join()
This is clientA.py:
import socket
host = socket.gethostname()
port = 2004
BUFFER_SIZE = 1024
MESSAGE = input("tcpClientA:")
tcpClientA = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tcpClientA.connect((host, port))
while MESSAGE != 'exit':
tcpClientA.send(MESSAGE.encode())
data = tcpClientA.recv(BUFFER_SIZE).decode()
print(" ClientA received data:", data)
MESSAGE = input("tcpClientA:")
tcpClientA.close()
This is clientB.py:
import socket
host = socket.gethostname()
port = 2004
BUFFER_SIZE = 1024
MESSAGE = input("tcpClientB:")
tcpClientB = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tcpClientB.connect((host, port))
while MESSAGE != 'exit':
tcpClientB.send(MESSAGE.encode())
data = tcpClientB.recv(BUFFER_SIZE).decode()
print(" ClientB received data:", data)
MESSAGE = input("tcpClientB:")
tcpClientB.close()
In this code, however, I can only send messages to the server and it can respond. Unfortunately, I don't know, how I can send messages to a specific client in this case. (I need to send different messages to the winner and to the loser).
First, this is not a trivial exercise and it will require a decent understanding of how threads work and how to work with them in Python in particular. What you seem to be missing at the moment is a way of orchestrating the communication from the 2 clients and of keeping track of what each client played so you can decide which client wins.
What currently happens is that when tcpClientA.connect((host, port)) runs on client A, (conn, (ip, port)) = tcpServer.accept() gets unblocked in the server. This creates a new instance of your ClientThread class and the new thread starts listening for data to be sent by client A on the connection. When client B runs, the same happens and you now have 2 threads running and listening for data but no way of knowing which plays what.
What I would suggest is to introduce a new class that will represent the game itself. That class will get the messages from both client and respond to each accordingly. What you will also need is a way of waiting for both clients to have played their turn before being able to decide who wins and what to send to each.
One way to do it would be with Barrier objects.
So I have created a socket program for both client and server as a basic chat. I made it so the server accepts multiple clients with threading, so that is not the problem. I am having trouble sending messages to each client that is connected to the server. I am not trying to have the server send a message it created but rather have client1 sending a message to client2 by going through the server. For some reason it will only send it back to client1.
For example, client1 will say hello and the server will send the same message back to client1 but nothing to client2. I fixed this slightly by making sure the client doesn't receive its own message but client2 is still not receiving the message from the client1.
Any help will be appreciated.
I have tried multiple changes and nothing seems to work. You can look at my code for specifics on how I did things but ask if there are any questions.
Also, there is a question where someone has asked that is similar and I thought it would give me an answer but the responses stopped going through and a solution was never fully given, so please don't just refer me to that question. that is located here: Python 3: Socket server send to multiple clients with sendto() function.
Here's the code:
CLIENT:
import socket
import sys
import thread
#Create a socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
#Enter username to identify self to others
name = raw_input("Enter username: ") + ": "
#Connect socket to ip and port
host = socket.gethostname()
#host = '192.168.1.10'
server_address = (host, 4441)
sock.connect(server_address)
#function waiting to receive and print a message
def receive(nothing):
while True:
data = sock.recv(1024)
if message != data:
print data
# Send messages
while True:
#arbitrary variable allowing us to have a thread
nothing = (0, 1)
message = name + raw_input("> ")
sock.sendall(message)
#thread to receive a message
thread.start_new_thread(receive, (nothing,))
SERVER:
import socket
import sys
import thread
# Create a TCP/IP socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# Bind the socket to the port
host = socket.gethostname()
server_address = (host, 4441)
sock.bind(server_address)
#Listen for incoming connections
sock.listen(5)
print "Waiting for connection..."
#Variable for the number of connections
numbOfConn = 0
#Name of list used for connections
addressList = []
#Function that continuosly searches for connections
def clients(connection, addressList):
while True:
message = connection.recv(1024)
print message
#connection.sendall(message)
#for loop to send message to each
for i in range(0,numbOfConn - 1):
connection.sendto(message, addressList[i])
connection.close()
while True:
#accept a connection
connection, address = sock.accept()
print 'Got connection from', address
numbOfConn += 1
addressList.append((address))
#Thread that calls the function: clients and stores them in a tuple called connection
thread.start_new_thread(clients, (connection, addressList))
sock.close()
Please help me if you can!
EDIT:
I was able to fix it to a certain extent. It is still a little buggy but I am able to send messages back and forth now. I needed to specify the connection socket as well as the address. Here's the updated code:
SERVER
import socket
import sys
import thread
# Create a TCP/IP socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# Bind the socket to the port
host = socket.gethostname()
server_address = (host, 4441)
sock.bind(server_address)
#Listen for incoming connections
sock.listen(5)
print "Waiting for connection..."
#Variable for the number of connections
numbOfConn = 0
#Name of list used for connections
addressList = []
connectionList = []
#Function that continuosly searches for connections
def clients(connectionList, addressList):
while True:
for j in range(0,numbOfConn):
message = connectionList[j].recv(1024)
print message
#for loop to send message to each
for i in range(0,numbOfConn):
connectionList[i].sendto(message, addressList[i])
connection.close()
while True:
#accept a connection
connection, address = sock.accept()
print 'Got connection from', address
numbOfConn += 1
addressList.append((address))
connectionList.append((connection))
#Thread that calls the function: clients and stores them in a tuple called connection
thread.start_new_thread(clients, (connectionList, addressList))
sock.close()
I am writing a client/ server program in Python where, once the client and server have successfully connected via a socket, they may exchange messages. Below is my server and client code. When compiled, the connection is established correctly and the messages are sent successfully, but one cannot send a second message until it has received a response from the other party.
For example:
Client sends: "Hello, server!"
Server sends: "I have received your message, client!"
Client sends: "great, here's another one"
Client sends: "and a second one!"
At this point, the server terminal window has received the message saying "great, here's another one", but must first reply to this message before receiving "and a second one!".
I think my issue is that I need to use the select() method, but do not understand how to do so. How can I fix this?
#The server code
HOST = ''
PORT = 9999
s = socket(AF_INET, SOCK_STREAM)
s.bind((HOST, PORT))
print("Now listening...")
s.listen(1) #only needs to receive one connection (the client)
conn, addr = s.accept() #accepts the connection
print("Connected by: ", addr) #prints the connection
i = True
while i is True:
data = conn.recv(1024) #receives data
print('Received:' , repr(data)) #prints the message from client
reply = raw_input() #server types a response
conn.sendall(reply) #server now sends response back to client
close()
below is the client code (client.py)
The client code
from socket import*
HOST = '192.168.41.1'
PORT = 9999
s = socket(AF_INET, SOCK_STREAM)
s.connect((HOST, PORT))
while True:
message = raw_input() #client's message to the server
s.send(message) #sends message to the server
print("Waiting for response...")
reply = s.recv(1024) #receives message from server
print("New message: " + repr(reply)) #prints the message received
close()
Look at the following examples:
http://code.activestate.com/recipes/531824-chat-server-client-using-selectselect/
and
http://www.binarytides.com/code-chat-application-server-client-sockets-python/
also some similar answer here:
Python client side in chat
What you are missing is select on client side where its select if to handle input from server or from command line.
So in that case, you don't have to wait for server response and can send 2 calls one after another from the client.
Freely adapting the answers above to what you wished to accomplish.
(I didn't test it - so make sure to check it)
from socket import*
import sys
import select
HOST = '192.168.41.1'
PORT = 9999
s = socket(AF_INET, SOCK_STREAM)
s.connect((HOST, PORT))
while True:
socket_list = [sys.stdin, s]
# Get the list sockets which are readable
read_sockets, write_sockets, error_sockets = select.select(
socket_list, [], [])
for sock in read_sockets:
#incoming message from remote server
if sock == s:
data = sock.recv(1024)
if not data:
print('\nDisconnected from server')
break
else:
#print data
sys.stdout.write(data)
# prints the message received
print("New message: " + repr(data))
prompt()
#user entered a message
else:
msg = sys.stdin.readline()
s.send(msg)
prompt()
s.close()
I would strongly suggest reading and familiarizing with this document and especially the non-blocking sockets part.
Your code now blocks when waiting for the data to arrive from the user. You want to instruct your program to wait for the data from the socket and at the same time allow user to type input.
How do I get a response from the server?
Client side:
#CLIENT
import socket
import time
host = "localhost"
port = 5454
data_c = input()
c = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
c.sendto(bytes(data_c, 'utf-8'),(host,port))
print( data_c )
print( c.recv(1024).decode('utf-8'))
SERVER side:
#SERVER
import socket
import time
host = "localhost"
port = 5454
data_s = "ACKNOWLEDGMENT"
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.bind((host, port))
print(s.recv(1024).decode('utf-8'))
I can send a message from the server that the client will receive, but can not seem to get communication (like an ACK.) to make it back to the server.
(yes UDP is not a good way to be doing this i'm pretty sure, but that was a specific for the project)
for question 1: to send the ACK, you could replicate what you have in the reverse direction.
Since UDP is connection-less you don't know beforehand you receive a packet where the packet will come from, so you have to use recvfrom to get both the packet and the peer (address/port) the packet came from. Then you have to use that address to send data back.
What you're doing now in your client (but what really looks like the server) in the loop is send the same data over and over to itself. Instead in the loop you should receive packets using the previously mentions recvfrom then send replies to the peer you received the packet from.
So something like the following pseudo code
while True:
peer = recvfrom(...)
sendto(..., peer)
After many attempts to get a simple acknowledgment reply from my server this did it.
Beyond literally starting completely over each round, the time.sleep(.1) function was the only missing key. It allowed the server and client both time to close the current socket connection so that there was not an error of trying to bind multiple bodies to a single location or something.
OSError: [WinError 10048] Only one usage of each socket address (protocol/network address/port) is normally permitted
Working result:
#SERVER
import socket
import time
host = "localhost"
port = 5454
data_s = "ACKNOWLEDGMENT"
while 1:
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.bind((host, port))
received = print("Client: " + s.recv(1024).decode('utf-8')) #waiting to receive
s.close
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
time.sleep(.1)
s.sendto(bytes(data_s, 'utf-8'),(host,port)) #sending acknowledgment
print("Server: " + data_s)
s.close # close out so that nothing sketchy happens
time.sleep(.1) # the delay keeps the binding from happening to quickly
Server Command Window:
>>>
Client: hello
Server: ACKNOWLEDGMENT
Client:
#CLIENT
import socket
import time
host = "localhost"
port = 5454
c = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
while 1:
data_c = input("Client: ")
c = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
c.sendto(bytes(data_c, 'utf-8'),(host,port)) #send message
c.close
# time.sleep()
c = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
c.bind((host, port))
print("Server: " + c.recv(1024).decode('utf-8')) # waiting for acknowledgment
c.close
c = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
time.sleep(.1)
Client Command Window:
>>>
Client: hello
Client: hello
Server: ACKNOWLEDGMENT
I did finally remove the redundant input("Client: ") there at the top.
A special thanks #JoachimPileborg for helping, but I have to give it to the little guy just because it was the path I ended up taking.