Persistent socket connection in Lua/Python - python

I'm trying to create a persistent socket connection between a Lua client and Python server. Effectively a script that'll constantly ping the server with keepalive messages
My current issue is that the socket closes after each connection without a means to reopen it for transmission.
Lua Client:
local HOST, PORT = "localhost", 9999
local socket = require('socket')
-- Create the client and initial connection
client, err = socket.connect(HOST, PORT)
client:setoption('keepalive', true)
-- Attempt to ping the server once a second
start = os.time()
while true do
now = os.time()
if os.difftime(now, start) >= 1 then
data = client:send("Hello World")
-- Receive data from the server and print out everything
s, status, partial = client:receive()
print(data, s, status, partial)
start = now
end
end
Python Server:
import socketserver
class MyTCPHandler(socketserver.BaseRequestHandler):
def handle(self):
self.data = self.request.recv(1024).strip()
print("{} wrote".format(self.client_address[0]))
print(self.data)
print(self.client_address)
# Send back some arbitrary data
self.request.sendall(b'1')
if __name__ == '__main__':
HOST, PORT = "localhost", 9999
# Create a socketserver and serve is forever
with socketserver.TCPServer((HOST, PORT), MyTCPHandler) as server:
server.serve_forever()
The expected result is a keepalive ping every second to ensure the client is still connected to the server.

I ended up finding a solution.
The problem seems to have been with the socketserver library in Python. I switched it to raw sockets and things began working how I wanted them to. From there I created threads to handle the back and forth in the background
Python Server:
import socket, threading
HOST, PORT = "localhost", 9999
# Ensures the connection is still active
def keepalive(conn, addr):
print("Client connected")
with conn:
conn.settimeout(3)
while True:
try:
data = conn.recv(1024)
if not data: break
message = data.split(b',')
if message[0] == b'ping':
conn.sendall(b'pong' + b'\n')
except Exception as e:
break
print("Client disconnected")
# Listens for connections to the server and starts a new keepalive thread
def listenForConnections():
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
sock.bind((HOST, PORT))
while True:
sock.listen()
conn, addr = sock.accept()
t = threading.Thread(target=keepalive, args=(conn, addr))
t.start()
if __name__ == '__main__':
# Starts up the socket server
SERVER = threading.Thread(target=listenForConnections)
SERVER.start()
# Run whatever code after this
The Lua client didn't change in this scenario

Related

Python socket server can only receive one message from client

I am currently developping a chat program, and I have a problem.
The server can only receive one information from the client and then stop receiving information.
here's my code :
Server.py
import socket
import threading
# Some base important value
ip = '0.0.0.0'
port = 25565
encoding = 'utf-8'
# Some runtime value
clientList = []
is_server_running = True
# a class representing a client
class ClientThread(threading.Thread):
conn = None
addr = None
# Use to init the thread and the main client value
def __init__(self, conn, addr):
threading.Thread.__init__(self)
self.conn = conn
self.addr = addr
print(f"Successfully created client thread for client {self.addr[0]}:{self.addr[1]}")
# Use to receive and send data
def run(self):
while True:
try:
data = self.conn.recv(1024).decode(encoding)
print(f"Got message from client ({self.addr[0]}:{self.addr[1]}) : \"{data}\"")
except Exception as e:
print(f"Got exception in client {self.addr[0]}:{self.addr[1]} : {str(e)}")
break
clientList.remove(self)
# Create a socket and bind the correct port and ip
print("Creating Server...")
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((ip, port))
s.listen(5)
print(f"Server created and launched on port {port}.")
while is_server_running:
try:
# Accept the connection and create a new client thread
conn, adrr = s.accept()
print(f"Got new connection from adress {adrr[0]}:{adrr[1]}. Creating Thread for client")
client_thread = ClientThread(conn, adrr)
client_thread.start()
clientList.append(client_thread)
except Exception as e:
print(f"Got Exception in server listening runtime : {str(e)}. Server Stopped")
is_server_running = False
break
for client in clientList:
client.conn.close()
s.close()
Client.py
import socket
# base important variables
encoding = 'utf-8'
adress = 'here is the server ip'
port = 25565
# runtime variables
is_client_running = True
# Create a socket and connects to the server
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((adress, port))
message = "Hello !".encode(encoding)
s.sendall(message)
while is_client_running:
message = input(">>> ")
s.sendall(message.encode(encoding))
Output :
Creating Server...
Server created and launched on port 25565.
Got new connection from adress -----------:----. Creating Thread for client
Successfully created client thread for client -----------:----
Got message from client (-----------:----) : "Hello !"
And then when I input something in the client console (like : Goodbye), the server receive nothing.
Thank you for your help !

Both client and server works on one file

