Can't receive multiple messages on server using TCP socket (Python) - python-3.x

I am new to sockets and don't really know how to receive multiple messages from the same client. I only receive the first message and not the rest.
Server code:
import socket
IP = "127.0.0.1"
PORT = 65432
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind((IP, PORT))
server.listen()
while True:
communication_socket, address = server.accept()
msg = communication_socket.recv(1024).decode("utf-8")
print(msg)
Client code:
import socket
import time
HOST = "127.0.0.1"
PORT = 65432
socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
socket.connect((HOST, PORT))
socket.send("success".encode("utf-8"))
time.sleep(2)
socket.send("?".encode("utf-8"))
socket.close()

communication_socket, address = server.accept()
msg = communication_socket.recv(1024).decode("utf-8")
The current code accepts the new connection and then does a single recv. That's why it gets only the first data. What you need are multiple recv here after the accept.
... multiple messages from the same client
TCP has no concept of messages. It is only a byte stream. There is no guaranteed 1:1 relation between send and recv, even if it might look like this in many situations. Thus message semantics must be an explicit part of the application protocol, like delimiting messages with new lines, having only fixed size messages or similar.

Related

Should I change socket options on the original socket or the new one?

Consider the following python script:
import socket
import time
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(('0.0.0.0', 9999))
s.listen()
connections = []
while True:
time.sleep(1)
conn, addr = s.accept()
connections.append(conn)
# send and receive data using open connections
According to the socket documentation:
socket.accept()
Accept a connection. The socket must be bound to an
address and listening for connections. The return value is a pair
(conn, address) where conn is a new socket object usable to send and
receive data on the connection, and address is the address bound to
the socket on the other end of the connection.
Now suppose I want to change the socket options, like:
setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
setsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF, 2048)
Should I call this method on the original socket s, the new connection conn or both of them?

Send using UDP between 2 local computers without knowing IP addresses using Python3

I'm trying to develop an app to send a json string from one computer on the wireless network to another (or a phone). The problem is it has to work without knowing the IP address of the recieving computer.
The below code works if i know the IP address to send to
# UDP Server
import socket
IP = "123.123.123.123" # Not actual IP address
PORT = 66666
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind((IP,PORT))
while True:
data, addr = sock.recvfrom(1024)
print(f"recieved message: {data} from: {addr}")
# UDP Client
import socket
IP = "123.123.123.123" # Not actual IP address
PORT = 66666
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
MSG = b"Hello there"
sock.sendto(MSG, (IP, PORT))
I can also use sock.getsockname()[0] to get the current IP address and listen to it, but what about sending?
I've read a few tutorials and some say to use 0.0.0.0 to send or listen to all addresses however nothing is recieved with this. The other idea was to use 192.0.0.1 on both ends to listen and send to the router but then I get 'OSError: [WinError 10049] The requested address is not valid in its context'
I thought about using broadcast but have read that this is very bad practice to the point where it was used from ipv6.
I read a suggestion to use multicasting but is there a way to get all IP addresses of computers on the local network in order to use this?
Any assistance would be hugely appreciated!
Thanks to help from rdas referring me to https://gist.github.com/ninedraft/7c47282f8b53ac015c1e326fffb664b5 i've managed to solve the issue with the below;
# UDP Server
import socket
PORT = 66666
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROT_UDP)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
sock.bind(("",PORT))
while True:
data, addr = sock.recvfrom(1024)
print(f"recieved message: {data} from: {addr}")
# UDP Client
import socket
PORT = 66666
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROT_UDP)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
MSG = b"Hello there"
sock.sendto(MSG, ('<broadcast>', PORT))

How to initiate a socket connection from server to client?

I have setup a tcp socket between a client and a server, very basic. Client side:
#!/usr/bin/env python3
import socket
# create a socket object
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# get local machine name
host = "81.88.95.250"
port = 25000
# connection to hostname on the port.
s.connect((host, port))
# Receive no more than 1024 bytes
msg = s.recv(1024)
s.close()
print (msg.decode('ascii'))
server side:
#!/usr/bin/env python3
import socket
# create a socket object
serversocket = socket.socket(
socket.AF_INET, socket.SOCK_STREAM)
# get local machine name
host = socket.gethostname()
port = 25000
# bind to the port
serversocket.bind((host, port))
# queue up to 5 requests
serversocket.listen(5)
while True:
# establish a connection
clientsocket,addr = serversocket.accept()
print("Got a connection from %s" % str(addr))
msg = 'Thank you for connecting'+ "\r\n"
clientsocket.send(msg.encode('ascii'))
clientsocket.close()
My target is to send notification from client to server, and that's easy. The difficult part is that I also need in some circumstances to start the connection from the server and to send a command to the client and this must be executed as soon as it is received, so I cannot setup a periodic "poll". But I'm quite confused on this part, because the client is behind a NAT, not exposed with a public IP.

