aio_write on Large Files - c

I'm trying to essentially mimic the functionality of sendfile(2) in an asynchronous fashion using aio_read(3) and aio_write(3).
Everything seems to be working fine, with the exception of testing large (> 150k) files.
I have a simple struct io_request I am using to keep track of the transfers:
struct io_request {
int status;
struct aiocb *aiocbp;
int sfd;
};
First, I build the aio_read() call:
struct io_request * ioreq = malloc(sizeof(struct io_request));
ioreq->status = EINPROGRESS;
ioreq->sfd = sfd;
struct aiocb * aiocbreq = malloc(sizeof(struct aiocb));
memset(aiocbreq, 0, sizeof(struct aiocb));
ioreq->aiocbp = aiocbreq;
ioreq->aiocbp->aio_fildes = ffd;
if (ioreq->aiocbp->aio_fildes == -1) {
perror("aio_fildes");
}
ioreq->aiocbp->aio_buf = malloc(st.st_size);
if (ioreq->aiocbp->aio_buf == NULL) {
perror("aio_buf malloc");
}
ioreq->aiocbp->aio_nbytes = st.st_size;
ioreq->aiocbp->aio_reqprio = 0;
ioreq->aiocbp->aio_offset = 0;
ioreq->aiocbp->aio_sigevent.sigev_signo = IO_READ_SIGNAL;
ioreq->aiocbp->aio_sigevent.sigev_value.sival_ptr = ioreq;
if (aio_read(ioreq->aiocbp) == -1) {
perror("aio_read");
}
Which then later is captured in a IO_READ_SIGNAL handler:
static void
aio_read_handler(int sig, siginfo_t *si, void *ucontext)
{
if (si->si_code == SI_ASYNCIO) {
struct io_request *ioreq = si->si_value.sival_ptr;
// Build the AIO write request
struct aiocb aiocbreq;
memset(&aiocbreq, 0, sizeof(struct aiocb));
aiocbreq.aio_fildes = ioreq->sfd;
aiocbreq.aio_buf = ioreq->aiocbp->aio_buf;
aiocbreq.aio_nbytes = ioreq->aiocbp->aio_nbytes;
aiocbreq.aio_sigevent.sigev_signo = IO_WRITE_SIGNAL;
aiocbreq.aio_sigevent.sigev_value.sival_ptr = ioreq;
if (aio_write((void *) &aiocbreq) == -1) {
perror("aio_write");
}
}
}
I can confirm that inside the handler, even for large files, the contents of ioreq->aiocbp->aio_buf is full and complete.
Later, the aio_write() is captured in a IO_WRITE_SIGNAL handler:
static void
aio_write_handler(int sig, siginfo_t *si, void *ucontext)
{
if (si->si_code == SI_ASYNCIO) {
struct io_request *ioreq = si->si_value.sival_ptr;
ssize_t bytes_written = aio_return(ioreq->aiocbp);
printf("Wrote %zu of %zu bytes\n", bytes_written, ioreq->aiocbp->aio_nbytes);
//free(ioreq->aiocbp);
//free(ioreq);
if (aio_error(ioreq->aiocbp) != 0) {
perror("aio_write_handler");
}
}
}
At this point aio_write() should have been completed. I check the return values and act accordingly. Both calls report the appropriate number of bytes have been written and no errors arose during the write.
The greater application is an HTTP server. I speculate that this problem arrises because the remote client cannot read fast enough to keep up with the aio_write(). When I had a sendfile() implementation of this, I had to call sendfile() multiple times to complete the file transfer.
Several direct questions:
Why does aio_return() and aio_error() not report any problems?
How can I fix this behavior?
Are there ways to buffer aio_write()? I was thinking of capping of n_bytes inside struct aiocb passed to aio_write(), and just calling aio_write() multiple times from inside aio_write_handler().
Thanks for your help!