So I have a program using sockets, it only accept connections, the server.py file listen to a client.py file, but what if I want it to do it that both files can listen and connect.
For example:
here is my server.py
def main():
print("[STARTING] Server is starting...")
""" Starting a TCP socket """
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind(ADDR)
server.listen()
print("[LISTENING] Server is listening...")
while True:
""" Accept the connection from the client """
conn, addr = server.accept()
addr = socket.gethostname()
print(f"[NEW CONNECTION] {addr} connected.")
and this is my client.py
def main():
""" Staring a TCP socket. """
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
while True:
""" Connecting to the server. """
client.connect(ADDR)
How can I do both of them in only one file like "Server-Client.py".
So if I want to use in one computer Server-Client.py as a client it can be use a a client,
and if I want to use Server-client.py as a server on another computer it can be use as a server and the other way around.
any ideas?
Put the server code in one function and the client code in another function. Then call the appropriate function based on whether the user asked for "client" or "server".
import sys
def client():
# client code here
def server():
# server code here
if __name__ == '__main__':
if sys.argv[1] == 'client':
client()
elif sys.argv[1] == 'server':
server()

How to get python tcp server/client to allow multiple clients on ant the same time

I have started to make my own TCP server and client. I was able to get the server and the client to connect over my LAN network. But when I try to have another client connect to make a three way connection, it does not work. What will happen is only when the first connected client has terminated the connection between, the server and the client, can the other client connect and start the chat session. I do not understand why this happens. I have tried threading, loops, and everything else I can think of. I would appreciate any advice. I feel like there is just one small thing i am missing and I can not figure out what it is.
Here is my server:
import socket
from threading import Thread
def whatBeip():
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.connect(('8.8.8.8', 0))
local_ip_address = s.getsockname()[0]
print('Current Local ip: ' + str(local_ip_address))
def clietConnect():
conn, addr = s.accept()
print 'Connection address:', addr
i = True
while i == True:
data = conn.recv(BUFFER_SIZE)
if not data:
break
print('IM Recieved: ' + data)
conn.sendall(data) # echo
whatBeip()
TCP_IP = ''
TCP_PORT = 5005
BUFFER_SIZE = 1024
peopleIn = 4
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((TCP_IP, TCP_PORT))
s.listen(peopleIn)
for client in range(peopleIn):
Thread(target=clietConnect()).start()
conn.close()
Here is my client
import socket
TCP_IP = '10.255.255.3'
TCP_PORT = 5005
BUFFER_SIZE = 1024
MESSAGE = "Hello, World!"
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((TCP_IP, TCP_PORT))
i = True
while i == True:
s.sendall(raw_input('Type IM: '))
data = s.recv(BUFFER_SIZE)
s.close()
This is your main problem: Thread(target=clietConnect()).start() executes the function clientConnect and uses it's return value as the Thread function (which is None, so the Thread does nothing)
Also have a look at:
1) You should wait for all connections to close instead of conn.close() in the end of the server:
threads = list()
for client in range(peopleIn):
t = Thread(target=clietConnect)
t.start()
threads.append(t)
for t in threads: t.join()
and to close the connection when no data is received:
if not data:
conn.close()
return
2) You probably want to use SO_REUSEADDR [ Socket options SO_REUSEADDR and SO_REUSEPORT, how do they differ? Do they mean the same across all major operating systems? , Python: Binding Socket: "Address already in use" ]
3) And have a look at asyncio for python

How to send and receive from the same socket in Python?

