I'd like to know how to write TCP tunnel/relay/bridge/proxy (you name it) using twisted.
I did some research in google, twisted doc/forum etc. etc but couldn't find anwser.
I already done it in pure python using socket, threading and select.
Here is code:
#!/usr/bin/env python
import socket
import sys
import select
import threading
import logging
import time
class Client(threading.Thread):
def __init__(self, client, address, id_number, dst_ip, dst_port):
self.log = logging.getLogger(__name__+'.client-%s' % id_number)
self.running = False
self.cl_soc = client
self.cl_adr = address
self.my_id = id_number
self.dst_ip = dst_ip
self.dst_port = dst_port
threading.Thread.__init__(self)
def stop(self):
self.running = 0
def run(self):
try:
self.dst_soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.dst_soc.connect((self.dst_ip,self.dst_port))
except:
self.log.error('Can\'t connect to %s:%s' % (self.dst_ip, self.dst_port))
else:
self.running = True
self.log.info('Bridge %s <-> %s created' % (
'%s:%s' % self.dst_soc.getpeername(), '%s:%s' % self.cl_adr))
try:
while self.running:
iRdy = select.select([self.cl_soc, self.dst_soc],[],[], 1)[0]
if self.cl_soc in iRdy:
buf = self.cl_soc.recv(4096)
if not buf:
info = 'Ended connection: client'
self.running = False
else:
self.dst_soc.send(buf)
if self.dst_soc in iRdy:
buf = self.dst_soc.recv(4096)
if not buf:
info = 'Ended connection: destination'
self.running = False
else:
self.cl_soc.send(buf)
except:
self.log.error('Sth bad happend', exc_info=True)
self.running = False
self.log.debug('Closing sockets')
try:
self.dst_soc.close()
except:
pass
try:
self.cl_soc.close()
except:
pass
class Server(threading.Thread):
def __init__(self, l_port=25565, d_ip='127.0.0.1', d_port=None):
self.log = logging.getLogger(__name__+'.server-%s:%s' % (d_ip,d_port))
threading.Thread.__init__(self)
self.d_ip = d_ip
if d_port == None:
self.d_port = l_port
else:
self.d_port = d_port
self.port = l_port
binding = 1
wait = 30
self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
while binding:
try:
self.s.bind(('',self.port))
except:
self.log.warning('Cant bind. Will wait %s sec' % wait)
time.sleep(wait)
else:
binding = 0
self.log.info('Server ready for connections - port %s' % d_port)
def run(self):
self.s.listen(5)
input = [self.s, sys.stdin]
running = 1
self.cl_threads = []
id_nr = 0
while running:
iRdy = select.select(input, [], [],1)[0]
if self.s in iRdy:
c_soc, c_adr = self.s.accept()
c = Client(c_soc, c_adr, id_nr, self.d_ip, self.d_port)
c.start()
self.cl_threads.append(c)
id_nr += 1
if sys.stdin in iRdy:
junk = sys.stdin.readline()
print junk
running = 0
try:
self.s.close()
except:
pass
for c in self.cl_threads:
c.stop()
c.join(5)
del c
self.cl_threads = None
self.log.info('Closing server')
if __name__ == "__main__":
logging.basicConfig(level=logging.DEBUG)
s = Server(1424, '192.168.1.6', 1424)
s.run()
this is actually, already built into twisted, from the command line you can type:
$ twistd --nodaemon portforward --port 1424 --host 192.168.1.6
to get the exact behavior you seem to be looking for.
If you'd like to roll your own, you can still use all of the bits, in twisted.protocols.portforward
Related
I made two applications ('Client' and 'Server') written in Python.
On each of them beyond main thread I created two additonal threads, which are handling operations of sending / receiving data from each TCP / UDP parts.
So for client I have written code for:
clientTCP part:
class ClientTCP:
def __init__(self, host_address: str, port: int):
self.client_socket = None
self.host_address = host_address
self.port = port
def connect_to_server(self, is_nagle_disabled: bool):
try:
self.client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
if is_nagle_disabled:
self.client_socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, True)
self.client_socket.connect((self.host_address, self.port))
except socket.error:
print('Error: probably wrong port passed for connection')
sys.exit(1)
def send_message_to_server(self, user_input: str):
try:
#print(f'MESSAGE TO SEND AS CLIENT TCP: {user_input}')
self.client_socket.sendall(bytes(user_input, 'utf-8'))
except socket.error as e:
print('OVER HERE SEND MESSAGE TCP ERROR')
print(f'Error: {e}')
self.client_socket.close()
sys.exit(1)
def receive_message_from_server(self, buffer_size: int):
data_from_server = []
while True:
byte_portion_of_data = self.client_socket.recv(buffer_size)
if byte_portion_of_data.decode("utf-8") in ['BUSY', 'READY']:
return data_from_server
elif byte_portion_of_data:
#print(f'TCP -> byte portion of data: {byte_portion_of_data.decode("utf-8")}')
data_from_server.append(byte_portion_of_data)
else:
print('Entirety of message from server received')
break
return data_from_server
def get_client_socket(self):
return self.client_socket
def __del__(self):
self.client_socket.close()
def tcp_send_data_to_server(client: ClientTCP, data_to_send: list[int], size_of_buffer: int, is_nagle_disabled: bool, stop):
try:
#print('OVER HERE TCP!!!')
client.connect_to_server(is_nagle_disabled)
client_connection_list = client.receive_message_from_server(10)
client_connection_message = ''.join([x.decode("utf-8") for x in client_connection_list])
if client_connection_message == 'BUSY':
return
elif client_connection_message == 'READY':
client.send_message_to_server(f"SIZE:{str(size_of_buffer)}")
while True:
#print("TCP!!!")
if stop():
break
message_to_send = ''.join([str(x) for x in data_to_send])
client.send_message_to_server(message_to_send)
time.sleep(1)
except ConnectionResetError:
print("Socket was closed due to some unknown reasons. Sorry. :(")
senderUDP
class SenderUDP:
def __init__(self, host_address: str, port: int):
self.client_socket = None
self.host_address = host_address
self.port = port
def connect_to_server(self):
try:
self.client_socket = socket.socket(family=socket.AF_INET, type=socket.SOCK_DGRAM)
except socket.error as e:
print(str(e))
sys.exit(1)
def send_message_to_server(self, input_to_send: str):
try:
#print(input_to_send)
#print('OVER HERE 1 UDP send')
self.client_socket.sendto(input_to_send.encode(), (self.host_address, self.port))
#print('OVER HERE 2 UDP send')
except Exception as e:
print('Error: ' + str(e))
self.client_socket.close()
sys.exit(1)
def get_client_socket(self):
return self.client_socket
def __del__(self):
self.client_socket.close()
def sending(sender: SenderUDP, data_to_send: list[int], size_of_buffer: int, stop):
try:
sender.connect_to_server()
sender.send_message_to_server(f"SIZE:{size_of_buffer}")
while True:
#print("UDP!!!")
if stop():
sender.send_message_to_server('END')
break
message_to_send = ''.join([str(x) for x in data_to_send])
sender.send_message_to_server(message_to_send)
sleep(1)
except ConnectionResetError:
print("Socket was closed due to some unknown reasons. Sorry. :(")
As for the 'Server' part:
serverTCP
import socket
import sys
import re
import time
from datetime import datetime
class ServerTCP:
def __init__(self, address, port, buffer: int):
self.server_socket = None
self.host_address = address
self.port = port
self.number_of_clients = 0
self.buffer = buffer
self.client_socket = None
self.count_bytes_from_client = 0
self.count_time_in_seconds = 0
def create_socket(self):
try:
socket.inet_aton(self.host_address)
self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.server_socket.bind((self.host_address, self.port))
except socket.error:
print('Error: ' + str(socket.error))
sys.exit(1)
def start_listening(self):
try:
self.server_socket.listen(1)
except socket.error as msg:
print('Error: ' + str(socket.error))
self.server_socket.close()
sys.exit(1)
def set_client_socket(self, client_socket):
self.client_socket = client_socket
self.count_bytes_from_client = 0
self.count_time_in_seconds = 0
self.client_socket.send('READY'.encode())
def handle_another_client(self, another_client_socket):
another_client_socket.send('BUSY'.encode())
another_client_socket.close()
def remove_client_socket(self):
self.client_socket.shutdown(socket.SHUT_WR)
self.client_socket.close()
self.buffer = 100
self.client_socket = None
def get_server_socket(self):
return self.server_socket
def get_client_socket(self):
return self.client_socket
def get_transmission_data(self):
return self.count_bytes_from_client / 1000, self.count_time_in_seconds
def __del__(self):
self.server_socket.shutdown(socket.SHUT_RDWR)
self.server_socket.close()
print("Server socket closed")
def __str__(self):
kbytes, time = self.get_transmission_data()
return f"TCP: {kbytes} per {time} seconds"
def tcp_get_data_from_client(server: ServerTCP):
# data_from_client = []
try:
start = datetime.now()
while True:
byte_portion_of_data = server.client_socket.recv(server.buffer)
if not byte_portion_of_data:
break
# data_from_client.append(byte_portion_of_data)
string_data_from_client = byte_portion_of_data.decode('utf-8')
if string_data_from_client.startswith('SIZE:'):
temp = re.findall(r'\d+', string_data_from_client[5:])
res = list(map(int, temp))
if len(res) != 0:
server.buffer = res[0]
start = datetime.now()
else:
server.count_bytes_from_client += len(string_data_from_client)
#print('End of the ServerTCP loop')
time.sleep(0)
end = datetime.now()
server.count_time_in_seconds += (end - start).total_seconds()
print(server)
server.remove_client_socket()
except ConnectionResetError:
print("Socket was closed due to some unknown reasons. Sorry. :(")
receiverUDP
import socket
import struct
import sys
import re
import time
from datetime import datetime
class ReceiverUDP:
def __init__(self, group, port: int, buffer: int):
self.group = group
self.port = port
self.socket = None
self.buffer = buffer
self.count_bytes_from_client = 0
self.count_time_in_seconds = 0
self.start = None
def starting(self):
try:
self.socket = socket.socket(family=socket.AF_INET, type=socket.SOCK_DGRAM)
self.socket.bind((self.group, self.port))
except socket.error as e:
print(f'Error: {str(e)}')
def get_transmission_data(self):
return self.count_bytes_from_client / 1000, self.count_time_in_seconds
def clean_transmission_data(self):
self.count_bytes_from_client = 0
self.count_time_in_seconds = 0
def close_of_receiver(self):
try:
self.socket.close()
except socket.error as e:
print(f'Error: {str(e)}')
def __str__(self):
kbytes, time = self.get_transmission_data()
return f"UDP: {kbytes} per {time}"
def receiving(receiver: ReceiverUDP, stop_thread):
is_first_client = True
try:
#print('Start of ReceiverUDP')
while True:
#print('Before recvfrom, ReceiverUDP')
#print(f'Start buffer: {receiver.buffer}')
data = receiver.socket.recvfrom(receiver.buffer)
message = data[0].decode("utf-8")
print(f"Server UDP, message: {message}")
if message.startswith("SIZE:"):
temp = re.findall(r'\d+', message[5:])
res = list(map(int, temp))
print(f'New buffer: {res[0]}')
if len(res) != 0:
if is_first_client:
receiver.start = datetime.now()
is_first_client = False
receiver.buffer = res[0]
print(f'New buffer assigned: {receiver.buffer}')
elif message.__contains__("END"):
receiver.count_time_in_seconds += (datetime.now() - receiver.start).total_seconds()
receiver.start = datetime.now()
print(receiver)
else:
receiver.count_bytes_from_client += len(message)
#print(f"Message from Server: ")
time.sleep(0)
except ConnectionResetError:
print(receiver)
print("Socket was closed due to some unknown reasons. Sorry. :(")
Static methods are of course 'thread' methods also.
Now back into the problem. I read on the internet that UDP transmission should be much faster than TCP. But that's not the case, in fact it's complete opposite for me.
When I put Server part on the container and run it + launched client with 'typed host_address' of docker gateway (it's something like 172.16.0.1') I got the same thing as earlier on running both on my machine.
On server application output I got such statistics for both TCP and UDP:
TCP: 2.3kB per 15.004 sec
UDP: 1.5kB per 15.009 sec
So clearly even now UDP is much slower than TCP. Why is that and what I did wrong?
I would be grateful for all advices.
Python UDP throughput is much slower than TCP throughput
This is to be expected. TCP is optimized for low overhead and will combine multiple send into as few packets on the wire as possible. With UDP instead each send will result in a single packet with all the overhead.
This overhead is especially noticable if the datagrams (i.e. the payload of send) are significantly smaller than the MTU of the link. And from a short look at your code it looks like that your are sending several small datagrams.
Apart from that it looks like you assume that a single send in the sender will match a single recv in the recipient. This is not true for TCP since data can be combined to reduce overhead: TCP is not a message protocol but an unstructured byte stream. The assumption is more or less true with UDP, but contrary to TCP there might be packet loss, packet reordering and duplication which you currently don't account for.
This program has both the ChatServer class and ChatClient class in the same file, and should be called in the terminal by --name=server --port=8800 for the server and --name=client1 --port=8800 for the client. The problem comes from the client class not being able to complete a try:
When running the program with server name, it seems to work fine. When it runs with client name, I get the output Failed to connect to chat server # port 8800.
You can find where this except statement lies.
import select
import socket
import sys
import signal
import _pickle as cPickle
import struct
import argparse
SERVER_HOST = 'localhost'
CHAT_SERVER_NAME = 'server'
# Some utilities
def send(channel, *args):
buffer = cPickle.dumps(args)
value = socket.htonl(len(buffer))
size = struct.pack("L", value)
channel.send(size)
channel.send(buffer)
def receive(channel):
size = struct.calcsize("L")
size = channel.recv(size)
try:
size = socket.ntohl(struct.unpack("L", size)[0])
except struct.error as e:
return ''
buf = ""
while len(buf) < size:
buf = channel.recv(size - len(buf))
return cPickle.loads(buf)[0]
class ChatServer(object):
def __init__(self, port, backlog=5):
self.clients = 0
self.clientmap = {}
self.outputs = []
self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# Enable re-using socket address
self.server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.server.bind((SERVER_HOST, port))
print('Server listening to port: %s...' % port)
self.server.listen(backlog)
# Catch keyboard interrupts
signal.signal(signal.SIGINT, self.sighandler)
def sighandler(self, signum, frame):
# Close the server
print("Shutting down server...")
# Close existing client sockets
for output in self.outputs:
output.close()
self.server.close()
def get_client_name(self,client):
info = self.clientmap[client]
host, name = info[0][0], info[1]
return '#'.join((name, host))
def run(self):
inputs = [self.server, sys.stdin]
self.outputs = []
running = True
while running:
try:
readable, writeable, exceptional = select.select(inputs, self.outputs, [])
except select.error as e:
break
for sock in readable:
if sock == self.server:
# handle the server socket
client, address = self.server.accept()
print("Chat Server: got connection %d from %s" % (client.fileno(), address))
# Read the login name
cname = receive(client).split('NAME: ')[1]
# Compute client name ad send back
self.clients += 1
send(client, 'CLIENT: ' + str(address[0]))
inputs.append(client)
self.clientmap[client] = (address, cname)
# Send joining information to other clients
msg = "\n(Connected: New client (%d) from %s)" % (self.clients, self.get_client_name(client))
for output in self.outputs:
send(output, msg)
self.outputs.append(client)
elif sock == sys.stdin:
# Handle standard input
junk = sys.stdin.readline()
running = False
else:
# Handle all other sockets
try:
data = receive(sock)
if data:
# Send as new client's message..
msg = '\n[' + self.get_client_name(sock) + ']>>' + data
# Send data to all except ourself
for output in self.outputs:
if output != sock:
send(output, msg)
else:
print("Chat server: %d hung up" % sock.fileno())
self.clients -= 1
sock.close()
inputs.remove(sock)
self.outputs.remove(sock)
# Sending client leaving info to others
msg = "\n(Now hung up: Client from %s" % self.get_client_name(sock)
for output in self.outputs:
send(output, msg)
except socket.error as e:
# Remove
inputs.remove(sock)
self.outputs.remove(sock)
self.server.close()
class ChatClient(object):
def __init__(self, name, port, host=SERVER_HOST):
self.name = name
self.connected = False
self.host = host
self.port = port
# Initial Prompt
self.prompt = '[' + '#'.join((name, socket.gethostname().split('.')[0])) + ']> '
# Connect to server at port
try:
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.sock.connect((host, self.port))
print("Now connected to chat server# port %d" % self.port)
self.connected = True
# Send by name...
send(self.sock, 'NAME: ' + self.name)
data = receive(self.sock)
# Contains client address, set it
addr = data.split('CLIENT: ')[1]
self.prompt = '[' + '#'.join((self.name, addr)) + ']>'
except socket.error as e:
print("Failed to connect to chat server # port %d" % self.port)
sys.exit(1)
def run(self):
while self.connected:
try:
sys.stdout.write(self.prompt)
sys.stdout.flush()
# Wait for input from stdin and socket
readable, writable, exceptional = select.select([0, self.sock], [], [])
for sock in readable:
if sock == 0:
data = sys.stdin.readline().strip()
if data:
send(self.sock, data)
elif sock == self.sock:
data = receive(self.sock)
if not data:
print('Client shutting down')
self.connected = False
break
else:
sys.stdout.write(data + '\n')
sys.stdout.flush()
except KeyboardInterrupt:
print("Client interrupted")
self.sock.close()
break
if __name__ == "__main__":
parser = argparse.ArgumentParser(description='Socket Server Example with Select')
parser.add_argument('--name', action="store", dest="name", required=True)
parser.add_argument('--port', action="store", dest="port", type=int, required=True)
given_args = parser.parse_args()
port = given_args.port
name = given_args.name
if name == CHAT_SERVER_NAME:
server = ChatServer(port)
server.run()
else:
client = ChatClient(name=name, port=port)
client.run()
I am writing a Python based application for which I am using socket programming.
I am following below approach.
Created 1 TCP/IP server, 1 controller TCP/IP client thread and 3 TCP/IP Clients threads.
I want the application to work like this. Whenever controller sends a message it gets broadcast to all 3 TCP/IP clients. Upon received message from controller the client threads perform some task and send data to the server.
Now server has to send this data to controller thread.
The communication part for of the clients and controller is working fine.
Only problem which I am facing is server is putting all the data received from clients to controller socket together.
I want server should put 1 Client thread's data on controller socket, Wait for that data to be picked up. Then place next thread's data.
So far I am using SOCK_STREAM for sockets.
Library:-
#!/usr/bin/python
import select, socket, sys, Queue, errno
usable_port_start = 40000
Internal_ip = "127.0.0.1"
class getTCPports(object):
def __init__(self,starting_port=usable_port_start,address=Internal_ip):
super(getTCPports, self).__init__()
self.IP_address = address
i = 1
delta = 0
while i <= 1:
delta += 2
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
try_port=starting_port + delta
s.bind((self.IP_address,try_port))
self.free_port=try_port
i+=1
except socket.error as e:
if e.errno == errno.EADDRINUSE:
print("Port" , try_port , "is already in use")
else:
# something else raised the socket.error exception
print(e)
s.close()
class IPCLib(getTCPports):
server_port = 0
controller_port = 0
client_map = {}
def __init__(self):
super(IPCLib,self).__init__()
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.socket.bind((self.IP_address, self.free_port))
self.inputs = [self.socket]
self.is_alive = True
self.broadcast_list = []
#classmethod
def modify_server_port(cls,port):
cls.server_port = port
#classmethod
def modify_client_port(cls,identity,port):
if 0 <= identity.find("CONTROLLER"):
cls.controller_port = port
elif 0 <= identity.find("CLIENT"):
cls.client_map[identity] = port
def start_TCP_server(self):
self.socket.setblocking(0)
self.socket.listen(10)
self.modify_server_port(self.free_port)
while self.is_alive:
inputready,outputready,exceptready = select.select(self.inputs,[],[])
for s in inputready: #check each socket that select() said has available data
if s == self.socket: #if select returns our server socket, there is a new
#remote socket trying to connect
client, address = s.accept()
self.inputs.append(client) #add it to the socket list so we can check it now
self.broadcast_list.append(client)
#print 'new client added%s'%str(address)
else:
# select has indicated that these sockets have data available to recv
data = s.recv(4096)
if data:
#print '%s Received From Client(on server)-> %s'%(data,s.getpeername()[1])
#Uncomment below to echo the recv'd data back
#to the sender... loopback!
if s.getpeername()[1]==self.controller_port:
self.broadcast(data)
else: #if sender is monitoring clients, send data to only controller
self.send_to_controller(data)
else:#if recv() returned NULL, that usually means the sender wants
#to close the socket.
s.close()
self.inputs.remove(s)
#if running is ever set to zero, we will call this
server.close()
def start_TCP_client(self,identity):
self.modify_client_port(identity,self.free_port)
self.socket.connect((self.IP_address,self.server_port))
def stop_TCP_client(self):
self.socket.shutdown(socket.SHUT_RDWR)
self.socket.close()
def broadcast(self,message):
for client in self.broadcast_list:
if client.getpeername()[1]!=self.controller_port:
try:
client.send(message)
except:
client.close()
# if the link is broken, we remove the client
remove(clients)
def send_to_controller(self,message):
for client in self.broadcast_list:
if client.getpeername()[1]==self.controller_port:
try:
client.send(message)
except:
client.close()
# if the link is broken, we remove the client
remove(clients)
def send_data(self,data):
self.socket.send(data)
def receive_data(self):
message = self.socket.recv(4096)
return message
Driver Program:-
#!/usr/bin/python
from IPCLib import *
import threading
import os
import time
def run_server():
i1=IPCLib()
print("Task assigned to thread: {}".format(threading.current_thread().name))
print("ID of process running task: {}".format(os.getpid()))
i1.start_TCP_server()
def run_controller(identity):
i1=IPCLib()
print("Task assigned to thread: {}".format(threading.current_thread().name))
print("ID of process running task: {}".format(os.getpid()))
i1.start_TCP_client(identity)
print("server port " , i1.server_port)
print("controller port", i1.controller_port)
print("bsc info", i1.client_map)
time.sleep(1)
while i1.is_alive:
i1.send_data("hello")
print"Next Clock"
sender_map={}
sender_list = []
sender_list = i1.client_map.values()
for sender in sender_list:
sender_map[sender] = False
i=1
#print any(sender_map.values())
while any(value == False for value in sender_map.values()):
print("Loop Iteration %s"%i)
data = i1.receive_data()
temp = data.split(",")
port = temp.pop(0)
sender_map[int(port)] = True
data = ",".join(temp)
print("Data %s received from port %s"%(data,port))
print sender_map
i+=1
print sender_list
time.sleep(1)
i1.stop_TCP_client()
def run_monitors(identity):
i1=IPCLib()
print("Task assigned to thread: {}".format(threading.current_thread().name))
print("ID of process running task: {}".format(os.getpid()))
i1.start_TCP_client(identity)
print("server port " , i1.server_port)
print("controller port", i1.controller_port)
print("bsc info", i1.client_map)
while i1.is_alive:
if i1.receive_data():
output = "%d"%i1.free_port
output = output + "," + "Hello"
i1.send_data(output)
i1.stop_TCP_client()
# creating thread
t1 = threading.Thread(target=run_server, name='server')
t3 = threading.Thread(target=run_monitors, name='Client1',args=("CLIENT-1",))
t4 = threading.Thread(target=run_monitors, name='Client2',args=("CLIENT-2",))
t5 = threading.Thread(target=run_monitors, name='Client3',args=("CLIENT-3",))
t6 = threading.Thread(target=run_monitors, name='Clinet4',args=("CLIENT-4",))
#make threads deamons
t1.daemon = True
t3.daemon = True
t4.daemon = True
t5.daemon = True
t6.daemon = True
# starting threads
try:
t1.start()
time.sleep(0.1)
t3.start()
time.sleep(0.1)
t4.start()
time.sleep(0.1)
t5.start()
time.sleep(0.1)
t6.start()
time.sleep(0.1)
run_controller("CONTROLLER")
except KeyboardInterrupt:
t1.is_alive = False
t3.is_alive = False
t4.is_alive = False
t5.is_alive = False
t6.is_alive = False
How can I force server to wait till the time there is already some data on the socket?
I have a Multihtreaded Server with python that can handle clients request, but i have a problem with this.
In my Server Class I have a start function that start listening to clients like this:
class Server:
def __init__(self, clients={}):
self.clients = clients
self.ip = 'localhost'
self.port = ****
self.pattern = '(C\d)'
def start(self):
self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.s.bind((self.ip, self.port))
self.s.listen(10)
while 1:
clientsock, addr = self.s.accept()
print ('Connected with ' + addr[0] + ':' + str(addr[1]))
_thread.start_new_thread(self.handler, (clientsock, addr))
def handler(self, clientsock, addr):
data = clientsock.recv(BUFF)
print ('Data : ' + repr(data))
data = data.decode("UTF-8")
result = re.match(self.pattern, data)
print (data)
if(result):
self.registerClient(clientsock, data)
if(data == "Exit"):
self.exitClient(clientsock)
def server_response(self, message, flag, err):
if(flag):
res = message.encode('utf-8')
return res
else:
res = message.encode('utf-8')+ "[ ".encode('utf-8')+err.encode('utf-8')+ " ]".encode('utf-8')
return res
def registerClient(self, clientsock, data):
if(data in self.clients):
err = "Error : Client Name Exist!"
clientsock.send(self.server_response('Reg#NOK#', 0, err))
clientsock.close()
sys.exit(1)
self.clients[clientsock] = data
clientsock.send(self.server_response('Reg#OK', 1, ''))
def exitClient(self, clientsock):
try:
f = self.clients.pop(clientsock)
clientsock.send(self.server_response('BYE#OK', 1, ''))
clientsock.close()
except KeyError:
err = "Error : Client Doesn't Connected To Server!"
clientsock.send(self.server_response('BYE#NOK#', 0, err))
clientsock.close()
sys.exit(1)
And this is my client Class:
class Client:
def __init__(self, name):
self.name = name
self.ip = '127.0.0.1'
self.next_client = None
self.s = ""
try:
self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
except:
print ('Reg#NOK#[ ' + msg[1] + ' ]')
sys.exit()
def register(self, server):
self.s.connect((server.ip, server.port))
message = self.name
try:
self.s.sendall(bytes(message, 'UTF-8'))
except (socket.error):
print ('Send Failed')
sys.exit()
reply = self.s.recv(4096)
print ("Respose From Server : " + reply.decode("utf-8") )
def exitFromServer(self, server):
message = "Exit".encode('utf-8')
try:
a = self.s.sendall(message)
except (socket.error):
print ('Send Failed')
sys.exit()
reply = self.s.recv(4096)
And this is the main file:
from server import *
from client import *
import _thread
a = Server()
_thread.start_new_thread(a.start, ())
b = Client("C1")
b.register(a)
b.exitFromServer(a)
As you can see when start function from Server class called there is no thread that can handle create Client , I mean when I use start function like this with out thread there is no way that program can go ahead in main file , I know I should use another thread here but where and how, I use Python 3.4, Thanks for helping me.
Edit
the Problem with start was Solved , Thanks from tdelaney,
but when I run this only the register function works and exitFromServer dont do anything can you tell me where is the problem.the program dosent do anything after execute register function and it seems that its wating for something.
This mean?
import threading
from server import *
from client import *
global a
a = Server()
def sServer():
global a
a.start()
def cClient():
global a
b = Client("C1")
b.register(a)
s = threading.Thread(name='server', target=sServer)
c = threading.Thread(name='client', target=cClient)
s.start()
c.start()
In Server Class I must add another while True loop after handler function cause it shuould do all client request till client has request:
def handler(self, clientsock, addr):
while 1:
data = clientsock.recv(BUFF)
print ('Data : ' + repr(data))
data = data.decode("UTF-8")
result = re.match(self.pattern, data)
if(result):
self.registerClient(clientsock, data)
if(data == "Exit"):
self.exitClient(clientsock)
break
iv created a simple async client and server but im unable to get the client to reply after receiving the first time. It seems the server can send back a reply after receiving from the client but the client cant:
here is the client's session:
[mike#mike Public]$ python cl.py
buf got your stuff
dded callback ## this is a log addded to see if execution got where i wanted
and here is the server's log:
[mike#mike Public]$ python that.py
buf ehlo localhost
i was expecting some sort of ping pong effect where one send then the other then rinse lather repeat.
here is the client's code:
import socket
import fcntl, os, io, time, functools
from tornado import ioloop
class Punk(object):
def __init__(self):
self.loop = ioloop.IOLoop.instance()
self.address = 'blah.sock'
self.authkey = "none"
self.sock = socket.socket(socket.AF_UNIX)
def setup(self):
self.sock.connect(self.address)
fcntl.fcntl(self.sock, fcntl.F_SETFL, os.O_NONBLOCK)
self.sock.sendall("ehlo localhost")
self.fd = self.sock.fileno()
self.loop.add_handler(self.fd,self.reader,self.loop.READ)
self.loop.start()
def reader(self,fd,event):
result = b""
if event == self.loop.READ:
try:
while True:
servrep = self.sock.recv(1024)
if not servrep:
break
result += servrep
self.prnt(result)
break
except Exception as e:
print "this %s happend"%e
return
def prnt(self,buf):
print "buf %s"%buf
tim = time.time() + 2
self.loop.instance().add_timeout(tim, self.reply)
#callbac = functools.partial(self.loop.add_timeout,tim,self.reply)
#self.loop.add_callback(self.reply) ### i tried this too
print "added callback"
def reply(self):
self.sock.sendall(" clent got your stuff")
if __name__ == "__main__":
bob = Punk()
bob.setup()
and here is the server:
import socket
import fcntl, os, io, time, functools
from array import array
from tornado import ioloop
class Player(object):
def __init__(self):
self.loop = ioloop.IOLoop.instance()
self.address = 'blah.sock'
self.authkey = "none"
self.sock = socket.socket(socket.AF_UNIX)
def setup(self):
self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR,1)
self.sock.bind(self.address)
fcntl.fcntl(self.sock, fcntl.F_SETFL, os.O_NONBLOCK)
self.sock.listen(1)
self.fd = self.sock.fileno()
self.loop.add_handler(self.fd,self.reader,self.loop.READ)
self.loop.start()
def reader(self,fd,event):
result = b""
if event == self.loop.READ:
self.conn, self.addr = self.sock.accept()
try:
while True:
maxrep = self.conn.recv(1024)
if not maxrep:
break
result += maxrep
self.prnt(result)
break
except Exception as e:
print "this %s happend"%e
return
def prnt(self,buf):
print "buf %s"%buf
tim = time.time() + 2
self.loop.instance().add_timeout(tim, self.reply)
#callbac = functools.partial(self.loop.add_timeout,tim,self.reply)
#self.loop.add_callback(callbac)
def reply(self):
self.conn.sendall("got your stuff")
if __name__ == "__main__":
bob = Player()
bob.setup()
i had set my sockets to nonblock mode, but i did not catch an error when accepting from
a nonblock state when there is no connection:
here:
def reader(self,fd,event):
result = b""
if event == self.loop.READ:
self.conn, self.addr = self.sock.accept()
should be
def reader(self,fd,event):
result = b""
if event == self.loop.READ:
try:
self.conn, self.addr = self.sock.accept() # we get stuck here
self.connl.append(self.conn)
except Exception as e:
pass