How to convert a string in cpp struct to python struct - python

I wrote a tcp server and tcp client, and I want to send a structure from client to server, and then the server send the structure back. Server is written in cpp, and client is written in python.
Then I met a problem, that my structure has a member which type is string, then I cannot find a proper format string to describe this member in python(https://docs.python.org/2/library/struct.html).
So I want to know how can I describe the string attribute in python?
below is the minimal code:
------server---------
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <cstring>
#include <iostream>
struct Message
{
int id;
std::string text;
};
int main()
{
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in my_addr;
bzero(&my_addr, sizeof(my_addr));
my_addr.sin_family = AF_INET;
my_addr.sin_port = htons(11111);
my_addr.sin_addr.s_addr = htonl(INADDR_ANY);
unsigned retry_times = 0;
while(retry_times < 3)
{
if(bind(sockfd, (struct sockaddr*)&my_addr, sizeof(my_addr)) == 0)
{
break;
}
sleep(1000);
++retry_times;
}
listen(sockfd, 1);
struct sockaddr_in client_addr;
socklen_t addr_len = sizeof(client_addr);
int connfd = accept(sockfd, (struct sockaddr*)&client_addr, &addr_len);
while(true)
{
Message msg;
unsigned int len = recv(connfd, &msg, sizeof(msg), 0);
if(len == 0)
{
break;
}
std::cout << msg.id << "--" << msg.text << std::endl;
send(connfd, &msg, sizeof(msg), 0);
}
close(connfd);
close(sockfd);
}
-----------client-----------
import socket
import struct
class TCPClient:
def __init__(self):
self.server_address = ('127.0.0.1', 11111)
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.sock.connect_ex(self.server_address)
def send(self, msg):
self.sock.send(msg)
def recv(self):
return self.sock.recv(512)
def close(self):
self.sock.close()
if __name__ == '__main__':
client = TCPClient()
fmt = 'is' #### what format string will be better? this fmt is useless
msg = bytearray(512)
struct.pack_into(fmt, msg, 0, 1, "Hello")
client.send(msg)
data = client.recv()
print struct.unpack_from(fmt, data)
client.close()

There is no Python format string which will fix this problem. The root cause is that you are sending the bytes of a std::string on the network. But a std::string often contains a pointer (and size) to the actual content, which means you are not sending the actual content at all!
To fix it, you have two main choices--either modify your struct:
struct Message
{
int32_t id; // use a fixed-size integer type
char text [50]; // assumes you know the max length
};
Or more conventionally, write a serialization routine:
void send_msg(int fd, const Message& msg)
{
// XXX: you must check the return value of send()
send(fd, &msg.id, sizeof(msg.id), 0);
uint32_t text_size = msg.text.size();
send(fd, &text_size, sizeof(text_size), 0);
send(fd, &msg.text.data(), msg.text.size(), 0);
}
Now we are sending the ID (4 bytes, Python format i), the text_size (4 bytes, unsigned, Python format I), then the text (text_size bytes, Python format '{}s'.format(text_size)). You can unpack it in two steps on the receiving end: first unpack iI to get the ID and text_size, then unpack '{}s'.format(text_size) to get the text.
Note that since you are using TCP, partial writes and reads are possible. So you need to deal with the fact that your sender might send only half a message, and your receiver might receive only half a message. Your current logic does not handle this (but will likely appear to work most of the time if text_size is less than 500).

Related

Sending const char* through UDP server

I am trying to implement a basic UDP socket in my code to send a string. Created an UDP server in C++ to send sort of a "hello world" and a client in Python to receive it. For this, I'm using G4G's example as base, only slightly modified:
#define PORT xxxx
void initializeUDP(int stop) {
int sockfd;
const char *hello = "Hello from server.\n";
struct sockaddr_in servaddr, cliaddr;
//Initialize Winsock
WSADATA data;
WORD version = MAKEWORD(2, 2);
int wsOk = WSAStartup(version, &data);
if (wsOk != 0) {
cout << "Cannot start Winsock! " << wsOk;
return;
}
// Creating socket and binding with address
if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
perror("socket creation failed");
exit(EXIT_FAILURE);
}
memset(&servaddr, 0, sizeof(servaddr));
memset(&cliaddr, 0, sizeof(cliaddr));
servaddr.sin_family = AF_INET; // IPv4
servaddr.sin_addr.s_addr = INADDR_ANY;
servaddr.sin_port = htons(PORT);
if (::bind(sockfd, (const struct sockaddr *)&servaddr, sizeof(servaddr)) < 0)
{
perror("bind failed");
exit(EXIT_FAILURE);
}
int len;
len = sizeof(cliaddr); //len is value/result
while (globalVariableNameInPortuguese == 0) {
sendto(sockfd, (const char *)hello, 1024, 0, (const struct sockaddr *) &cliaddr, len);
}
closesocket(sockfd);
WSACleanup();
}
Also created these few lines to try to receive this string as a client in Python:
import socket
bufferSize = 1024
ip = "localhost"
port = xxxx
UDPClientSocket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
UDPClientSocket.connect((ip, port))
while True:
message, address = UDPClientSocket.recvfrom(bufferSize)
print(message)
UDPClientSocket.close()
The C++ code executes normally but I am uncertain whether it's actually doing what it should. However, if I set the IP in the Python code as "localhost" it gets stuck in recvfrom, and if I set the IP to 0.0.0.0 it gets WinError 10049. Not sure on what I'm doing wrong and how I should proceed to actually get this string.