If I understand correctly, you're using aio_return before aio_error. The aio_return man page says,
This function should be called only once for any given request, after
aio_error(3) returns something other than EINPROGRESS.

Related

Function outputting sound through alsa not working when called via pthread create: no sound, 100% CPU usage

I have a program that receives messages via a socket and starts or stops playing a certain sound file depending on the message. In order for the "stop" message to work, I need the sound to play from a separate thread. My solution is to play the sound using alsa from a function I invoke using pthread_create(), and upon receiving a stop message I end the thread using pthread_cancel(). The function that plays the sound is called play_sound(void *args);
Here's what works:
struct args *args;
args->fp = fopen("path/to/soundfile.wav", "r");
args->volume = 1;
play_sound((void *) args);
but as soon as I try to run the function from within a new thread, I get no sound and 100% CPU usage on both my threads:
struct args *args;
int sound_thread;
args->fp = fopen("path/to/soundfile.wav", "r");
args->volume = 1;
pthread_create(&sound_thread, NULL, (void *) play_sound, (void *) args);
I have no idea where to even begin troubleshooting.
My code looks as follows:
#include <alsa/asoundlib.h>
#include <alsa/mixer.h>
#include <stdbool.h>
#include <pthread.h>
#include "server.h"
#include "sound.h"
//#include "log.h"
int sound_thread;
struct args {
FILE *fp;
float volume;
};
void init_sound ()
{
sound_thread = -1;
}
void stop_sound ()
{
if (sound_thread != -1) {
pthread_cancel(sound_thread);
keep_playing = false;
sound_thread = -1;
}
}
void dispatch_sound (FILE *fp, float volume)
{
// this function serves to create a new thread for the
// sound to be played from. This is what's giving me
// headaches.
if (sound_thread != -1) {
stop_sound();
}
struct args *args = (struct args *) malloc(sizeof(struct args));
args->fp = fp;
args->volume = volume;
if (pthread_create(&sound_thread, NULL, (void *) play_sound, args) != 0)
sound_thread = -1;
}
}
bool play_sound (void *args)
{
// This function actually plays the sound using functions
// from the alsa lib. it works when invoked regularly without
// threading.
keep_playing = true;
FILE *fp;
int volume;
bool success;
unsigned int samplerate;
int bufsz;
char *buf;
snd_pcm_t *pcm;
snd_pcm_hw_params_t *params;
snd_pcm_uframes_t frames;
samplerate = SAMPLERATE;
fp = ((struct args *) args)->fp;
volume = ((struct args *) args)->volume;
// volume is not actually used right now, since I took out
// the function that sets the volume before playing the
// audio in order to make it easier to pinpoint the issue.
if (snd_pcm_open(&pcm, PCM_DEVICE, SND_PCM_STREAM_PLAYBACK, 0) < 0) {
success = false;
}
snd_pcm_hw_params_alloca(&params);
snd_pcm_hw_params_any(pcm, params);
if (snd_pcm_hw_params_set_access(pcm, params, SND_PCM_ACCESS_RW_INTERLEAVED) < 0) {
success = false;
}
if (snd_pcm_hw_params_set_format(pcm, params, SND_PCM_FORMAT_S16_LE) < 0) {
success = false;
}
if (snd_pcm_hw_params_set_channels(pcm, params, CHANNELS) < 0) {
success = false;
}
if (snd_pcm_hw_params_set_rate_near(pcm, params, &samplerate, 0) < 0) {
success = false;
}ยด
if (snd_pcm_hw_params(pcm, params) < 0) {
success = false;
}
snd_pcm_hw_params_get_period_size(params, &frames, 0);
bufsz = frames * CHANNELS * SAMPLE_SIZE;
buf = (char *) malloc(bufsz);
while (keep_playing) {
while (fread(buf, bufsz, 1, fp) != 0 && keep_playing) {
int err;
if ((err = snd_pcm_writei(pcm, buf, frames)) == -EPIPE) {
snd_pcm_prepare(pcm);
}
}
rewind(fp);
}
snd_pcm_drain(pcm);
snd_pcm_close(pcm);
free(buf);
return success;
}
From the man page of pthread_cancel:
On Linux, cancellation is implemented using signals. Under the NPTL threading implementation, the first real-time signal (i.e., signal 32)
is used for this purpose. On LinuxThreads, the second real-time signal is used, if real-time signals are available, otherwise SIGUSR2 is
used.
In your while(keep_playing) loop, you aren't yielding the thread enough to handle the cancel signal; in your main thread; you aren't waiting for the result of the cancel request, ergo both threads hog the cpu.
A small delay before you restart playing the sound and pthread_join() after you call pthread_cancel should fix your problem.

