Skip to content

Instantly share code, notes, and snippets.

@marcom04
Last active May 14, 2026 19:50
Show Gist options
  • Select an option

  • Save marcom04/22860f1168330605cac3c448982b0393 to your computer and use it in GitHub Desktop.

Select an option

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()
@marcom04

marcom04 commented Feb 7, 2021

Copy link
Copy Markdown
Author

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

waelmas commented Sep 29, 2021

Copy link
Copy Markdown

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

guzminho commented Apr 7, 2022

Copy link
Copy Markdown

Awesome code! Thanks mate!

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