-
-
Save marcom04/22860f1168330605cac3c448982b0393 to your computer and use it in GitHub Desktop.
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() |
@Mario-RC Hello, I am trying the same but to no result. Have you been able to do it?
@Mario-RC Hello, I am trying the same but to no result. Have you been able to do it?
@xicocana Hi! I finally decided not to use ctype structure, instead I encoded the message and sent it at a byte level.
You can check my code here: https://github.com/Mario-RC/UDP-sockets
@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
@xicocana It is a pleasure, thank you very much!
Hey, thanks for the gist. Can you guide me on the vice-versa process? C client to Python server?
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.
Awesome code! Thanks mate!
Hello, I'm trying to sent a str from client to server using the ctype structure but I couldn't, could you help me?