Using sockets to send a string from a C++ client on one computer to a Python server on another. Getting `send: Bad file descriptor`

I'm trying to send a string from a C++ client on one computer to a Python server on another computer.
My error is send: Bad file descriptor
The Python server is killed if it is contacted by the client but it doesn't receive a string. While the Python server is running it does end the program when I attempt to send the string from the C++ client. So I know the server is being reached by the client when I execute it.
I am able to send strings to the server from the C++ client's computer with a Python client script. Since it's not a basic problem with the server I don't think this and other answers apply to my problem.
On the Python script I have tried changing this number.
s.listen(11)
Here is the Python server
import os
import sys
import socket
s=socket.socket()
host='192.168.0.101'
port=12003
s.bind((host,port))
s.listen(11)
while True:
c, addr=s.accept()
content=c.recv(1024).decode('utf-8')
print(content)
if not content:
break
Here is the C++ client
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netdb.h>
#include <unistd.h>
#define ADDR "192.168.0.101"
#define PORT "12003"
void sendall(int socket, char *bytes, int length)
{
int n = 0, total = 0;
while (total < length) {
n = send(socket, bytes + total, total-length, 0);
if (n == -1) {
perror("send");
exit(1);
}
total += n;
}
}
int main()
{
struct addrinfo hints = {0}, *addr = NULL;
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
int status = getaddrinfo(ADDR, PORT, &hints, &addr);
if (status != 0) {
fprintf(stderr, "getaddrinfo()\n");
exit(1);
}
int sock = -1;
{
struct addrinfo *p = NULL;
for (p = addr; p != NULL; p = addr->ai_next) {
int sock = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
if (sock == -1) {
continue;
}
if (connect(sock, p->ai_addr, p->ai_addrlen) != -1) {
break;
}
close(sock);
}
if (p == NULL) {
fprintf(stderr, "connect(), socket()\n");
exit(1);
}
freeaddrinfo(addr);
/* Do whatever. */
sendall(sock, "Hello, World", 12);
/* Do whatever. */
}
close(sock);
return 0;
}
UPDATE:
In the client there was an unessacary int in front of sock = socket...
I removed it and now I'm getting an error on the server side when I send the string that reads..
$ python server.py
Traceback (most recent call last):
File "/home/computer/server.py", line 35, in <module>
content=c.recv(1024).decode('utf-8')
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xfc in position 29: invalid start byte
You're redeclaring the sock variable in the for loop, so the value of sock when you call sendall() is the original -1. Change
int sock = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
to
sock = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
so it assigns the outer variable.

C socket server and Python socket client "Resource temporarily unavailable"