Python chat application

I am trying to write a simple chat server, that takes message from 1 user and sends to all other users. The other users can simultaneously send messages and receive them.
On client side one thread continuously waits for messages and other thread sends messages.
import socket
import threading
def getMessage(s):
while True:
s.send(raw_input("Message: "))
#Main
port = 1041
host = 'localhost'
s = socket.socket()
s.connect((host, port))
background_thread = threading.Thread(target=getMessage, args=(s,))
background_thread.daemon = True
background_thread.start()
while True:
print s.recv(1024)
On server side the server, takes the incoming connection request, opens a new thread for each new request and waits for their messages, when a connection sends a message, the server broadcasts it to all other connections that are open.
import socket
from thread import *
def ClientThread(connection, clients):
while True:
message = connection.recv(1024)
connection.send("Ack\n")
broadcast(connection, clients, message)
def broadcast(connection, clients, message):
for conn in clients:
if(conn != connection):
conn.send(message)
def AcceptConnections(clients):
while True:
connection, address = s.accept()
print "Got connection from ",connection
clients.append(connection)
start_new_thread(ClientThread, (connection, clients))
#Main
print "Started server"
port = 1041
host = 'localhost'
s = socket.socket()
s.bind((host, port))
s.listen(5)
clients = []
AcceptConnections(clients)
Expected: When one client sends a message, all other connected clients receive that message, irrespective of them typing and sending a message.
Reality: Other clients receive the message only after they send 1 or 2 messages.

python3: two clients sending data to server using sockets

I'm working with 3 raspberry pi, one as a server and the two others are clients. What I want to do is to make the clients communicate with the server simultaneously, I don't want to wait for client1 communication to be done in order to launch client2 request to the server (which I succeeded to do). However, I want each client to send different data to server at the same time. I tried to use Sockets and threading, like below.
server code:
import socket
import RPi.GPIO as GPIO
from threading import Thread
# 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 :
data = conn.recv(2048)
data = data.decode('utf-8')
print ("Server received data:", data)
MESSAGE = input("Multithreaded Python server : Enter Response from Server/Enter exit:")
if MESSAGE == 'exit':
break
conn.send(str.encode(MESSAGE)) # echo
# Multithreaded Python server : TCP Server Socket Program Stub
TCP_IP = ''
TCP_PORT = 9050
BUFFER_SIZE = 2000 # Usually 1024, but we need quick response
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((TCP_IP, TCP_PORT))
s.listen(2)
threads = []
list_data=[]
while True:
print ("Multithreaded Python server : Waiting for connections from TCP clients...")
(conn, (ip,port)) = s.accept()
data = conn.recv(2048)
newthread = ClientThread(ip,port)
newthread.start()
threads.append(newthread)
list_data.append(data)
for t in threads:
t.join()
client1 code:
import socket
import RPi.GPIO as GPIO
import time
host = '192.168.0.198'
port = 9050
BUFFER_SIZE = 2000
MESSAGE = input("tcpClient1: Enter message/ Enter exit:")
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((host, port))
while MESSAGE != 'exit':
s.send(str.encode(MESSAGE))
data = s.recv(BUFFER_SIZE)
data = data.decode('utf-8')
print (" Client2 received data:", data)
MESSAGE = input("tcpClient2: Enter message to continue/ Enter exit:")
client2 code:
import socket
import RPi.GPIO as GPIO
import time
import socket
host = '192.168.0.198'
port = 9050
BUFFER_SIZE = 2000
MESSAGE = input("tcpClient2: Enter message/ Enter exit:")
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((host, port))
while MESSAGE != 'exit':
s.send(str.encode(MESSAGE))
data = s.recv(BUFFER_SIZE)
data = data.decode('utf-8')
print (" Client received data:", data)
MESSAGE = input("tcpClient2: Enter message to continue/ Enter exit:")
when i run, i obtain:
in the server terminal:
Multithreaded Python server : Waiting for connections from TCP clients...
[+] New server socket thread started for 192.168.0.197:47012
Multithreaded Python server : Waiting for connections from TCP clients...
[+] New server socket thread started for 192.168.0.196:47886
Multithreaded Python server : Waiting for connections from TCP clients...
in client1 terminal:
tcpClient1: Enter message/ Enter exit:begin
in client2 terminal:
tcpClient2: Enter message/ Enter exit:begin
It seems like server didn't receive or send any data.
As #Hikke mentioned in his comment, your server receives at two different places. The conn.recv call in this code snippet eats up the data that the server receiving thread is expecting. Remove data = conn.recv(2048) in your server's main loop:
while True:
print ("Multithreaded Python server : Waiting for connections from TCP clients...")
(conn, (ip,port)) = s.accept()
data = conn.recv(2048) # <== dont eat the data of your thread here!
newthread = ClientThread(ip,port)
newthread.start()
threads.append(newthread)
list_data.append(data)

Resources