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
Related
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.
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.
I am trying to create a socket program that communicate with client android device to simulate clicks on it, so far I managed to set up and run the TCP server code successfully on Python using the code below.
import socket
import time
HOST = '192.168.1.243'
PORT = 4000
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.bind((HOST, PORT))
s.listen()
conn, addr = s.accept()
while True:
time.sleep(1)
conn.sendall(b'a 925 1725\n') //Click 1
time.sleep(1)
conn.sendall(b'a 220 2100\n') //Click 2
After some research, I am able to produce the C code for TCP server to bind host and port, listen for clients and accept clients.
#include<stdio.h>
#include<time.h>
#include<unistd.h>
#include<sys/socket.h>
#include<stdlib.h>
#include<netinet/in.h>
#include<string.h>
#include<arpa/inet.h>
#define PORT 4000
int main(int argc, char const*argv[])
{
int createsocket, phone_socket;
struct sockaddr_in server;//Declare structure to connect to a remote server
int opt = 1;
int addrlen = sizeof(server);
char buffer[1024] = {0};
ssize_t sendto(int createsocket, const void *buf, size_t len, int flags, const struct
sockaddr *dest_addr, socklen_t addrlen);
createsocket = socket(AF_INET, SOCK_STREAM, 0); //To create socket
if (createsocket == -1){
printf("Error creating socket");
}
//Assign structure
server.sin_family = AF_INET;
server.sin_addr.s_addr = inet_addr("10.10.10.10"); //Assign host
server.sin_port = htons( PORT ); //Assign port
//Bind host and phone
if (bind(createsocket, (struct sockaddr *)&server, sizeof(server))<0){
printf("Bind error\n");
return 1;
}
else
printf("Bind Connected\n");
//Ready to receive connections
if (listen(createsocket, 5) < 0){
printf("Listening error\n");
return 1;
}
else
printf("Listening\n");
//Connection received, pending accept
if((phone_socket = accept(createsocket, (struct sockaddr *)&server,(socklen_t*)&addrlen)< 0){
printf("Failed to accept\n");
return 1;
}
else
printf("Accepted device\n");
while(1){
sleep(1); //One second delay
printf("click\n"); //Supposed click command
}
}
Anybody knows how to convert the python line conn.sendall(b'a 925 1725\n') for clicking into C?
Thank you for your help!
Are you trying to change into C from Python or something else? I might be able to help with a bit more explanation of what your goal is other than clicking into C.
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).
I am beginner in python written first program two days ago. I am having connection problem in python client and C server for AF_UNIX. I have C socket Server with AF_LOCAL.
#define NAME "#/tmp/kvsd"
int
main()
{
int sock, msgsock, rval;
struct sockaddr_un server;
char buf[1024];
unlink(NAME);
printf("before socket \n");
sock = socket(AF_LOCAL, SOCK_STREAM, 0);
if (sock < 0) {
perror("opening stream socket");
exit(1);
}
memset(&server, 0, (sizeof (server)));
server.sun_family = AF_LOCAL;
memcpy(server.sun_path, NAME, strlen(NAME));
server.sun_path[0] = 0;
printf("before bind \n");
int len = strlen(server.sun_path) + sizeof(server.sun_family);
if (bind(sock, (struct sockaddr *) &server, len)) {
perror("binding stream socket");
exit(1);
}
printf("before listen \n");
if (listen(sock, 5) == -1) {
perror("listen");
exit(1);
}
printf("before accept \n");
msgsock = accept(sock, 0, 0);
printf("accepted \n");
if (msgsock == -1)
perror("accept");
else do {
bzero(buf, sizeof(buf));
printf("before read \n");
if ((rval = read(msgsock, buf, 1024)) < 0)
perror("reading stream message");
else if (rval == 0)
printf("Ending connection\n");
else
printf("-->%s\n", buf);
} while (rval > 0);
close(msgsock);
close(sock);
unlink(NAME);
}
And Python AF_UNIX client.py:-
####### CLIENT CODE #######
from socket import *
# Create an unbond and not-connected socket.
sock = socket(AF_UNIX, SOCK_STREAM)
# Connect to the peer registered as "MyBindName" in the abstract namespace. Note the '\0'.
str = "\0/tmp/kvsd\0"
print "len ", len (str)
sock.connect("\0/tmp/kvsd")
# Wait for message
msg = sock.recv(100)
print msg
# Send reply
sock.send("Hi there!\n")
# Block until new message arrives
msg = sock.recv(100)
# When the socket is closed cleanly, recv unblocks and returns ""
if not msg:
print "It seems the other side has closed its connection"
# Close it
sock.close()
But When I run the client I'm getting following error:
[root#mat afunix]# python ./client.py len 11 Traceback (most recent call last): File "./client.py", line 13, in sock.connect("\0/tmp/kvsd") File "", line 1, in connect socket.error: [Errno 111] Connection refused [root#mat afunix]#
I am trying to use the abstract namespaces for UNIX socket but my python client is not able to connect to c server.
I tried without abstract namespaces it works. (changed NAME macro in server.c to "/tmp/kvsd" and argument to sock.connect to "/tmp/kvsd").
Can someone help me to figure out what may be the exact issue ?
Thanks in advance.
Following line has a problem.
int len = strlen(server.sun_path) + sizeof(server.sun_family);
server.sun_path has now leading null character. So strlen(server.sun_path) is 0. You need change above line as follow:
#include <stddef.h>
....
int len = offsetof(struct sockaddr_un, sun_path) + strlen(NAME);
Then, it will work.
EDIT: updated the code to use offsetof to avoid padding issue. (Thank you, alk)
PS: I assume that both server, client use name without trailing null byte. If you use name with trailing null byte, add 1 to len.