I would like to write a class which inherits the functionalities of socket.
So my code looks like this:
class walkie_talkie(socket.socket(socket.AF_INET, socket.SOCK_STREAM)):
def __init__(self):
self.BUFFERSIZE = 8192
self.STATE = None
self.IP = None # Server IP
self.PORT = 5000
self.NUMBER_OF_UNACCEPTED_CONNECTIONS = 1
self.bytestream = None
super().__init__()
And I use this class as:
from walkie_talkie import walkie_talkie
rpi1 = walkie_talkie()
So I thought using super().__init__() inherits functions of socket.socket(socket.AF_INET, socket.SOCK_STREAM)
However, I receive this error:
File "...\lib\socket.py", line 151, in __init__
_socket.socket.__init__(self, family, type, proto, fileno)
TypeError: an integer is required (got type str)
Can someone tell me how to use the super function for that?
As jasonharper specified, a class can only inherit from another class, such as socket.socket. You can't inherit from an instance of a class, as you're trying to do here. The parameters you're trying to pass to socket.socket() should go in the super().__init__().
class walkie_talkie(socket.socket):
def __init__(self):
self.BUFFERSIZE = 8192
self.STATE = None
self.IP = None # Server IP
self.PORT = 5000
self.NUMBER_OF_UNACCEPTED_CONNECTIONS = 1
self.bytestream = None
super().__init__(socket.AF_INET, socket.SOCK_STREAM)
This answer was posted as an edit to the question Python super init custom socket class by the OP V.Hunon under CC BY-SA 4.0.
Related
I made the follow class:
class Client(socket.socket):
def __init__(self):
super(Client, self).__init__()
self.settimeout(None)
self.radd = None
self.port = None
self.buffersize = None
def connect_to_server(self):
self.connect((self.radd, self.port))
def configure(self, radd:str, port=49305, buffersize=2048):
# close the socket
self.close()
# assign a new configuration
self.radd = radd
self.port = port
self.buffersize = buffersize
and i used it as follow:
c = Client()
c.configure('192.168.1.1')
c.connect_to_server()
but i get the error: [WinError 10038]
Can anyone tell me why this happens?
Error 10038 is WSAENOTSOCK.
An operation was attempted on something that is not a socket.
It is happening because you are closing the socket before you connect. If you call close(), you have to create a new socket after that.
class Socket:
def __init__(self, ip, port, auto_connect=False):
self.ip = ip
self.port = port
self.sockfd = socket.socket()
if auto_connect:
self.connect()
#staticmethod
def connect(sockfd, ip, port):
sockfd.connect((ip, port))
#nonstaticmethod
def connect(self):
self.sockfd.connect((self.ip, self.port))
Similar to how other languages like Dlang do it where you can define functions that have the same names; but different signatures, thus allowing the compiler to distinguish what function ambiguous function calls refer to.
I had the thought that you could somehow imitate properties, because they allow for you to enact on the same function but use different inputs and receive different outputs. But since the #property tag isn't Python, and recreating it in C isn't something very feasible nor efficient work-wise; I'm seeking a way to do it either purely or with 3rd-party libraries.
class Socket:
def __init__(self, ip, port, auto_connect=False):
self.ip = ip
self.port = port
self.sockfd = socket.socket()
if auto_connect:
self.connect()
#staticmethod
def static_connect(sockfd, ip, port):
sockfd.connect((ip, port))
def connect(self):
self.sockfd.connect((self.ip, self.port))
I did as well figure that you could just name the functions differently but I just don't like this approach since it involves the user knowing that the secondary function exists and although sensible, not my style.
Also I did suggest to myself the fact that I could do something along the lines of this:
class Socket:
...
def connect(self, ip, port):
"""
When using statically:
self = socket
ip = ip
port = port
When using as a class member:
ip = ip & port = port
"""
if isinstance(self, types.ClassType):
self.sockfd.connect((ip, port))
return
self.connect((ip, port))
But that's just unnatural and could cause confusion when somebody reads the code, and is over-all unPythonic.
NOTE: This function replicates behaviour shown in here but it luckily manages to utilize all the parameters and thus no optional parameters are required, so apologies for not mentioning it explicitly, but my question doesn't ask for a way to do it with key word arguments.
tl;dr:
class functions that have different signatures e.g.: static method but don't replace each other- and yet still can be called appropriately
How about a method with default keyword arguments ?
class Socket:
def __init__(self, ip, port, auto_connect=False):
self.ip = ip
self.port = port
self.sockfd = socket.socket()
if auto_connect:
self.connect()
def connect(sockfd=self.sockfd, ip=self.ip, port=self.port):
sockfd.connect((ip, port))
passed arguments will override defaults, but otherwise when called without arguments will use its default parameters.
Is that a solution that can work for you ?
When I create a socket in python (a simple TCP socket for example), can I call / use it in another class? And if not, how can I do it?
Thanks from a python beginner ^^
Python has no concept of 'private' data members. Accessing members of a class is as simple as using their name, ie:
import socket
class A:
def __init__(self):
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
class B:
def send(self, host, port):
# send msg through A
a = A()
a.sock.connect((host, port))
a.sock.sendall('Hello, world')
I'm confused as to how to send a variable to a TCPHandler using SocketServer.TCPServer in python..
HOST, PORT = hosts[0], args.port
server = SocketServer.TCPServer((HOST, PORT), METCPHandler)
server.serve_forever()
Which calls:
class METCPHandler(SocketServer.BaseRequestHandler):
def handle(self):
self.data = self.request.recv(1024).strip()
print "{} wrote:".format(self.client_address[0])
r = MExpressHandler(self.data, False)
But I want to pass a debug boolean to MExpressHandler.. so
HOST, PORT = hosts[0], args.port
server = SocketServer.TCPServer((HOST, PORT), METCPHandler(debug))
server.serve_forever()
Fails. Whats the correct way of doing this? Do I have to recreate a whole TCPHandler over-ridding __init__?
Trust your instincts, the correct way is indeed to subclass TCPServer and override the __init__ method, but Python makes this very easy!
import SocketServer
class DebugTCPServer(SocketServer.TCPServer):
def __init__(self, server_address, RequestHandlerClass, bind_and_activate=True, debug=True):
self.debug = debug
SocketServer.TCPServer.__init__(self, server_address, RequestHandlerClass, bind_and_activate=True)
class DebugMETCPHandler(SocketServer.BaseRequestHandler):
def handle(self):
# self.server is an instance of the DebugTCPServer
DEBUG = self.server.debug
self.data = self.request.recv(1024).strip()
if DEBUG:
print "{} wrote:".format(self.client_address[0])
r = MExpressHandler(self.data, False)
server = DebugTCPServer((HOST, PORT), DebugMETCPHandler, debug=True)
or since we specified debug=True as the default:
server = DebugTCPServer((HOST, PORT), DebugMETCPHandler)
As I proposed in this post already, it is possible to do it without sub-classing the TCPServer. It is in fact more concise and generic.
You can give parameters to your handler this way:
class METCPHandler(SocketServer.BaseRequestHandler):
def __init__(self, debug):
self.debug = debug
def __call__(self, request, client_address, server):
h = METCPHandler(self.debug)
SocketServer.StreamRequestHandler.__init__(h, request, client_address, server)
You can now give an instance of your handler to the TCPServer:
SocketServer.TCPServer((HOST, PORT), METCPHandler(True))
The TCPServer normally creates a new instance of METCPHandler per request but in this case, the __call__ method will be called instead of the constructor (it is already an instance.)
In the call method, I explicitly make a copy of the current METCPHandler and pass it to the super constructor to conform to the original logic of "one handler instance per request".
It is worth having a look at the SocketServer module to understand what happens here: https://github.com/python/cpython/blob/2.7/Lib/SocketServer.py
Short Question
Using my examples below, is there a Pythonic way to share my_object's actual instance with with the BaseRequestHandler class?
Background
By definition, the BaseRequestHandler class creates a new instance for each request. Because of this, I am struggling to try find a solution on how to get data from the handle() function back to the ProtocolInterface instance. Note that this might be the wrong approach if I am needing to do something in handle() other than print to stdout.
At this point in time, I do not believe that global variables will work because my_object is passed in and is expected to change often (this is why handle() needs to see it. To see an example client (sending bogus data) see my other SO question. I think the biggest issue I am facing is the the socketservers are running in a background thread.
Example of what I would like to do
class ProtocolHandler(SocketServer.BaseRequestHandler):
def handle(self):
while(1):
self.data = self.request.recv(1024)
if self.data == '':
break
self.request.send("Success")
self.my_object.success = True# <--- How can I share my_object's instance?
class ProtocolInterface():
def __init__(self, obj, host='127.0.0.1', port=8000, single_connection=False):
self.my_object = obj # <--- This ideally is the same instance seen in ProtocolHandler
self.host = host
self.port = port
# Create the socket server to process in coming traffic
if(single_connection):
self.server = SocketServer.TCPServer((self.host, self.port), ProtocolHandler)
else:
self.server = SocketServer.ThreadingTCPServer((self.host, self.port), ProtocolHandler)
def start(self):
print "Server Starting on HOST: " + self.host
server_thread = threading.Thread(target=self.server.serve_forever)
server_thread.daemon = True
server_thread.start()
You could pass the object through the server instance:
self.server = SocketServer.TCPServer((self.host, self.port), ProtocolHandler)
self.server.my_object = self.my_object
The documentation indicates that you can have access to the server instance in handle() as self.server.