I'm am trying to write a client program in Python that can send and receive from the same socket, but it is always giving me the same error which address is already in use. Here is the function I'm trying to write.
def Login():
username=raw_input()
password=raw_input()
message=raw_input()
array=[username,password,message]
TCP_IP = '127.0.0.1'
TCP_PORT = 5563
BUFFER_SIZE = 1024 # Normally 1024, but we want fast response
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((TCP_IP, TCP_PORT))
array_string=pickle.dumps(array)
sock.send(array_string)
sock.close()
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind((TCP_IP, TCP_PORT))
sock.listen(1)
conn, info = sock.accept()
while 1:
data = serverSocket.recv(1024)
if not data:break
conn.send(data)
conn.close()
There is a bunch of truly newbie errors here.
You can't ever connect a TCP socket to itself. There must be two different sockets.
If you really want to get the data you sent earlier at a listening socket, this listening socket must be created, bound and configured to listen before the client side connects (or, at least, in parallel to this connect attempt, in a few seconds, so the connect attempt will try - but this very likely won't work on localhost).
You can't wait on connect and on accept in the same thread if both are blocking. The simplest approach is to separate the client side and the server side to 2 different programs and run them manually in parallel. Then, after successful debugging, you will be able to do this in different threads of the same process, or using an event-driven engine.
While you may not be able to connect a socket to itself to send and receive data, you might be able to learn from the following example inspired by your code that attempts to do something similar.
import _thread
import pickle
import socket
import time
def main():
"""Run a server in a thread and start a client to talk to it."""
_thread.start_new_thread(run_server, ('', 5563))
run_client('localhost', 5563)
def run_server(host, port):
"""Handle all incoming connections by spawning worker threads."""
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind((host, port))
server.listen(5)
while True:
_thread.start_new_thread(handle_connection, server.accept())
def handle_connection(client, address):
"""Answer an incoming question from the connected client."""
print('Incoming connection from', address)
client.settimeout(0.1)
data = recvall(client)
client.shutdown(socket.SHUT_RD)
question = pickle.loads(data)
answer = '''len(username) = {}
len(password) = {}
len(message) = {}'''.format(*map(len, question))
client.sendall(answer.encode())
client.shutdown(socket.SHUT_WR)
client.close()
print('Finished with', address)
def recvall(connection):
"""Receive all data from a socket and return as a bytes object."""
buffer = bytearray()
while True:
try:
data = connection.recv(1 << 12)
except socket.timeout:
pass
else:
if data:
buffer.extend(data)
else:
return bytes(buffer)
def run_client(host, port):
"""Collect information from question and display returned answer."""
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
time.sleep(0.1) # wait for server to start listening for clients
client.connect((host, port))
time.sleep(0.1) # wait for handler thread to display connection
username = input('Username: ')
password = input('Password: ')
message = input('Message: ')
question = pickle.dumps((username, password, message))
client.sendall(question)
client.shutdown(socket.SHUT_WR)
answer = recvall(client)
client.shutdown(socket.SHUT_RD)
client.close()
print(answer.decode())
time.sleep(0.1) # wait for handler to cleanly terminate execution
if __name__ == '__main__':
main()

How to test loopback socket connections with python?

I want to test a complex class, which wraps some methods of the socket module: connect, sendall and recv. Especially, I want to test the recv method of this class.
The working example code below shows how I could do that (in a basic, underlying form to keep it simple, testsocket would correspond to the complex wrapper class):
import socket
# This is just a socket for testing purposes, binds to the loopback device
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind(("127.0.0.1", 1234))
sock.listen(5)
# This is the socket later part of the complex socket wrapper.
# It just contains calls to connect, sendall and recv
testsocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
testsocket.connect(("127.0.0.1", 1234))
testsocket.sendall("test_send")
# The testing socket connects to a client
(client, adr) = sock.accept()
print client.recv(1024)
# Now I can do the actual test: Test the receive method of the socket
# wrapped in the complex class
client.sendall("test_recv")
print testsocket.recv(1024) # <-- This is what I want to test !!
# close everything
testsocket.close()
client.close()
sock.close()
But in order to test testsocket.recv I need to use testsocket.sendall before.
Is it possible to modify this code in a simple way (without forks or threads) in order to test testsocket.recv without using the method testsocket.sendall?
How about using socket.socketpair? :
import socket
client, testsocket = socket.socketpair()
client.sendall("test_recv")
print testsocket.recv(1024)
testsocket.close()
client.close()
NOTE only available in Unix.
Using mock
import mock
testsocket = mock.Mock()
testsocket.configure_mock(**{'recv.return_value': 'test_recv'})
print testsocket.recv(1024)
You can't run the client and the server socket in the same process/thread since the server.recv() is a blocking call
my routine :
import socket, threading
# Protocols supported
TCP = (0x00)
UDP = (0x01)
UDP_Multicast = (0x02)
# Client/ Server mode
CLIENT = (0x00)
SERVER = (0x01)
# Data to be sent
data = 'Test. Please Ignore'
# Server processing
def simple_processing(data):
print "messsage : ", data
def start_socket( protocol, client, processing_callback):
# switch on protocol
if protocol == TCP:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
else:
return
# switch on client
if client == SERVER:
# Server mode = listening to incoming datas
sock.bind(("127.0.0.1", 1234))
sock.listen(5)
(sock, adr) = sock.accept()
processing_callback( sock.recv(1024) ) # processing data
elif client == CLIENT:
# Client mode : connecting and sending data
sock.connect(("127.0.0.1", 1234))
sock.sendall(data)
else:
return
sock.close()
def test():
# Thread creations
server = threading.Thread( target = start_socket,
args=( TCP,
SERVER,
simple_processing, )
)
client = threading.Thread( target= start_socket,
args=( TCP,
CLIENT,
None)
)
server.start()
client.start()
# Join : wait on every thread to finish
client.join()
server.join()
if __name__ == '__main__':
# Launch the test
test()

Categories

Resources