Skip to content

Instantly share code, notes, and snippets.

@marcom04
Last active April 20, 2024 18:14
Show Gist options
  • Save marcom04/22860f1168330605cac3c448982b0393 to your computer and use it in GitHub Desktop.
Save marcom04/22860f1168330605cac3c448982b0393 to your computer and use it in GitHub Desktop.
Basic echo between Python client and C server via socket using Python ctypes
Basic echo between Python3 client and C server, and vice versa, via socket using Python ctypes
/* client.c */
#include <sys/socket.h>
#include <arpa/inet.h> //inet_addr
#include <unistd.h> //write
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#pragma pack(1)
typedef struct payload_t {
uint32_t id;
uint32_t counter;
float temp;
} payload;
#pragma pack()
void sendMsg(int sock, void* msg, uint32_t msgsize)
{
if (write(sock, msg, msgsize) < 0)
{
printf("Can't send message.\n");
close(sock);
exit(1);
}
printf("Message sent (%d bytes).\n", msgsize);
return;
}
int main()
{
const int PORT = 2300;
const char* SERVERNAME = "localhost";
int BUFFSIZE = sizeof(payload);
char buff[BUFFSIZE];
int sock;
int nread;
float mintemp = -10.0;
float maxtemp = 30.0;
time_t t;
srand((unsigned) time(&t));
struct sockaddr_in server_address;
memset(&server_address, 0, sizeof(server_address));
server_address.sin_family = AF_INET;
inet_pton(AF_INET, SERVERNAME, &server_address.sin_addr);
server_address.sin_port = htons(PORT);
if ((sock = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
printf("ERROR: Socket creation failed\n");
return 1;
}
if (connect(sock, (struct sockaddr*)&server_address, sizeof(server_address)) < 0) {
printf("ERROR: Unable to connect to server\n");
return 1;
}
printf("Connected to %s\n", SERVERNAME);
payload data;
for(int i = 0; i < 5; i++) {
data.id = 1;
data.counter = i;
data.temp = mintemp + rand() / (RAND_MAX / (maxtemp - mintemp + 1.0) + 1.0);
printf("\nSending id=%d, counter=%d, temp=%f\n", data.id, data.counter, data.temp);
sendMsg(sock, &data, sizeof(payload));
bzero(buff, BUFFSIZE);
nread = read(sock, buff, BUFFSIZE);
printf("Received %d bytes\n", nread);
payload *p = (payload*) buff;
printf("Received id=%d, counter=%d, temp=%f\n",
p->id, p->counter, p->temp);
}
// close the socket
close(sock);
return 0;
}
#!/usr/bin/env python3
""" client.py - Echo client for sending/receiving C-like structs via socket
References:
- Ctypes: https://docs.python.org/3/library/ctypes.html
- Sockets: https://docs.python.org/3/library/socket.html
"""
import socket
import sys
import random
from ctypes import *
""" This class defines a C-like struct """
class Payload(Structure):
_fields_ = [("id", c_uint32),
("counter", c_uint32),
("temp", c_float)]
def main():
server_addr = ('localhost', 2300)
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
s.connect(server_addr)
print("Connected to {:s}".format(repr(server_addr)))
for i in range(5):
print("")
payload_out = Payload(1, i, random.uniform(-10, 30))
print("Sending id={:d}, counter={:d}, temp={:f}".format(payload_out.id,
payload_out.counter,
payload_out.temp))
nsent = s.send(payload_out)
# Alternative: s.sendall(...): coontinues to send data until either
# all data has been sent or an error occurs. No return value.
print("Sent {:d} bytes".format(nsent))
buff = s.recv(sizeof(Payload))
payload_in = Payload.from_buffer_copy(buff)
print("Received id={:d}, counter={:d}, temp={:f}".format(payload_in.id,
payload_in.counter,
payload_in.temp))
except AttributeError as ae:
print("Error creating the socket: {}".format(ae))
except socket.error as se:
print("Exception on socket: {}".format(se))
finally:
print("Closing socket")
s.close()
if __name__ == "__main__":
main()
/* server.c */
#include <sys/socket.h>
#include <arpa/inet.h> //inet_addr
#include <unistd.h> //write
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#pragma pack(1)
typedef struct payload_t {
uint32_t id;
uint32_t counter;
float temp;
} payload;
#pragma pack()
int createSocket(int port)
{
int sock, err;
struct sockaddr_in server;
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
printf("ERROR: Socket creation failed\n");
exit(1);
}
printf("Socket created\n");
bzero((char *) &server, sizeof(server));
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons(port);
if (bind(sock, (struct sockaddr *)&server , sizeof(server)) < 0)
{
printf("ERROR: Bind failed\n");
exit(1);
}
printf("Bind done\n");
listen(sock , 3);
return sock;
}
void closeSocket(int sock)
{
close(sock);
return;
}
void sendMsg(int sock, void* msg, uint32_t msgsize)
{
if (write(sock, msg, msgsize) < 0)
{
printf("Can't send message.\n");
closeSocket(sock);
exit(1);
}
printf("Message sent (%d bytes).\n", msgsize);
return;
}
int main()
{
int PORT = 2300;
int BUFFSIZE = 512;
char buff[BUFFSIZE];
int ssock, csock;
int nread;
struct sockaddr_in client;
int clilen = sizeof(client);
ssock = createSocket(PORT);
printf("Server listening on port %d\n", PORT);
while (1)
{
csock = accept(ssock, (struct sockaddr *)&client, &clilen);
if (csock < 0)
{
printf("Error: accept() failed\n");
continue;
}
printf("Accepted connection from %s\n", inet_ntoa(client.sin_addr));
bzero(buff, BUFFSIZE);
while ((nread=read(csock, buff, BUFFSIZE)) > 0)
{
printf("\nReceived %d bytes\n", nread);
payload *p = (payload*) buff;
printf("Received contents: id=%d, counter=%d, temp=%f\n",
p->id, p->counter, p->temp);
printf("Sending it back.. ");
sendMsg(csock, p, sizeof(payload));
}
printf("Closing connection to client\n");
printf("----------------------------\n");
closeSocket(csock);
}
closeSocket(ssock);
printf("bye");
return 0;
}
#!/usr/bin/env python3
""" server.py - Echo server for sending/receiving C-like structs via socket
References:
- Ctypes: https://docs.python.org/3/library/ctypes.html
- Sockets: https://docs.python.org/3/library/socket.html
"""
import socket
import sys
import random
from ctypes import *
""" This class defines a C-like struct """
class Payload(Structure):
_fields_ = [("id", c_uint32),
("counter", c_uint32),
("temp", c_float)]
def main():
PORT = 2300
server_addr = ('localhost', PORT)
ssock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print("Socket created")
try:
# bind the server socket and listen
ssock.bind(server_addr)
print("Bind done")
ssock.listen(3)
print("Server listening on port {:d}".format(PORT))
while True:
csock, client_address = ssock.accept()
print("Accepted connection from {:s}".format(client_address[0]))
buff = csock.recv(512)
while buff:
print("\nReceived {:d} bytes".format(len(buff)))
payload_in = Payload.from_buffer_copy(buff)
print("Received contents id={:d}, counter={:d}, temp={:f}".format(payload_in.id,
payload_in.counter,
payload_in.temp))
print("Sending it back.. ", end='')
nsent = csock.send(payload_in)
print("Sent {:d} bytes".format(nsent))
buff = csock.recv(512)
print("Closing connection to client")
print("----------------------------")
csock.close()
except AttributeError as ae:
print("Error creating the socket: {}".format(ae))
except socket.error as se:
print("Exception on socket: {}".format(se))
except KeyboardInterrupt:
ssock.close()
finally:
print("Closing socket")
ssock.close()
if __name__ == "__main__":
main()
@xicocana
Copy link

@Mario-RC thanks for the fast reply! Yesterday I ended up doing the same. I'll still star your rep it looks useful for the future! thanks again

@Mario-RC
Copy link

@xicocana It is a pleasure, thank you very much!

@pra-dan
Copy link

pra-dan commented Feb 5, 2021

Hey, thanks for the gist. Can you guide me on the vice-versa process? C client to Python server?

@marcom04
Copy link
Author

marcom04 commented Feb 7, 2021

Hi @pra-dan, the payload handling is quite similar, just need to switch roles. I added the files to show an example of C client and Python server.

@waelmas
Copy link

waelmas commented Sep 29, 2021

Any ideas on how to modify the above to communicate with FastAPI Websockets either directly from the C client or from the Python server?

Something like this:
C client code ----> Python server.py <----> FastAPI
OR
C client code ----> FastAPI

@marcom04 @Mario-RC

@guzminho
Copy link

guzminho commented Apr 7, 2022

Awesome code! Thanks mate!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment