-
-
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() |
Hello, I'm trying to sent a str from client to server using the ctype structure but I couldn't, could you help me?
@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!
Yes sure, you can include the uint32 array inside a Payload structure, along with other data. Not sure how to handle dynamic size array in that case, though