I am creating a C server and Python client for UNIX domain datagram sockets (UDS) IPC on Ubuntu 18.04. My scenario is: Python runs as a child process created with fork-execv where C is the parent process. The Python client blocks on socket.recvfrom until data is sent by the C server. When the C server sends data to the Python client then C will block on recvfrom until Python sends data to C with sendto.
I have used UDS for a C client and a C server with no problems, but the C-Python setup is causing some problems. For this Python version I worked from an example at https://lloydrochester.com/post/c/unix-domain-socket-datagram.
I create a server socket in C and bind to it; it returns file descriptor 5:
int64_t * create_socket_server(struct sockaddr_un svaddr, int64_t retvals[])
{
int sfd, j;
ssize_t numBytes;
socklen_t len;
char buf[BUF_SIZE];
retvals[0] = 0;
retvals[1] = 0;
sfd = socket(AF_UNIX, SOCK_DGRAM, 0); /* Create server socket
if (sfd == -1)
return retvals;
if (remove(SV_SOCK_PATH) == -1 && errno != ENOENT)
return retvals;
memset(&svaddr, 0, sizeof(struct sockaddr_un));
svaddr.sun_family = AF_UNIX;
strncpy(svaddr.sun_path, SV_SOCK_PATH, sizeof(svaddr.sun_path) - 1);
if (bind(sfd, (struct sockaddr *) &svaddr, sizeof(struct sockaddr_un)) == -1)
return retvals;
retvals[0] = sfd;
retvals[1] = (int64_t)&svaddr;
return retvals;
}
I do not create or explicitly connect to the client socket on the C side.
On the Python side I bind to the client socket. Here is my Python code, following the example cited, but altered somewhat to fit my use case:
#!/usr/bin/python3
import socket
import os, os.path
csock_file = "/tmp/py_sock"
ssock_file = "/tmp/ud_ucase"
if os.path.exists(csock_file):
os.remove(csock_file)
csock = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)
csock.bind(csock_file) # Bind to the server socket
return_msg = "Got it"
while True:
(bytes, address) = csock.recvfrom(720)
msg = bytes.decode('utf-8')
print("Python received")
if msg != "Code_99":
print('address:',address,'received:',msg)
csock.sendto(str.encode(return_msg), ssock_file)
if msg == "Code_99":
print("closing")
#Close the socket
I want recvfrom to be blocking in both Python and C because Python should block until C sends, but when I leave it at blocking (the default) then Python blocks both processes when it calls (bytes, address) = csock.recvfrom(720), and C cannot continue.
If I set it to nonblocking with csock.setblocking(False) I get this error message:
(bytes, address) = csock.recvfrom(720)
BlockingIOError: [Errno 11] Resource temporarily unavailable
So my question is why does Python block both processes, and why do I get that error message in nonblocking mode?
Thanks for any help.
Explanation
why does Python block both processes ?
When your client is waiting for your server's response with recvfrom, you server just did nothing, thus server blocks at its recvfrom as well.
why do I get that error message in nonblocking mode ?
Your server/client might not be as robust as the one you quoted (i.e. from lloydrochester.com). Serveral parts broke and result in breaking the whole thing. Some of them are just about C Lang, such as Variable Declarations, Function Returning, etc. Others are about network programming, such as Buffer Sizing, Socket Internals, etc. It's not realistic to list them all and analyse one by one. Better read through K&R and BSD socket to fix them thoroughly.
However, here is an relatively simple implementation for you case, based on your codes, shown below. In addition, you might want to change the reply message to Code_99 in the 48th line of server_alice.c.
Environment
Ubuntu 18.04
gcc 7.5.0
Python 3.6.9
server_alice.c
#include <sys/un.h>
#include <sys/socket.h>
#include <ctype.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#define BUF_SIZE 720
#define SV_SOCK_PATH "ssock"
int create_socket_server(int *sfd_ptr, struct sockaddr_un *svaddr_ptr);
int main(int argc, char *argv[]) {
struct sockaddr_un svaddr, claddr;
int sfd, j;
ssize_t numBytes;
socklen_t len;
char buf[BUF_SIZE];
int64_t retvals[2];
if (create_socket_server(&sfd, &svaddr) == 0)
printf("create_socket_server...DONE\n");
else exit(0);
for (;;) {
len = sizeof(struct sockaddr);
printf("waiting clients...\n");
numBytes = recvfrom(sfd, buf, BUF_SIZE, 0, (struct sockaddr *) &claddr, &len);
if (numBytes == -1) {
fprintf(stderr, "error recvfrom");
return 4;
}
claddr.sun_path[len - sizeof(sa_family_t) - 1] = 0;
buf[numBytes] = '\0';
fprintf(stdout, "server received %ld bytes from %s, they are: \x1b[32m%s\x1b[0m\n", (long) numBytes,
claddr.sun_path, buf);
for (j = 0; j < numBytes; j++) {
buf[j] = toupper((unsigned char) buf[j]);
}
// char *reply_msg="Code_99"; # different reply message
char *reply_msg = "Hello Bob~ This is a message: blablablabla";
j = sendto(sfd, reply_msg, strlen(reply_msg), 0, (struct sockaddr *) &claddr, len);
if (j != strlen(reply_msg)) {
fprintf(stderr, "error sendto %s", strerror(errno));
}
}
exit(EXIT_SUCCESS);
}
/* Your create_socket_server, with a few changes */
int create_socket_server(int *sfd_ptr, struct sockaddr_un *svaddr_ptr) {
struct sockaddr_un svaddr;
int sfd = socket(AF_UNIX, SOCK_DGRAM, 0); // Create server socket
if (sfd == -1)
return -1;
if (remove(SV_SOCK_PATH) == -1 && errno != ENOENT)
return -1;
memset(&svaddr, 0, sizeof(struct sockaddr_un));
svaddr.sun_family = AF_UNIX;
strncpy(svaddr.sun_path, SV_SOCK_PATH, sizeof(svaddr.sun_path) - 1);
if (bind(sfd, (struct sockaddr *) &svaddr, sizeof(struct sockaddr_un)) == -1)
return -1;
memcpy(sfd_ptr, &sfd, sizeof(int));
memcpy(svaddr_ptr, &svaddr, sizeof(struct sockaddr_un));
return 0;
}
client_bob.py
#!/usr/bin/python3
import socket
import os, os.path
csock_file = "./csock"
ssock_file = "./ssock"
if os.path.exists(csock_file):
os.remove(csock_file)
csock = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)
csock.bind(csock_file) # Bind to the server socket
return_msg = "Got it"
csock.sendto(str.encode("Hello Alice! I'm coming!"), ssock_file)
# while True: # ! CATION ! If 'while(true)', there will be infinite message sending back and forth!
(bytes, address) = csock.recvfrom(720)
msg = bytes.decode('utf-8')
if msg != "Code_99":
print('address: ', address, 'received: ', msg)
csock.sendto(str.encode(return_msg), ssock_file)
if msg == "Code_99":
print("closing")
csock.close()
Server Output:
$ gcc server_alice.c && ./a.out
create_socket_server...DONE
waiting clients...
server received 24 bytes from ./csock, they are: Hello Alice! I'm coming!
waiting clients...
server received 6 bytes from ./csock, they are: Got it
waiting clients...
Client Output:
$ python3 client_bob.py
address: ssock received: Hello Bob~ This is a message: blablablabla

