Last active
April 20, 2024 18:14
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Basic echo between Python3 client and C server, and vice versa, via socket using Python ctypes |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* 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; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* 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; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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() |
Awesome code! Thanks mate!
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.