I am sending a double value from C through TCP using lwIP. To accomplish that, I am using an union between a double and one string of 8 bytes (because the lwIP's function to send data is of type 'char *'). Here te code:
void process_echo_request(void *p) {
int sd = (int)p;
int RECV_BUF_SIZE = 2048;
char recv_buf[RECV_BUF_SIZE];
int n, nwrote;
union {
double dval;
char sval[sizeof(double)];
} data_to_send;
data_to_send.dval = 1e+23;
while (1) {
/* read a max of RECV_BUF_SIZE bytes from socket */
if ((n = read(sd, recv_buf, RECV_BUF_SIZE)) < 0) {
xil_printf("%s: error reading from socket %d, closing socket\r\n", __FUNCTION__, sd);
break;
}
/* break if the recved message = "quit" */
if (!strncmp(recv_buf, "quit", 4))
break;
/* break if client closed connection */
if (n <= 0)
break;
data_to_send.dval += 1e+23;
/* handle request */
if ((nwrote = write(sd, data_to_send.sval, 8)) < 0) {
xil_printf("%s: ERROR responding to client echo request. received = %d, written = %d\r\n",
__FUNCTION__, n, nwrote);
xil_printf("Closing socket %d\r\n", sd);
break;
}
}
/* close connection */
close(sd);
vTaskDelete(NULL);
I am trying to read from a Python script, but I fail on get the double value. The code:
#!/usr/bin/env python
import socket
from ctypes import *
TCP_IP = '192.168.0.10'
TCP_PORT = 1000
BUFFER_SIZE = 8
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((TCP_IP, TCP_PORT))
s.send(" ")
data = s.recv(BUFFER_SIZE)
s.close()
print float(data)
It fails with the message ValueError: could not convert string to float: �J��-�D
I know, is because the string is not a literal representation of a real value. Any idea? I need the real (double) value.
For more information, the lwIP echo server is running in a Zynq 7000 FPGA+SoC. I am running the Python code from a Debian 8. The double value is a 64 bit temperature for a sensor.
-- EDIT --
The final working code is:
#!/usr/bin/env python
import socket
from struct import *
TCP_IP = '192.168.0.10'
TCP_PORT = 1000
BUFFER_SIZE = 8
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((TCP_IP, TCP_PORT))
s.send(" ")
data = s.recv(BUFFER_SIZE)
s.close()
print unpack("d",data)[0]
you're recieving the binary representation of the double, not the string one.
You have to unpack it using struct module and the double specifier which is d. struct.unpack returns a tuple, so take first & only value to get your float
my_value = struct.unpack("d",data)[0]
note that you can even fix the endianness with < or >, not necessary if you're on the same machine or CPU type for both programs.
Related
I am trying to implement a basic UDP socket in my code to send a string. Created an UDP server in C++ to send sort of a "hello world" and a client in Python to receive it. For this, I'm using G4G's example as base, only slightly modified:
#define PORT xxxx
void initializeUDP(int stop) {
int sockfd;
const char *hello = "Hello from server.\n";
struct sockaddr_in servaddr, cliaddr;
//Initialize Winsock
WSADATA data;
WORD version = MAKEWORD(2, 2);
int wsOk = WSAStartup(version, &data);
if (wsOk != 0) {
cout << "Cannot start Winsock! " << wsOk;
return;
}
// Creating socket and binding with address
if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
perror("socket creation failed");
exit(EXIT_FAILURE);
}
memset(&servaddr, 0, sizeof(servaddr));
memset(&cliaddr, 0, sizeof(cliaddr));
servaddr.sin_family = AF_INET; // IPv4
servaddr.sin_addr.s_addr = INADDR_ANY;
servaddr.sin_port = htons(PORT);
if (::bind(sockfd, (const struct sockaddr *)&servaddr, sizeof(servaddr)) < 0)
{
perror("bind failed");
exit(EXIT_FAILURE);
}
int len;
len = sizeof(cliaddr); //len is value/result
while (globalVariableNameInPortuguese == 0) {
sendto(sockfd, (const char *)hello, 1024, 0, (const struct sockaddr *) &cliaddr, len);
}
closesocket(sockfd);
WSACleanup();
}
Also created these few lines to try to receive this string as a client in Python:
import socket
bufferSize = 1024
ip = "localhost"
port = xxxx
UDPClientSocket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
UDPClientSocket.connect((ip, port))
while True:
message, address = UDPClientSocket.recvfrom(bufferSize)
print(message)
UDPClientSocket.close()
The C++ code executes normally but I am uncertain whether it's actually doing what it should. However, if I set the IP in the Python code as "localhost" it gets stuck in recvfrom, and if I set the IP to 0.0.0.0 it gets WinError 10049. Not sure on what I'm doing wrong and how I should proceed to actually get this string.
I am creating a C server and Python client for UNIX domain datagram sockets (UDS) IPC on Ubuntu 18.04. My scenario is: Python runs as a child process created with fork-execv where C is the parent process. The Python client blocks on socket.recvfrom until data is sent by the C server. When the C server sends data to the Python client then C will block on recvfrom until Python sends data to C with sendto.
I have used UDS for a C client and a C server with no problems, but the C-Python setup is causing some problems. For this Python version I worked from an example at https://lloydrochester.com/post/c/unix-domain-socket-datagram.
I create a server socket in C and bind to it; it returns file descriptor 5:
int64_t * create_socket_server(struct sockaddr_un svaddr, int64_t retvals[])
{
int sfd, j;
ssize_t numBytes;
socklen_t len;
char buf[BUF_SIZE];
retvals[0] = 0;
retvals[1] = 0;
sfd = socket(AF_UNIX, SOCK_DGRAM, 0); /* Create server socket
if (sfd == -1)
return retvals;
if (remove(SV_SOCK_PATH) == -1 && errno != ENOENT)
return retvals;
memset(&svaddr, 0, sizeof(struct sockaddr_un));
svaddr.sun_family = AF_UNIX;
strncpy(svaddr.sun_path, SV_SOCK_PATH, sizeof(svaddr.sun_path) - 1);
if (bind(sfd, (struct sockaddr *) &svaddr, sizeof(struct sockaddr_un)) == -1)
return retvals;
retvals[0] = sfd;
retvals[1] = (int64_t)&svaddr;
return retvals;
}
I do not create or explicitly connect to the client socket on the C side.
On the Python side I bind to the client socket. Here is my Python code, following the example cited, but altered somewhat to fit my use case:
#!/usr/bin/python3
import socket
import os, os.path
csock_file = "/tmp/py_sock"
ssock_file = "/tmp/ud_ucase"
if os.path.exists(csock_file):
os.remove(csock_file)
csock = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)
csock.bind(csock_file) # Bind to the server socket
return_msg = "Got it"
while True:
(bytes, address) = csock.recvfrom(720)
msg = bytes.decode('utf-8')
print("Python received")
if msg != "Code_99":
print('address:',address,'received:',msg)
csock.sendto(str.encode(return_msg), ssock_file)
if msg == "Code_99":
print("closing")
#Close the socket
I want recvfrom to be blocking in both Python and C because Python should block until C sends, but when I leave it at blocking (the default) then Python blocks both processes when it calls (bytes, address) = csock.recvfrom(720), and C cannot continue.
If I set it to nonblocking with csock.setblocking(False) I get this error message:
(bytes, address) = csock.recvfrom(720)
BlockingIOError: [Errno 11] Resource temporarily unavailable
So my question is why does Python block both processes, and why do I get that error message in nonblocking mode?
Thanks for any help.
Explanation
why does Python block both processes ?
When your client is waiting for your server's response with recvfrom, you server just did nothing, thus server blocks at its recvfrom as well.
why do I get that error message in nonblocking mode ?
Your server/client might not be as robust as the one you quoted (i.e. from lloydrochester.com). Serveral parts broke and result in breaking the whole thing. Some of them are just about C Lang, such as Variable Declarations, Function Returning, etc. Others are about network programming, such as Buffer Sizing, Socket Internals, etc. It's not realistic to list them all and analyse one by one. Better read through K&R and BSD socket to fix them thoroughly.
However, here is an relatively simple implementation for you case, based on your codes, shown below. In addition, you might want to change the reply message to Code_99 in the 48th line of server_alice.c.
Environment
Ubuntu 18.04
gcc 7.5.0
Python 3.6.9
server_alice.c
#include <sys/un.h>
#include <sys/socket.h>
#include <ctype.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#define BUF_SIZE 720
#define SV_SOCK_PATH "ssock"
int create_socket_server(int *sfd_ptr, struct sockaddr_un *svaddr_ptr);
int main(int argc, char *argv[]) {
struct sockaddr_un svaddr, claddr;
int sfd, j;
ssize_t numBytes;
socklen_t len;
char buf[BUF_SIZE];
int64_t retvals[2];
if (create_socket_server(&sfd, &svaddr) == 0)
printf("create_socket_server...DONE\n");
else exit(0);
for (;;) {
len = sizeof(struct sockaddr);
printf("waiting clients...\n");
numBytes = recvfrom(sfd, buf, BUF_SIZE, 0, (struct sockaddr *) &claddr, &len);
if (numBytes == -1) {
fprintf(stderr, "error recvfrom");
return 4;
}
claddr.sun_path[len - sizeof(sa_family_t) - 1] = 0;
buf[numBytes] = '\0';
fprintf(stdout, "server received %ld bytes from %s, they are: \x1b[32m%s\x1b[0m\n", (long) numBytes,
claddr.sun_path, buf);
for (j = 0; j < numBytes; j++) {
buf[j] = toupper((unsigned char) buf[j]);
}
// char *reply_msg="Code_99"; # different reply message
char *reply_msg = "Hello Bob~ This is a message: blablablabla";
j = sendto(sfd, reply_msg, strlen(reply_msg), 0, (struct sockaddr *) &claddr, len);
if (j != strlen(reply_msg)) {
fprintf(stderr, "error sendto %s", strerror(errno));
}
}
exit(EXIT_SUCCESS);
}
/* Your create_socket_server, with a few changes */
int create_socket_server(int *sfd_ptr, struct sockaddr_un *svaddr_ptr) {
struct sockaddr_un svaddr;
int sfd = socket(AF_UNIX, SOCK_DGRAM, 0); // Create server socket
if (sfd == -1)
return -1;
if (remove(SV_SOCK_PATH) == -1 && errno != ENOENT)
return -1;
memset(&svaddr, 0, sizeof(struct sockaddr_un));
svaddr.sun_family = AF_UNIX;
strncpy(svaddr.sun_path, SV_SOCK_PATH, sizeof(svaddr.sun_path) - 1);
if (bind(sfd, (struct sockaddr *) &svaddr, sizeof(struct sockaddr_un)) == -1)
return -1;
memcpy(sfd_ptr, &sfd, sizeof(int));
memcpy(svaddr_ptr, &svaddr, sizeof(struct sockaddr_un));
return 0;
}
client_bob.py
#!/usr/bin/python3
import socket
import os, os.path
csock_file = "./csock"
ssock_file = "./ssock"
if os.path.exists(csock_file):
os.remove(csock_file)
csock = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)
csock.bind(csock_file) # Bind to the server socket
return_msg = "Got it"
csock.sendto(str.encode("Hello Alice! I'm coming!"), ssock_file)
# while True: # ! CATION ! If 'while(true)', there will be infinite message sending back and forth!
(bytes, address) = csock.recvfrom(720)
msg = bytes.decode('utf-8')
if msg != "Code_99":
print('address: ', address, 'received: ', msg)
csock.sendto(str.encode(return_msg), ssock_file)
if msg == "Code_99":
print("closing")
csock.close()
Server Output:
$ gcc server_alice.c && ./a.out
create_socket_server...DONE
waiting clients...
server received 24 bytes from ./csock, they are: Hello Alice! I'm coming!
waiting clients...
server received 6 bytes from ./csock, they are: Got it
waiting clients...
Client Output:
$ python3 client_bob.py
address: ssock received: Hello Bob~ This is a message: blablablabla
I need to send big fixed sized buffers from python to c/c++ code side.
From python side I have buffers in form of:
array = np.zeros([1000], dtype=np.uint8)
array = fill(array)
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('localhost', 1010))
Code below is used to recv data from connected socket from C/C++ side.From the c/c++ side I need to have this buffer as raw 1000 byte array, I don't need any headers, I need just data. Unfortunately I haven't found howto do it. In general np.tofile()- makes things I need but in file.
int recvBuffer(uint8_t *p_buff, uint32_t size, int socket)
{
uint32_t recived = 0;
uint8_t *p_curr = p_buff;
while (recived < size)
{
int ret = recv(tcp_sock, p_curr, size - recived, 0);
if (ret != -1)
{
p_curr += ret;
recived += ret;
}
else
{
return false;
}
}
return true;
}
I found solution.
I found it in np.tofile description.
np_array = np.zeros([1000], dtype=np.uint8)
np_array = fill(np_array)
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('localhost', 1010))
raw_buffer = np_array.to_bytes()
s.send(raw_buffer)
Makes exactlty what I wanted. raw_buffer - holds np.array buffer as raw c-stype buffer.
I'm trying to send json over modbus rtu (I know, it is very bad use of modbus.)
My schema is similar to:
I have connected Arduino USB to PC as COM5 and RS485 converter connected to USB-RS485 to PC as COM4.
If I read data from Arduino using QModBus application, I will see a lot
of bytes (COM4).
For control: after I send from QModBus "read holding registers" Arduino serial monitor on "Arduino usb port" (COM5) print valid string. So I mean that modbus bytes are ok:
There is my Arduino code:
#include <ArduinoJson.h>
#include <ModbusRtu.h>
#define ID 1
// assign the Arduino pin that must be connected to RE-DE RS485 transceiver
#define TXEN 2
Modbus slave(ID, 0, TXEN); // this is slave ID and RS-232 or USB-FTDI
// data array for modbus network sharing
uint16_t au16data[100];
boolean state;
String json = "{\"idx\":1430,\"nvalue\":0,\"svalue\":\"-58.00\"}";
void setup() {
slave.begin( 9600 );
StaticJsonBuffer<200> jsonBuffer;
JsonObject& root = jsonBuffer.parseObject(json);
}
void loop() {
// https://github.com/smarmengol/Modbus-Master-Slave-for-Arduino/blob/master/ModbusRtu.h#L1391
byte x = 0;
for (byte i = 0; i < json.length(); i += 2) {
uint16_t temp;
temp = word(
json[i],
json[i+1]);
au16data[x] = temp;
x++;
}
state = slave.poll( au16data, 100 );
}
But I don't know how to convert these bytes back to json string in python. My code:
import serial
import minimalmodbus
MODBUS_3 = 3 # Read holding registers
dev1 = minimalmodbus.Instrument('COM4', 1) # port name, slave address (in decimal)
dev1.serial.baudrate = 9600
dev1.serial.bytesize = 8
dev1.serial.stopbits = 1
dev1.serial.parity = serial.PARITY_NONE
dev1.debug = False
data = dev1.read_registers(0, 20, MODBUS_3)
print(data)
Code print my the same values as QModBus:
[31522, 26980, 30754, 14897, 13363, 12332, 8814, 30305, 27765, 25890, 14896, 11298, 29558, 24940, 30053, 8762, 8749, 13624, 11824, 12322]
Can you please help, how can I convert these numbers to json string as you can see in arduino serial monitor?
And how to convert python string to "uint_16t" for sending over modbus.
Thank you!
This should work:
import struct
dataStr = b''
for uint_16t in data:
dataStr += struct.pack('>I', uint_16t)
print dataStr
Output based on your supplied list:
{"idx":1430,"nvalue":0,"svalue":"-58.00"
Not sure why it is missing the closing } though...
Edit: To remove that weird whitespace you can do:
for i in dataStr:
if ord(i) != 0:
newDataStr += i
print newDataStr
My (Python) publisher:
import zmq
import time
context = zmq.Context()
socket = context.socket(zmq.PUB)
connectStr = "tcp://*:%d" % 5563
socket.bind(connectStr)
messageNum = 0
while True:
++messageNum
message = "Testing %d"%messageNum
print("Sending.. '%s'"%message)
socket.send_string(message)
time.sleep(1)
messageNum += 1
My (C++) subscriber (running in GTest):
TEST(ZeroMqPubSubTest, SubscribeGetsData)
{
// Set up the subscriber we'll use to receive the message.
zmq::context_t context;
zmq::socket_t subscriber(context, ZMQ_SUB);
// Connect to the publisher
subscriber.connect("tcp://127.0.0.1:5563");
subscriber.setsockopt(ZMQ_SUBSCRIBE, ""); // Set the filter blank so we receive everything
zmq::message_t response(0);
EXPECT_TRUE(subscriber.recv(&response));
}
I start up the publisher then start up the subscriber. The latter never returns though.
If I run a Python subscriber doing (I thought) exactly the same thing..
import zmq
context = zmq.Context()
socket = context.socket(zmq.SUB)
socket.connect ("tcp://127.0.0.1:5563")
socket.setsockopt_string(zmq.SUBSCRIBE, "")
print ("Waiting for data...")
while True:
message = socket.recv()
print ("Got some data:",message)
..it works fine:
Waiting for data...
Got some data: b'Testing 8'
Got some data: b'Testing 9'
There are two overloads of setsockopt defined in zmq.hpp:
template<typename T> void setsockopt(int option_, T const& optval)
{
setsockopt(option_, &optval, sizeof(T) );
}
inline void setsockopt (int option_, const void *optval_, size_t optvallen_)
{
int rc = zmq_setsockopt (ptr, option_, optval_, optvallen_);
if (rc != 0)
throw error_t ();
}
By providing only two arguments you implicity used the first overload, which assumes a value length of sizeof(T). This resolves to one, because "" is a zero-terminated character array. To pass in an empty string you need to use the second overload and specify a length of 0:
subscriber.setsockopt(ZMQ_SUBSCRIBE, "", 0);
Alternatively, use a zero size data type:
char none[0];
subscriber.setsockopt(ZMQ_SUBSCRIBE, none);