Update Gtk+2 text view widget from another thread

I am writing a chat client in GTK. The client has the main GTK loop, plus a spawned thread that sits and blocks at the read() function waiting for input from a file descriptor connected to a socket.
Once the read function gets past the blocking, it has a char buffer of text that I would like to append to the GTK Text View widget, however, this is in a thread that is different than the main GTK loop.
How can I most quickly update the GUI from that other thread? In Java, I would have used the SwingUtilities.invokeLater(new Runnable()) method to cause that method to be called from the main thread. I want similar behavior in C and using GTK.
Here is the function that is called from the new thread...
void* messageReceived(void* data)
{
struct ClientWindow* localVar = (struct ClientWindow*)data;
while(TRUE)
{
char buf[256];
int bytesRead = read(localVar->socketFileDescriptor, buf, 256);
GtkTextBuffer* tb = gtk_text_view_get_buffer(GTK_TEXT_VIEW(localVar->chatHistoryTextView));
GtkTextIter end;
//This code needs to execute in the main thread
gtk_text_buffer_get_end_iter(tb, &end);
gtk_text_buffer_insert(tb, &end, buf, -1);
}
}
The solution I came up with is using the g_idle_add() function. I don't know if I am missing something because the solution is very simple but no one else identified it, so it makes me a bit worried.
void* messageReceived(void* data)
{
struct ClientWindow* localVar = (struct ClientWindow*)data;
char* message = NULL;
int bytesRead = 0;
do
{
message = bufferedRead(localVar->socketFileDescriptor, 4, &bytesRead);
struct UpdateGUIMessage* updateGui = malloc(sizeof(struct UpdateGUIMessage));
memset(updateGui, 0, sizeof(struct UpdateGUIMessage));
updateGui->clientWindow = localVar;
updateGui->message = message;
updateGui->bytesRead = bytesRead;
g_idle_add(G_SOURCE_FUNC(updateGUI), updateGui);
}while(message != NULL);
}
bool updateGUI(void* data)
{
struct UpdateGUIMessage* localVar = (struct UpdateGUIMessage*)data;
GtkTextBuffer* tb = gtk_text_view_get_buffer(GTK_TEXT_VIEW(localVar->clientWindow->chatHistoryTextView));
GtkTextIter end;
gtk_text_buffer_get_end_iter(tb, &end);
gtk_text_buffer_insert(tb, &end, localVar->message, localVar->bytesRead);
free(localVar->message);
free(data);
return FALSE; //So it only gets called once and then is removed
}

Send WebSockets message to server

