Inter-Process Communications between Python and C++ using local file sockets? - python

I have a c++ program which creates a local socket bound to "/tmp/.mysocket" and waits to receive data from that socket. The way it is set up, raw binary data would be sent to the socket and loaded into the following C++ structure:
struct StateVariable
{
char Name[64];
int E[8];
};
The C++ program listens for input using recvfrom:
int nBytes = recvfrom(SD,&DataReceived,sizeof(StateVariable)/sizeof(char),0,(sockaddr*)&SentFrom,&size);
The server is just using the standard AF_UNIX and SOCK_DGRAM to create the socket.
My questions is relating to python: How do I send data to the local socket bound to /tmp/.mysocket using python? I am not using AF_INET or opening a specific port for this.
I can use python's socket library to describe the socket, but I can't find any resource that discusses binding a socket to a file in python and sending data to that socket. The documentation for the socket library only discusses using AF_INET and SOCK_DGRAM for local sockets bound to a port number at 127.0.0.1, but I'm not doing that.
How do I get python to send data to a socket bound to a file? Is there an example python program that does just that (maybe a client/server pair that demonstrates this functionality)? As long as I can get python to send data to a local file socket, I can figure out the rest.

The Python socket library is a fairly thin wrapper around the socket interface you're familiar with from C++. See socket documentation.
It's going to look something like this:
import socket
import struct
s = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)
s.connect('/tmp/...')
s.send(struct.pack('64s8i', ...))

You just change AF_INET to AF_UNIX and then .connect(address) and/or .bind(address) methods accept path to a file (instead of (host, port) pair). Other then that everything else works pretty much the same.

Related

Twisted python - socket to bind to path on the filesystem

I am trying to implement a socket server that receives rsyslog messages from windows or linux os. Ryslog uses omuxsock to output logs to socket server. I want to use twisted python to implement this socket that receives windows event/linux syslog messages. All the examples i've come across documentation only shows how to bind to IP and port. I want twisted socket to bind to a socket file not ip or port. eg., file "/var/syslog.sock"
in python without using twisted this can be done using:
s = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)
s.bind("/var/syslog.sock")
has anyone implemented socket in twisted python using socket file?
With a reactor that supports IReactorUNIX you can do this either with the lower-level listenUNIX or the higher level UNIXServerEndpoint.
For example
from twisted.internet import reactor
from twisted.internet.endpoints import UNIXServerEndpoint
from twisted.internet.protocols import Factory, Protocol
e = UNIXServerEndpoint(reactor, "/var/syslog.sock")
d = e.listen(Factory.forProtocol(Protocol))
reactor.run()

How to make simple python UDP socket server?

I am trying to make a python socket server based on UDP.
The point is that we need to receive data from the Java client socket server and the python UDP protocol socket server must throw JSON data to React in the front.
I have the level of knowledge to make a simple UDP chat server, so I'm worried a lot now.
I am currently reading the django channels official documentation.
Does django-channeles provide easy configuration to use UDP protocol as well?
There is a specification for raw UDP in the docs. UDP is not reliable as some of the data may be lost, so it is not widely used. If you must use it, you have to implement a UDP consumer based on the specification using the websocket consumers as a template

How can I listen for raw ethernet frames in vanilla Python 3?

I'm doing some self-educational low-level network programming in Python. I'm using Ubuntu 18.04 and Python 3. Using this code, I'm able to send raw ethernet packets:
from socket import socket as Socket, AF_PACKET, SOCK_RAW
def send_bytes(byte_sequence):
with Socket(AF_PACKET, SOCK_RAW) as socket:
socket.bind(("enp0s31f6", 0))
socket.send(bytes(byte_sequence))
I can use this procedure to send pings. I know it's working because I can see the ping going out and receiving a response in Wireshark.
Now I want to listen for packets, like the response to my ping. How can I do this, hopefully without involving any non-standardlib libraries? I'd like the code to be as "close to the metal" as possible, so ideally I'd like to listen for the entire ethernet frame so I can parse it all by hand and figure out if it's the packet I'm looking for.
This works for me
import sys
import socket
ETH_P_ALL=3 # not defined in socket module, sadly...
s=socket.socket(socket.AF_PACKET, socket.SOCK_RAW, socket.htons(ETH_P_ALL))
s.bind(("eth0", 0))
r=s.recv(2000)
sys.stdout.write("<%s>\n"%repr(r))
The third argument when creating the socket acts as a filter on the type of incoming frames we want to capture (all of them here).
The ETH_P_ALL constant comes from /usr/include/linux/if_ether.h.

Open Raw Socket Micropython For 802.11 Packets

I am working with an ESP8266 (NodeMCU) with MicroPython and want to be able to do packet injection or send raw packets / freedom packets. I cannot find anyway to open a raw socket (usocket/socket module) or do this via the 'network' module. Is there anyway I can do this?
The normal python equivalent would be:
import socket
s = socket.socket(socket.AF_PACKET, socket.SOCK_RAW, socket.htons(0x0003))
s.bind(("wlan0", 0x0003)) #wlan0 being in monitor mode
In micropython, you can enter monitor mode (station mode) like this
import network
sta_if = network.WLAN(network.STA_IF)
But from there, you cannot send/receive any packets. Is there any way to be able to do this?
Any help is much appreciated.
Sorry for the lack of detail but I have no idea what to do from here.
I don't think you can achieve raw socket by using micropython#esp8266
One reason is the memory are very limited on esp8266. Another reason is their socket doesn't implement raw socket.
You could try to use CC3200 ports and modify it's micropython's firmware.

Is it possible to have a socket listening to two UDP IPs, one that is 127.0.0.1 (same machine) and a different computer at the same time?

