UDP Client with Socket Programming Message Error? - python

Hello l am new to BSD Socket API programming. I followed the UDP client example on the Wikipedia (https://en.wikipedia.org/wiki/Berkeley_sockets) and l am encountering a strange issue. The packets arrive at my server, but the message inside is cut off. I am looking for the terminology for this problem, and a clue to resolve this issue. Thank you for the assistance.
C Function:
void udp_client_task() {
while(1) {
int sock; struct sockaddr_in sa; char buffer[200];
strcpy(buffer,"My World NEO! This is My World!");
/* create an Internet, datagram, socket using UDP */
sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (sock == -1) {
/* if socket failed to initialize, exit */
break;
}
/* Zero out socket address */
memset(&sa, 0, sizeof sa);
/* The address is IPv4 */
sa.sin_family = AF_INET;
/* IPv4 addresses is a uint32_t, convert octets to the appropriate value */
sa.sin_addr.s_addr = inet_addr("192.168.0.5");
/* sockets are unsigned shorts, htons(x) ensures x is in network byte order */
sa.sin_port = htons(139);
bytes_sent = sendto(sock, buffer, strlen(buffer), 0,(struct sockaddr*)&sa, sizeof sa);
// osDelay(500);
close(sock); /* close the socket */
}
Python UDP Server:
import socket
from datetime import datetime
class UDP_Server():
def __init__(self, single_group, port_receive):
self.single_group = single_group
self.port_receive = port_receive
def configure_receive_server(self):
# Define the buffer size for this function
size_buffer = 1024
# Print start of function
msg = 'UDP Receive Inputs: Single Group - {0} ; Port (Receive From) - {1} ; Buffer Size - {2}'.format(self.single_group, self.port_receive, size_buffer)
print(msg)
# Open a UDP socket
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
print("Socket created...")
# Allow port reuse
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
print("Socket allowed reuse...")
# Bind IP Address to Port
print("Binding the IP: {0}".format(self.single_group))
sock.bind((self.single_group, self.port_receive))
while True:
print("------ New Loop ------")
# Receive the client packet along with the address it is coming from
message, address = sock.recvfrom(1024)
print("{0}".format(datetime.now().strftime("%Y-%m-%d_%H:%M:%S")))
msg = 'UDP message received from address - {0} ; \nMessage - {1} ; \nMessage Length - {2}'.format(address, message, len(message))
print(msg)
if __name__ == '__main__':
# Define constants
UDP_IP = "192.168.0.5"
# UDP_group = "192.168.0.5"
port_receive_tlm = 139
# port_receive_tlm = 139
# Initialize the class
commander = UDP_Server(single_group=UDP_IP,
port_receive=port_receive_tlm)
# Listen for a response
# NOTE: This will exit after a certain number of attempts
commander.configure_receive_server()

Related

How to send a base64 encoded image via tcp from python to node js?

I am basically working on a project and got stuck at this point. I tried normal tcp but later found that the image was partially transported of max length around 65,000 at node js end. But the total encoded image length is around 3 times of 65000 at python side. The image is basically a screen-shot of my desktop of resolution around 1920 x 1020.
Here is my python side code
import socket
HOST = '127.0.0.1' # Standard loopback interface address (localhost)
PORT = 9898 # Port to listen on (non-privileged ports are > 1023)
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.bind((HOST, PORT))
s.listen()
print("-- start --")
conn, addr = s.accept()
print("-- accepted --")
with conn:
print('Connected by', addr)
while True:
data = conn.recv(1024)
print("R : ", data)
if not data:
break
print("sending data")
# b64str is a pre computed string of length around 65000*3
conn.sendall(bytes(b64str, 'utf-8'))
Here is Node js side code
client.connect(9898, '127.0.0.1', function() {
console.log('CONNECTED : img-data-channel');
});
// buff is a buffer queue that stores the base64 encoded string
client.on('data', function(data) {
str_data = String.fromCharCode.apply(null, data);
buff.push_data(str_data);
// console.log("Received: img-data type : ", typeof(str_data), " size : ", str_data.length) ;
});
client.on('close', function() {
console.log('DISCONNECTED : img-data-channel');
});
Thankyou in advance.

Differences between C and Python sockets

I am working in a C program with sockets. I found a proxy python script which is working with my program:
import threading
import serial
import socket
def setup():
"""
This function sets up the variables needed, including the serial port,
and it's speed/port settings, listening socket, and localhost adddress.
"""
global clisock, cliaddr, svrsock, ser
# Change this to the COM port your XBee Cellular module is using. On
# Linux, this will be /dev/ttyUSB#
comport = '/dev/ttyAMA0'
# This is the default serial communication speed of the XBee Cellular
# module
comspeed = 9600
buffer_size = 4096 # Default receive size in bytes
debug_on = 0 # Enables printing of debug messages
toval = None # Timeout value for serial port below
# Serial port object for XBCell modem
ser = serial.Serial(comport,comspeed,timeout=toval)
# Listening socket (accepts incoming connection)
svrsock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
# Allow address reuse on socket (eliminates some restart errors)
svrsock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
clisock = None
cliaddr = None # These are first defined before thread creation
addrtuple = ('localhost', 1881) # Address tuple for localhost
# Binds server socket to localhost (allows client program connection)
svrsock.bind(addrtuple)
svrsock.listen(1) # Allow (1) connection
def ComReaderThread():
"""
This thread listens on the defined serial port object ('ser') for data
from the modem, and upon receipt, sends it out to the client over the
client socket ('clisock').
"""
global clisock
while (1):
resp = ser.read() ## Read any available data from serial port
print("Received {} bytes from modem.".format(len(resp)))
clisock.sendall(resp) # Send RXd data out on client socket
print("Sent {} byte payload out socket to client.".format(len(resp)))
def SockReaderThread():
"""
This thread listens to the MQTT client's socket and upon receiving a
payload, it sends this data out on the defined serial port ('ser') to the
modem for transmission.
"""
global clisock
while (1):
data = clisock.recv(4096) # RX data from client socket
# If the RECV call returns 0 bytes, the socket has closed
if (len(data) == 0):
print("ERROR - socket has closed. Exiting socket reader thread.")
return 1 # Exit the thread to avoid a loop of 0-byte receptions
else:
print("Received {} bytes from client via socket.".format(len(data)))
print("Sending payload to modem...")
bytes_wr = ser.write(data) # Write payload to modem via UART/serial
print("Wrote {} bytes to modem".format(bytes_wr))
def main():
setup() # Setup the serial port and socket
global clisock, svrsock
if (not clisock): # Accept a connection on 'svrsock' to open 'clisock'
print("Awaiting ACCEPT on server sock...")
(clisock,cliaddr) = svrsock.accept() # Accept an incoming connection
print("Connection accepted on socket")
# Make thread for ComReader
comthread = threading.Thread(target=ComReaderThread)
comthread.start() # Start the thread
# Make thread for SockReader
sockthread = threading.Thread(target=SockReaderThread)
sockthread.start() # Start the thread
main()
I tried to do the same proxy script in C
#include "project.h"
#include <sys/socket.h>
#include <arpa/inet.h>
int fd,baudrate=9600,sock,new_socket;
struct sockaddr_in serv_addr, client;
int setup(){
int opt=1;
sock=0;
if(wiringPiSetup() <0) return 1;
if((fd=serialOpen("/dev/ttyAMA0",baudrate))<0) return 1;
printf("Serial communication opened \n");
fflush(stdout);
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == 0)
{
printf("\n Socket creation error \n");
return -1;
}
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR , &opt, sizeof(opt)))
{
perror("setsockopt");
exit(EXIT_FAILURE);
}
memset(&serv_addr, '0', sizeof(serv_addr));
serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(1881);
int addrlen = sizeof(struct sockaddr_in);
if (bind(sock, (struct sockaddr *)&serv_addr, addrlen)<0)
{
perror("bind failed");
exit(EXIT_FAILURE);
}
if (listen(sock, 1) <0)
{
perror("listen");
exit(EXIT_FAILURE);
}
printf("1\n");
addrlen=sizeof(struct sockaddr_in);
socklen_t sin_size=sizeof(struct sockaddr_in);
if ((new_socket = accept(sock, (struct sockaddr *)&client, &sin_size)) < 0)
{
perror("accept");
exit(EXIT_FAILURE);
}
char *client_ip = inet_ntoa(client.sin_addr);
printf("Accepted new connection from a client %s:%d\n", client_ip, ntohs(client.sin_port));
printf("1\n");
return 0;
}
PI_THREAD(socketRead){
int valread;
char buffer[4096]={0};
printf("hola %i\n",new_socket);
//Nos mantenemos a la escucha
for(;;){
//memset(buffer,0,sizeof(buffer));
//valread = recv( new_socket, buffer, 1024,0);
while((valread = read(new_socket,buffer,sizeof(buffer)-1))>0){
/*if ( valread < 0 ) {
printf ( "An error occured during the receive procedure \n" ) ;
return 0 ;
}*/
buffer[valread]=0;
printf("buffer %s\n",buffer);
write(fd,buffer,strlen(buffer));
}
}
}
PI_THREAD(uartRead){
int valread;
char buffer[4096]={0};
//Nos mantenemos a la escucha
for(;;){
//memset(buffer,0,sizeof(buffer));
valread = read( fd, buffer, sizeof(buffer));
//valread = read(new_socket,buffer,4096);
//send( new_socket, buffer,4096,0);
write(new_socket,buffer,sizeof(buffer));
printf("recibido\n");
}
}
int main(){
setup();
printf("adios %i\n",new_socket);
/* Thread creation */
piThreadCreate (socketRead);
piThreadCreate (uartRead);
for(;;){}
return 0;
}
I have not found differences between both programs, so my question is if there are any differences between Python and C libraries. With Python I am allow to see read the messages but in C I only receive 0x10 and 0x11. So, are there any differences between libraries or is something with my C script?
PI_THREAD(uartRead){
...
char buffer[4096]={0};
...
valread = read( fd, buffer, sizeof(buffer));
...
write(new_socket,buffer,sizeof(buffer));
In this code you read valread byte from the serial line but you always write 4096 byte (sizeof(buffer)). This means you send not only the data from the serial line but lots of junk data which are in the buffer.
The problem is thus not the difference between sockets in Python and C but just a bug in the C program.

How can I debug latency in a UDP multicast request/reply?

I'm building a real-time wireless link between a PC base station and a dozen robots, each transmitting at 60Hz.
For testing I wrote a Python script that sends UDP multicast packets over my WiFi network. And then on another multicast group I have two ESP8266 sending replies. One sends at 60Hz to simulate the real set-up, and the other spams at 10 times that rate to simulate congestion from the other devices.
First I only looked at packet loss, which was kind of as expected. But then I started to look at round-trip time. I made my Python script write the current time, and made the "real" node echo them back. (spammer messages are ignored)
With the spammer node turned off I get 10ms round-trip, but with the spammer, it starts at 100ms and slowly grows to over a second.
How can I debug this issue?
I tried to use Wireshark, but since they are separate UDP streams with custom data in them, I could not figure out any sensible analysis.
I figured the packets probably get stuck in a queue somewhere, so some googling suggested you can look at the queue length with the following command. Sure, the queue is not empty, but if I turn the spammer node off, nothing much changes in the queue length, while round-trip drops back to 10ms.
netstat -c --udp -an
Proto Recv-Q Send-Q Local Address Foreign Address State
udp 40256 0 0.0.0.0:8080 0.0.0.0:*
I thought maybe my Python code is just too slow to handle 600 messages per second. Running on PyPy made absolutely no difference, so I'm a bit hesitant to write the whole thing in C. It has almost 2ms per packet to do almost nothing.
Base station code:
import socket
import struct
import sched, time
import threading
base_multicast = '239.255.0.34'
robot_multicast = '239.255.0.35'
port = 8080
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind(('', port))
mreq = struct.pack("4sl", socket.inet_aton(robot_multicast), socket.INADDR_ANY)
sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)
# schedule base station packets
send_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
send_sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 2)
rate = 1/60
#sock.settimeout(rate)
s = sched.scheduler(time.time, time.sleep)
def send(now):
nxt = now+rate
s.enterabs(nxt, 1, send, argument=(nxt,))
tstr = struct.pack("d", time.time())
send_sock.sendto(tstr, (base_multicast, port))
print(".", end='')
s.enter(1, 1, send, argument=(time.time(),))
t = threading.Thread(target=s.run)
t.daemon = True
t.start()
start = time.time()
avg_dur = 0
avg_ping = 0
while True:
try:
data = sock.recv(10240)
except socket.timeout:
continue
now = time.time()
duration = now-start
start = now
avg_dur = 0.99*avg_dur + 0.01*duration
try:
(t,) = struct.unpack("d", data)
ping = now-t
avg_ping = 0.99*avg_ping + 0.01*ping
print(len(data), 1/avg_dur, avg_ping)
except struct.error: # spammer message
pass
Robot node: (spammer is identical, except it sends replyPacket 10 times in a loop)
#include <ESP8266WiFi.h>
#include <WiFiUdp.h>
const char* ssid = "mywifi";
const char* password = "password";
IPAddress base_multicast(239, 255, 0, 34);
IPAddress robot_multicast(239, 255, 0, 35);
WiFiUDP Udp;
unsigned int port = 8080; // local port to listen on
char incomingPacket[255]; // buffer for incoming packets
char replyPacket[] = "Hi there! Got the message :-))))"; // a reply string to send back
int rate = 1000/60;
unsigned long mytime;
unsigned long count;
float avg_diff = 0;
void setup()
{
Serial.begin(115200);
Serial.println();
Serial.printf("Connecting to %s ", ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED)
{
delay(500);
Serial.print(".");
}
Serial.println(" connected");
//Udp.begin(localUdpPort);
Udp.beginMulticast(WiFi.localIP(), base_multicast, port);
Serial.printf("Now listening at IP %s, UDP port %d\n", WiFi.localIP().toString().c_str(), port);
mytime = millis();
}
void loop()
{
int packetSize = Udp.parsePacket();
if (packetSize)
{
// receive incoming UDP packets
unsigned long diff = micros() - mytime;
avg_diff = 0.9*avg_diff + 0.1*diff;
mytime = micros();
int rcv_rate = 1000000/avg_diff;
Serial.println(rcv_rate);
int len = Udp.read(incomingPacket, 255);
delay(random(rate));
//Serial.printf("UDP packet contents: %s\n", incomingPacket);
Udp.beginPacketMulticast(robot_multicast, port, WiFi.localIP());
Udp.write(incomingPacket, len);
Udp.endPacket();
}
}

