Nie usatysfakcjonowany zasobami internetu, wynikami wyszukiwania Google... to choć zaciekawiony GLib'em, zdążyłem napisać własny wrapper na komunikację międzyprocesową na bazie BSD sockets. Wynik prezentuję poniżej.
Kod działa pod Windows, Linux i Solaris (ten ostatni wymaga gcc -o icch icch.c -lsocket do skompilowania.
/*****************************************************************************
icch.c -- wrapper on sockets to implement asynchronous interprocess
communication
Copyright (c) 2010 Manveru
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
*****************************************************************************/
#ifdef WIN32
/* Windoze specific stuff */
#define _WIN32_WINNT 0x0501
#include <ws2tcpip.h>
#include <process.h>
#define IS_ADDR_IN_USE (WSAEADDRINUSE == (errno = WSAGetLastError()))
#define CHECK_EWOULDBLOCK(x) (x == WSAEWOULDBLOCK)
#else
#include <sys/types.h>
#include <sys/socket.h>
#include <fcntl.h>
#include <netdb.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#define IS_ADDR_IN_USE (EADDRINUSE == errno)
#define CHECK_EWOULDBLOCK(x) ((x == EWOULDBLOCK) || (x == ECONNREFUSED))
#endif /* WIN32 */
#include <stdio.h>
static const char* icch_handshake = "-%icch_handshake%-";
typedef enum {
NOT_INITALIZED = 0,
BOUND,
CONNECTED,
DROPPED
} icch_internal_state_t;
typedef struct {
int sock_fd;
icch_internal_state_t state;
struct addrinfo* peerinfo_p;
} icch_handler_t;
static void local_perror(const char *s)
{
#ifdef WIN32
int ecode = WSAGetLastError();
if (!CHECK_EWOULDBLOCK(ecode))
{
char message[1024+1];
DWORD dwFlags = FORMAT_MESSAGE_FROM_SYSTEM
| FORMAT_MESSAGE_IGNORE_INSERTS
| FORMAT_MESSAGE_MAX_WIDTH_MASK;
DWORD dwLanguageId = MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT);
FormatMessageA(dwFlags, NULL, ecode, dwLanguageId, (LPSTR)message, 1024, NULL);
fprintf(stderr, "%s: %s", s, message);
#else /* WIN32 */
if (!CHECK_EWOULDBLOCK(errno))
{
perror(s);
#endif /* WIN32 */
exit(1);
}
}
icch_handler_t icch_create_connection() {
int status;
int idx = 0;
icch_handler_t icch_handler[2];
struct addrinfo hints;
struct in_addr *addr;
socklen_t addr_size;
unsigned long ioctlarg = 1;
memset(&hints, 0, sizeof hints); // make sure the struct is empty
hints.ai_family = AF_UNSPEC; // don't care IPv4 or IPv6
hints.ai_socktype = SOCK_DGRAM; // UDP datagram sockets
hints.ai_flags = AI_PASSIVE; // fill in my IP for me
/* prepare first address */
if ((status = getaddrinfo("127.0.0.1", "13331", &hints, &icch_handler[0].peerinfo_p)) != 0)
{
fprintf(stderr, "getaddrinfo error: %s\n", gai_strerror(status));
exit(1);
}
/* prepare second address */
if ((status = getaddrinfo("127.0.0.1", "13332", &hints, &icch_handler[1].peerinfo_p)) != 0)
{
fprintf(stderr, "getaddrinfo error: %s\n", gai_strerror(status));
exit(1);
}
while (idx < 2)
{
icch_handler[idx].sock_fd = socket(icch_handler[idx].peerinfo_p->ai_family,
icch_handler[idx].peerinfo_p->ai_socktype,
icch_handler[idx].peerinfo_p->ai_protocol);
/* prepare non-blocking socket */
#ifdef WIN32
ioctlsocket(icch_handler[idx].sock_fd, FIONBIO, &ioctlarg );
#else
fcntl(icch_handler[idx].sock_fd, F_SETFL, O_NONBLOCK);
#endif /* WIN32 */
if(0 > bind(icch_handler[idx].sock_fd,
icch_handler[idx].peerinfo_p->ai_addr,
icch_handler[idx].peerinfo_p->ai_addrlen))
{
/* couple gotchas! */
if (IS_ADDR_IN_USE)
{
fprintf(stderr, "Address in use, move to next socket!\n");
idx++;
continue; /* go to process second socket */
}
else
{
local_perror("bind");
} /* end of if (IS_ADDR_IN_USE) */
}
else /* of if (0 > bind(... */
{
icch_handler[idx].state = BOUND;
/* connect - do a trick to connect to second side ! */
fprintf(stderr, "* idx = %d; (idx + 1) % 2 = %d\n", idx, (idx + 1) % 2);
if (0 > connect(icch_handler[idx].sock_fd,
icch_handler[(idx + 1) % 2].peerinfo_p->ai_addr,
icch_handler[(idx + 1) % 2].peerinfo_p->ai_addrlen))
{
local_perror("connect");
}
else /* else of if (0 > connect(... */
{
icch_handler[idx].state = CONNECTED;
break;
} /* end of if (0 > connect(... */
} /* end of if (0 > bind(... */
} /* end of while (idx < 2) */
return icch_handler[idx];
}
int icch_send(icch_handler_t *h, void* data, size_t len)
{
if (h->state == CONNECTED)
{
if (-1 == (len = send(h->sock_fd, data, len, 0)))
{
local_perror("send");
}
}
else len = 0; /* ignore other cases */
return len;
}
int icch_recv(icch_handler_t *h, void* data, size_t len)
{
if (h->state == CONNECTED)
{
if (-1 == (len = recv(h->sock_fd, data, len, 0)))
{
local_perror("recv");
/* above exits so, clean up */
//memset(data, 0, len);
len = 0;
}
}
else
{
memset(data, 0, len);
len = 0; /* ignore other cases */
}
return len;
}
#ifdef WIN32
void win32exit(void)
{
WSACleanup();
}
#endif /* WIN32 */
int main(void)
{
int i = 0;
ssize_t slen = 0, rlen = 0;
char buffer[1024] = "test123";
icch_handler_t h = {0};
#ifdef WIN32
WSADATA wsaData;
atexit(win32exit); /* Do this at the end */
if (WSAStartup(MAKEWORD(2,0), &wsaData) != 0) {
fprintf(stderr, "WSAStartup failed.\n");
exit(1);
}
#endif /* WIN32 */
h = icch_create_connection();
printf("click\n");
snprintf(buffer, 1024, "test pid = %d", getpid());
while(i < 10)
{
snprintf(buffer, 1024, "test pid = %d", getpid());
icch_send(&h, buffer, 1024);
printf("[s]buffer = '%s'\n", buffer);
if (0 != icch_recv(&h, buffer, 1024))
{
printf("[r]buffer = '%s'\n", buffer);
i++;
}
}
return 0;
}