An eye-tracking application I use utilizes UDP to send packets of data. I made a python socket on the same computer to listen and dump the data into a .txt file. I already have this much working.
A separate application also written in python (what the eye-tracked subject is seeing) is running on a separate computer. Because the eye-tracking application is continuous and sends unnecessary data, so far I've had to manually parse out the instances when the subject is looking at desired stimuli. I did this based on a manually synchronized start of both the stimuli and eye-tracking applications and then digging through the log file.
What I want to do is have the second computer act as a second UDP client, sending a packet of data to the socket on the eye-tracking computer everytime the subject is looking at stimuli (where a marker is inserted into the .txt file previously mentioned). Is it possible to have a socket listening to two IP addresses at one time?
Here's my socket script:
#GT Pocket client program
import datetime
import socket
now = datetime.datetime.now()
filename = 'C:\gazelog_' + now.strftime("%Y_%m_%d_%H_%M") + '.txt'
UDP_IP = '127.0.0.1' # The remote host (in this case our local computer)
UDP_PORT = 6666 # The same port as used by the GT server by default
sock = socket.socket(socket.AF_INET, #internet
socket.SOCK_DGRAM) #UDP
sock.bind( (UDP_IP, UDP_PORT) )
while True:
data, addr = sock.recvfrom( 1024) #I assume buffer size is 1024 bytes.
print "Received Message:", data
with open(filename, "a") as myfile:
myfile.write(str(data + "\n"))
sock.close()
myfile.close()
EDIT:
#abarnert I was able to bind to the host address on the Ethernet interface and send a message from computer B to computer A, but computer A was no long able to receive packets from itself. When I specified UDP_IP = '0.0.0.0' computer B was no longer able to send data across the Ethernet. When I specified UDP_IP = '' I received the `error: [Errno 10048] Only one usage of each socket address (protocol/network address/port) is normally permitted
This have to do with the script I used on the Computer B to send the data:
import socket
UDP_IP = "169.254.35.231" # this was the host address I was able to send through.
UDP_PORT = 6666
MESSAGE = "Start"
print ("UDP target IP:"), UDP_IP
print ("UDP target port:"), UDP_PORT
print ("message:"), MESSAGE
sock = socket.socket(socket.AF_INET,
socket.SOCK_DGRAM)
sock.sendto(MESSAGE, (UDP_IP, UDP_PORT) )
I didn't know where (or if at all) I needed to specify INADDR_ANY, so I didn't. But I did try once where import socket.INADDR_ANY but got ImportError: No module named INADDR_ANY
Seems like a simple issue based on your response, so I'm not sure where I'm messing up.
EDIT2: I just reread your answer again and understand why socket.INADDR_ANY doesn't work. Please disregard that part of my previous edit
EDIT3: Okay so the reason that I wasn't picking up data when specifying the host IP was that the application I was collecting data from on Computer A was still specified to send to 127.0.0.1. So I figured it out. I am still curious why 0.0.0.0 didn't work though!
No. A socket can only be bound to a single address at a time.*
If there happens to be a single address that handles both things you want, you can use a single socket to listen to it. In this case, the INADDR_ANY host (0.0.0.0) may be exactly what you're looking for—that will handle any (IPv4) connections on all interfaces, both loopback and otherwise. And even if there is no pre-existing address that does what you want, you may be able to set one up via, e.g., an ipfilter-type interface.
But otherwise, you have to create two sockets. Which means you need to either multiplex with something like select, or create two threads.
In your case, you want to specify a host that can listen to both the local machine, and another machine on the same Ethernet network. You could get your host address on the Ethernet interface and bind that. (Your machine can talk to itself on any of its interfaces.) Usually, getting your address on "whatever interface is the default" works for this too—you'll see code that binds to socket.gethostname() in some places, like the Python Socket Programming HOWTO. But binding to INADDR_ANY is a lot simpler. Unless you want to make sure that machines on certain interfaces can't reach you (which is usually only a problem if you're, e.g., building a server intended to live on a firewall's DMZ), you'll usually want to use INADDR_ANY.
Finally, how do you bind to INADDR_ANY? The short answer is: just use UDP_IP = '', or UDP_IP = '0.0.0.0' if you want to be more explicit. Anyone who understands sockets, even if they don't know any Python, will understand what '0.0.0.0' means in server code.(You may wonder why Python doesn't have a constant for this in the socket module, especially when even lower-level languages like C do. The answer is that it does, but it's not really usable.**)
* Note that being bound to a single address doesn't mean you can only receive packets from a single address; it means you can receive packets from all networks where that single address is reachable. For example, if your machine has a LAN connection, where your address is 10.0.0.100, and a WAN connection, where your address is 8.9.10.11, if you bind 10.0.0.100, you can receive packets from other LAN clients like 10.0.0.201 and 10.0.0.202. But you can't receive packets from WAN clients like 9.10.11.12 as 10.0.0.100.
** In the low-level sockets API, dotted-string addresses like '0.0.0.0' are converted to 32-bit integers like 0. Python sometimes represents those integers as ints, and sometimes as 4-byte buffers like b'\0\0\0\0'. Depending on your platform and version, the socket.INADDR_ANY constant can be either 0 or b'\0\0\0\0'. The bind method will not take 0, and may not take b'\0\0\0\0'. And you can't convert to '0.0.0.0' without first checking which form you have, then calling the right functions on it. This is ugly. That's why it's easier to just use '0.0.0.0'.
I believe you can bind a raw socket to an entire interface, but you appear to be using two different interfaces.
It's probably best to use two sockets with select().

Categories

Resources