I am trying to work with an API of one device, but it is using a WS interface with enforced Origin header, which is giving me troubles.
In Chrome, I can open the Console while a page with the correct Origin is loaded, create the WS connection, and send/receive messages without difficulties:
Note that sent messages (in green) are always acknowledged by the server.
For reference, this is what happens if I create the connection on a different page, which results in an Origin header mismatch, reported as 404:
To sidestep this problem, I turned to C, because the rest of my program is written in that anyway. This is the code I have right now, based mostly on this answer:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <libwebsockets.h>
#define KGRN "\033[0;32;32m"
#define KCYN "\033[0;36m"
#define KRED "\033[0;32;31m"
#define KYEL "\033[1;33m"
#define KBLU "\033[0;32;34m"
#define KCYN_L "\033[1;36m"
#define KBRN "\033[0;33m"
#define RESET "\033[0m"
static int destroy_flag = 0;
static int connection_flag = 0;
static int writeable_flag = 0;
static void INT_HANDLER(int signo) {
destroy_flag = 1;
}
struct session_data {
int fd;
};
struct pthread_routine_tool {
struct lws_context *context;
struct lws *wsi;
};
static int websocket_write_back(struct lws *wsi_in, char *str, int str_size_in)
{
if (str == NULL || wsi_in == NULL)
return -1;
int n;
int len;
char *out = NULL;
if (str_size_in < 1)
len = strlen(str);
else
len = str_size_in;
out = (char *)malloc(sizeof(char)*(LWS_SEND_BUFFER_PRE_PADDING + len + LWS_SEND_BUFFER_POST_PADDING));
//* setup the buffer*/
memcpy (out + LWS_SEND_BUFFER_PRE_PADDING, str, len );
//* write out*/
n = lws_write(wsi_in, out + LWS_SEND_BUFFER_PRE_PADDING, len, LWS_WRITE_TEXT);
printf(KBLU"[websocket_write_back] %s\n"RESET, str);
//* free the buffer*/
free(out);
return n;
}
static int ws_service_callback(
struct lws *wsi,
enum lws_callback_reasons reason, void *user,
void *in, size_t len)
{
switch (reason) {
case LWS_CALLBACK_CLIENT_ESTABLISHED:
printf(KYEL"[Main Service] Connect with server success.\n"RESET);
connection_flag = 1;
break;
case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
printf(KRED"[Main Service] Connect with server error.\n"RESET);
destroy_flag = 1;
connection_flag = 0;
break;
case LWS_CALLBACK_CLOSED:
printf(KYEL"[Main Service] LWS_CALLBACK_CLOSED\n"RESET);
destroy_flag = 1;
connection_flag = 0;
break;
case LWS_CALLBACK_CLIENT_RECEIVE:
printf(KCYN_L"[Main Service] Client recvived:%s\n"RESET, (char *)in);
if (writeable_flag)
destroy_flag = 1;
break;
case LWS_CALLBACK_CLIENT_WRITEABLE :
printf(KYEL"[Main Service] On writeable is called. send byebye message\n"RESET);
websocket_write_back(wsi, "{\"command\":\"subscribe\",\"identifier\":\"{\\\"channel\\\":\\\"DevicesChannel\\\",\\\"share_token\\\":\\\"D0E91\\\"}\"}", -1);
websocket_write_back(wsi, "{\"command\":\"message\",\"identifier\":\"{\\\"channel\\\":\\\"DevicesChannel\\\",\\\"share_token\\\":\\\"D0E91\\\"}\",\"data\":\"{\\\"value\\\":100,\\\"action\\\":\\\"set_buzz\\\"}\"}", -1);
writeable_flag = 1;
break;
default:
break;
}
return 0;
}
static void *pthread_routine(void *tool_in)
{
struct pthread_routine_tool *tool = tool_in;
printf(KBRN"[pthread_routine] Good day. This is pthread_routine.\n"RESET);
//* waiting for connection with server done.*/
while(!connection_flag)
usleep(1000*20);
//*Send greeting to server*/
lws_callback_on_writable(tool->wsi);
}
int main(void)
{
//* register the signal SIGINT handler */
struct sigaction act;
act.sa_handler = INT_HANDLER;
act.sa_flags = 0;
sigemptyset(&act.sa_mask);
sigaction( SIGINT, &act, 0);
struct lws_context *context = NULL;
struct lws_context_creation_info info;
struct lws *wsi = NULL;
struct lws_protocols protocol;
memset(&info, 0, sizeof info);
info.port = CONTEXT_PORT_NO_LISTEN;
info.iface = NULL;
info.protocols = &protocol;
info.ssl_cert_filepath = NULL;
info.ssl_private_key_filepath = NULL;
info.extensions = lws_get_internal_extensions();
info.gid = -1;
info.uid = -1;
info.options = 0;
protocol.name = "websockets";
protocol.callback = &ws_service_callback;
protocol.per_session_data_size = sizeof(struct session_data);
protocol.rx_buffer_size = 0;
protocol.id = 0;
protocol.user = NULL;
context = lws_create_context(&info);
printf(KRED"[Main] context created.\n"RESET);
if (context == NULL) {
printf(KRED"[Main] context is NULL.\n"RESET);
return -1;
}
wsi = lws_client_connect(context, "mobu1.herokuapp.com", 443, 1,
"/cable", "mobu1.herokuapp.com", "link.motorbunny.com",
if (wsi == NULL) {
printf(KRED"[Main] wsi create error.\n"RESET);
return -1;
}
printf(KGRN"[Main] wsi create success.\n"RESET);
struct pthread_routine_tool tool;
tool.wsi = wsi;
tool.context = context;
pthread_t pid;
pthread_create(&pid, NULL, pthread_routine, &tool);
pthread_detach(pid);
while(!destroy_flag)
{
lws_service(context, 50);
}
lws_context_destroy(context);
return 0;
}
The result of running the above program is this:
As you can see, the periodic pings from server to my client are being picked up, but the lws_callback_on_writable(wsi); seems to have no effect as the LWS_CALLBACK_CLIENT_WRITEABLE callback never gets called. Additionally, if I call websocket_write_back() directly anywhere else, it doesn't seem to be sending anything to the server, and no acknowledgement is present either.
Is there something obvious I am doing wrong?
EDIT 1:
I found this neat wscat, where I can replicate the results from Chrome:
Now the question is, how can I interface this with my C program in a way that it can wait for the Welcome message from the server, and then send two messages?
And better yet, how to stay connected, so that my program can send multiple commands at different points of time without having to do the handshake all the time?
The reason why the LWS_CALLBACK_CLIENT_WRITEABLE callback never got called was because this particular server uses non-standard handshake. So, to bypass this, I forked a fork of libwsclient and modified the handshake checking function to not fail on mismatch. I also added an optional Origin header.
Now, all I need to do in my original program is
wsclient *client;
char sync_str[6];
void mb_send(int power, char* type)
{
char cmd[2048];
sprintf (cmd, "{\"command\":\"message\",\"identifier\":\"{\\\"channel\\\":\\\"DevicesChannel\\\",\\\"share_token\\\":\\\"%s\\\"}\",\"data\":\"{\\\"value\\\":%d,\\\"action\\\":\\\"set_%s\\\"}\"}",sync_str,power,type);
libwsclient_send(client,cmd);
}
void mb_connect()
{
char cmd[2048];
sprintf (cmd, "{\"command\":\"subscribe\",\"identifier\":\"{\\\"channel\\\":\\\"DevicesChannel\\\",\\\"share_token\\\":\\\"%s\\\"}\"}",sync_str);
libwsclient_send(client,cmd);
mb_send(0,"buzz");
}
int nop()
{
return 0;
}
int main()
{
client = libwsclient_new_extra("wss://mobu1.herokuapp.com/cable","https://link.motorbunny.com");
if(!client) {
fprintf(stderr, "Unable to initialize new WS client.\n");
exit(1);
}
libwsclient_onopen(client, &nop);
libwsclient_onmessage(client, &nop);
libwsclient_onerror(client, &nop);
libwsclient_onclose(client, &nop);
libwsclient_run(client);
...
mb_connect();
...
mb_send(200,"buzz");
mb_send(40,"twirl");
...
mb_send(0,"buzz");
mb_send(0,"twirl");
}
I found an ugly hack to make my C program send WebSocket messages to a server via the wsta program.
It requires a text file, into which my program will append whenever it wants to send a message to the server. The new lines are then picked up in the background by tail -f, and are piped to wsta which maintains the connection. Output can be redirected to /dev/null so that the wsta output doesn't pollute the output of my program, or sent to a file if responses from the server need to be parsed.
The whole script to make this work would look like this (or you could use FIFO pipe with cat instead of a file with tail):
#!/bin/bash
touch commands.txt
tail commands.txt -f -n 0 | wsta --header "Origin: https://link.motorbunny.com" "wss://mobu1.herokuapp.com/cable" &> /dev/null &
./program
In the C program, I just need to write to the commands.txt file:
FILE* cmd;
char sync_str[6];
void mb_connect()
{
fprintf (cmd, "{\"command\":\"subscribe\",\"identifier\":\"{\\\"channel\\\":\\\"DevicesChannel\\\",\\\"share_token\\\":\\\"%s\\\"}\"}\n",sync_str);
fflush(cmd);
}
void mb_send(int power, char* type)
{
fprintf (cmd, "{\"command\":\"message\",\"identifier\":\"{\\\"channel\\\":\\\"DevicesChannel\\\",\\\"share_token\\\":\\\"%s\\\"}\",\"data\":\"{\\\"value\\\":%d,\\\"action\\\":\\\"set_%s\\\"}\"}\n",sync_str,power,type);
fflush(cmd);
}
int main()
{
cmd = fopen ("commands.txt","w");
...
mb_connect();
...
mb_send(200,"buzz");
...
mb_send(0,"buzz");
}

recvmmsg() with timeout = 0 is equivalent to nonblocking recvmsg()?

I am on CentOS 6.5 with kernel version kernel-2.6.32-431.el6.
I was trying to find the implementation of recvmmsg(), and hopefully, I am not looking at the wrong source ~/rpmbuild/BUILD/kernel-2.6.32-431.el6/linux-2.6.32-431.el6.x86_64/net/socket.c. If I am, please kindly point me to the right source.
int __sys_recvmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen,
unsigned int flags, struct timespec *timeout)
{
int fput_needed, err, datagrams;
struct socket *sock;
struct mmsghdr __user *entry;
struct compat_mmsghdr __user *compat_entry;
struct msghdr msg_sys;
struct timespec end_time;
if (timeout &&
poll_select_set_timeout(&end_time, timeout->tv_sec,
timeout->tv_nsec))
return -EINVAL;
datagrams = 0;
sock = sockfd_lookup_light(fd, &err, &fput_needed);
if (!sock)
return err;
err = sock_error(sock->sk);
if (err)
goto out_put;
entry = mmsg;
compat_entry = (struct compat_mmsghdr __user *)mmsg;
while (datagrams < vlen) {
/*
* No need to ask LSM for more than the first datagram.
*/
if (MSG_CMSG_COMPAT & flags) {
err = __sys_recvmsg(sock, (struct msghdr __user *)compat_entry,
&msg_sys, flags, datagrams);
if (err < 0)
break;
err = __put_user(err, &compat_entry->msg_len);
++compat_entry;
} else {
err = __sys_recvmsg(sock, (struct msghdr __user *)entry,
&msg_sys, flags, datagrams);
if (err < 0)
break;
err = put_user(err, &entry->msg_len);
++entry;
}
if (err)
break;
++datagrams;
if (timeout) {
ktime_get_ts(timeout);
*timeout = timespec_sub(end_time, *timeout);
if (timeout->tv_sec < 0) {
timeout->tv_sec = timeout->tv_nsec = 0;
break;
}
/* Timeout, return less than vlen datagrams */
if (timeout->tv_nsec == 0 && timeout->tv_sec == 0)
break;
}
/* Out of band data, return right away */
if (msg_sys.msg_flags & MSG_OOB)
break;
}
out_put:
fput_light(sock->file, fput_needed);
if (err == 0)
return datagrams;
if (datagrams != 0) {
/*
* We may return less entries than requested (vlen) if the
* sock is non block and there aren't enough datagrams...
*/
if (err != -EAGAIN) {
/*
* ... or if recvmsg returns an error after we
* received some datagrams, where we record the
* error to return on the next call or if the
* app asks about it using getsockopt(SO_ERROR).
*/
sock->sk->sk_err = -err;
}
return datagrams;
}
return err;
}
Let's say there are 2 packets at the socket, and I try:
timespec t = {0, 0};
recvmmsg(fd, mmsg, vlen, 0, &t);
Then, because of these lines:
if (timeout->tv_nsec == 0 && timeout->tv_sec == 0)
break;
recvmmsg() will just return 1 packet instead of 2. Am I right?
It seems defecting the one of the main purposes of recvmmsg() -- trying to reduce # of system calls when there are packet queued.
Maybe I miss something?
Any suggestion is welcome.
Thanks!
============================
Update:
I tried to write a small snippet of code that waits for the packets to queue up and then call recvmmsg() with timeout=0 (not NULL). It still picks up only 1 packet. Hence, I think I am looking at the correct source code.
Yes, you are right. I think it is better to use NULL timeout + O_NONBLOCK if you want to read all packets in the queue
No. A zero timeout means infinity.
Ignore the recvmmsg timeout parameter and use SOL_SOCKET, SO_RCVTIMEO if necessary. Works correctly.
If you want to receive up to vlen messages exist in receive buffer without blocking, this will solve your problem:
recvmmsg(fd, mmsg, vlen, MSG_DONTWAIT, NULL);
It will loop until the internal recvmsg call returns by an error code like EAGAIN/EWOULDBLOCK or until vlen count of messages filled in your buffer without blocking.