strtok() change my buffer, I need stored some data that change in an arbitrary time, how can I do this?

I have a list with coordinates sent from a Python server to a C++ client like a buffer, then I need to split each coordinate, I used strtok() for this, but when the function is tokenized for the first time do it correctly, when my while cycle repeat and received a new list of coordinates, the function returns the first token split previously, I need to saved the new coordinate list and split it in tokens like the first time, anyone knows what's my problem or a better way to solve that without use strtok()?
This is my C++ client code
#define _CTR_SECURE_NO_WARNINGS
#include <stdio.h>
#include <Winsock2.h>
#pragma comment(lib,"ws2_32.lib")
#pragma warning(disable:4996)
#include <iostream>
#include <sstream>
#include <conio.h>
#include <stdlib.h>
#include <string.h>
#include <typeinfo>
using namespace std;
int main()
{
char delimitador[] = ",";
WORD wVersionRequested;
WSADATA wsaData;
int err, N;
char* length;
string D, Coordenada;
wVersionRequested = MAKEWORD(1, 1);
err = WSAStartup(wVersionRequested, &wsaData);
if (err != 0) {
return -1;
}
if (LOBYTE(wsaData.wVersion) != 1 ||
HIBYTE(wsaData.wVersion) != 1) {
WSACleanup();
return -1;
}
SOCKET sockClient = socket(AF_INET, SOCK_STREAM, 0);
SOCKADDR_IN addrSrv;
addrSrv.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
addrSrv.sin_family = AF_INET;
addrSrv.sin_port = htons(2070);
connect(sockClient, (SOCKADDR*)&addrSrv, sizeof(SOCKADDR));
const char* baseCh = { "hello" };
char recvBuf[50], expected[50];
send(sockClient, baseCh, strlen(baseCh), 0);
while (1 == 1)
{
recv(sockClient, recvBuf, strlen(recvBuf), 0);
strcpy(expected, recvBuf);
char *token = strtok(expected, delimitador);
if (token != NULL); {
while (token != NULL) {
printf("Token %s\n", token);
token = strtok(NULL, delimitador);
}
}
send(sockClient, baseCh, strlen(baseCh), 0);
}
closesocket(sockClient);
WSACleanup();
getchar();
return 0;
}
And this is my Python Server code
import socket
import time
def main():
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind(("localhost", 2070))
server.listen(0)
connection, address = server.accept()
Hand = []
while True:
recv_str=connection.recv(1024)[0:5]
print("enter 1")
recv_str=recv_str.decode("ascii")
if not recv_str:
break
print( recv_str)
while True:
time.sleep(0.5)
Hand.append(1)
Hand.append(20)
Hand.append(25)
connection.send( bytes("%s," %Hand, encoding="ascii"))
recv_str=connection.recv(1024)[0:5]
print(Hand)
print(recv_str)
Hand = []
connection.close()
input("enter end")
if __name__ == '__main__':
main()
enter image description here
I already put the correct code that I use and the main problem is that I need to receive a Message from a Python Server continuously at an undefined time, this message is a group of coordinates, and how you can see the function strtok() change my Buffer, I need only split the data without change the original buffer variable, like my first tokenize result but everytime that my buffer change.
My problem isn't my strtok() function, after reading an ancient question post by me, I can realize that my problem was in the recv() function my correction was
recv(sockClient, recvBuf, strlen(recvBuf), 0);
for
recv(sockClient, recvBuf, sizeof(recvBuf), 0);
This solved my problem and finally, I could receive a continuous data from Python Server to C++ client.