Why can't I struct.unpack an unsigned char and a string afterwards in Python 3.x?

I'm making a server in Python for my GMS 2 project and I'm writing a client in GameMaker. But somehow when I use only:
struct.unpack('B', data[:1])[0]
It works but when I'm trying to send a string afterwards:
struct.unpack('Bs', data[:1])[0]
It gives me an following error:
mid = struct.unpack('Bs', data[:1])[0]
struct.error: unpack requires a buffer of 2 bytes
This is the entire code I'm using to receive data:
import socket
import struct
UDP_IP = "127.0.0.1"
UDP_PORT = 5555
sock = socket.socket(socket.AF_INET, # Internet
socket.SOCK_DGRAM) # UDP
sock.bind((UDP_IP, UDP_PORT))
while True:
data, addr = sock.recvfrom(1024) # buffer size is 1024 bytes
msg_id = struct.unpack('Bs', data[:1])[0]
print(msg_id)
#if mid == 0:
# struct.unpack('Bp', data[:1])[0]
And this is how I send it in GameMaker:
buffer_seek(global.Buffer, buffer_seek_start, 0);
buffer_write(global.Buffer, buffer_u8, 0); //Sends which PACKET ID we should decode
buffer_write(global.Buffer, buffer_string, global.Username); //Sends username as a "buffer_string" type
network_send_udp_raw(socket,"127.0.0.1", 5555, global.Buffer, buffer_tell(global.Buffer));

Print a Double from C in Python

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.

Categories

Resources