linux fork socketpair sock_dgram

I'm new to socketpairs and I need my children each to pass information from a structure to the parent.I was told this can be done using SOCK_DGRAM but I don't know how to do it.I looked over the internet but i couldn't find a concrete example.Can you please show for example hoe can you pass to the parent a structure made out of 2 ints and a string maybe ?I just want an example so I can understand how I could build this kind of socketpair and send information through it.Thank you
How about the following:
int sockets[2];
if (socketpair(AF_INET, SOCK_DGRAM, 0, sockets) != -1)
{
int res = fork();
if (res == 0)
{
/* In child process */
/* We only need one socket, so close the other */
close(sockets[0]);
struct some_structure my_struct;
write(sockets[1], &my_struct, sizeof(my_struct));
/* All done */
exit(0);
}
else if (res > 0)
{
/* In parent process */
/* We only need one socket, so close the other */
close(sockets[1]);
struct some_structure my_struct;
read(sockets[0], &my_struct, sizeof(my_struct));
}
}
The above code doesn't check for, or handle, errors. It can't handle structures containing pointers, structures using arrays are okay though.
Assuming that your string is represented as a char* as in
struct data {
int i, j;
char *s;
};
you need to devise some serialization format, because sending a pointer won't work; the pointee is not passed so it won't point to anything useful in the receiver (the parent). A simple format would be to put the integers end-to-end, then directly append the string including its NUL terminator, so you'd get
int senddata(int fd, struct data const *d)
{
size_t msglen = 2 * sizeof(int) + strlen(d->s) + 1;
char *msg = malloc(msglen);
if (msg == NULL)
return -1;
((int *)msg)[0] = d->i;
((int *)msg)[1] = d->j;
strcpy(msg + 2 * sizeof(int), d->s);
ssize_t r = send(fd, msg, msglen, 0);
free(msg);
return r;
}
with a corresponding receive function for the parent. You might want to put some maximum length on the string, because the parent needs to know the size of the message in advance.

Resources