Can't connect a Unix domain socket using Python: No such file or directory

I have several pieces of codes to establish a Unix domain socket and a service using this socket. While there are some confusing errors here leading to a failure.
the code that creats the Unix domain socket is written in c:
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/un.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <errno.h>
int main(int ac, char *av[])
{
if (ac != 4) {
printf("Usage: %s dummy-fd sockpath binary\n", av[0]);
exit(-1);
}
char *sockpn = av[2];
char *bin = av[3];
int srvfd = socket(AF_UNIX, SOCK_STREAM, 0);
if (srvfd < 0) {
perror("socket");
exit(-1);
}
fcntl(srvfd, F_SETFD, FD_CLOEXEC);
struct stat st;
if (stat(sockpn, &st) >= 0) {
if (!S_ISSOCK(st.st_mode)) {
fprintf(stderr, "socket pathname %s exists and is not a socket\n",
sockpn);
exit(-1);
}
unlink(sockpn);
}
struct sockaddr_un addr;
addr.sun_family = AF_UNIX;
snprintf(&addr.sun_path[0], sizeof(addr.sun_path), "%s", sockpn);
if (bind(srvfd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
fprintf(stderr, "WARNING: cannot bind to socket %s (%s), exiting\n",
sockpn, strerror(errno));
exit(-1);
}
// allow anyone to connect; for access control, use directory permissions
chmod(sockpn, 0777);
listen(srvfd, 5);
signal(SIGCHLD, SIG_IGN);
signal(SIGPIPE, SIG_IGN);
for (;;) {
struct sockaddr_un client_addr;
unsigned int addrlen = sizeof(client_addr);
int cfd = accept(srvfd, (struct sockaddr *) &client_addr, &addrlen);
if (cfd < 0) {
perror("accept");
continue;
}
int pid = fork();
if (pid < 0) {
perror("fork");
close(cfd);
continue;
}
if (pid == 0) {
// Child process
dup2(cfd, 0);
dup2(cfd, 1);
close(cfd);
execl(bin, bin, 0);
perror("execl");
exit(-1);
}
close(cfd);
}
}
the client Python to using this sock is as follow(unixclient.py):
def call(pn, req):
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
sock.connect(pn)
sock.send(req)
sock.shutdown(socket.SHUT_DOWN)
data = ""
while True:
buf = sock.recv(1024)
if not buf:
break
data += buf
sock.close()
return data
And I trigger this piece of client code in another Python code, by importing this file and call the call funciton:(Both "/jail/zoobar/echosvc" and "/jail/zoobar/echosvc/sock" will fail)
resp = call("/jail/zoobar/echosvc", str1)
There the error occurs, showing that:
FIle "zoobar/unixclient.py", line 8, in call
sock.connect(pn)
File "<string>", line 1, in connect
error: [ERROR 2] No such file or directory
Yet I swear the directory and the socket does exist(/jail/zoobar/echosvc/sock), and the permission is correct, too(777), so I can't understand this weird error. Does anyone know about it?
I would appreciate very much for sparing time to help.
Looks like you're trying to open the wrong filename. The code looks like:
resp = call("/jail/zoobar/echosvc", str1)
But you say "the file exists":
/jail/zoobar/echosvc/sock
Try changing your call line to:
resp = call("/jail/zoobar/echosvc/sock", str1)

Categories

Resources