日期:2014-05-16 浏览次数:20894 次
准备做一个网络侦听进程和数据处理进程分离的模块,侦听进程和数据处理进程一对多关系,希望侦听进程在收到连接后,把socket句柄传送给空闲的数据处理进程。对于进程间文件描述符传送,先做了如下的示例程序。
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <sys/un.h>
#include <netinet/in.h>
#include <sys/wait.h>
#include <sys/uio.h>
/**
* Author: luckysym
* Date: 3/22/2013
*
* Global Variables:
* int client_pipe_fd 与子进程通讯的fd,用于向子进程发送远程socket句柄
*
* Functions:
* create_inet_server() 创建tcp侦听服务,父进程调用
* create_pipe_server() 创建本地管道侦听服务,父进程调用
* pipe_connect() 子进程连接父进程的管道
* inet_client_connected() 父进程收到远程tcp连接的处理函数,收到连接后将句柄发送到子进程
* pipe_client_connected() 父进程收到子进程的管道连接处理函数,函数中将管道句柄保存为全局变量
* wait_for_connect() 父进程等待socket连接,包括等待子进程管道连接,或者远程tcp连接,
* 收到连接后根据socket类型分别调用inet_client_connected()
* 或pipe_client_connected()
* recv_fd() 子进程用于接收父进程发来的远程socket句柄
*
* child_main() 子进程主函数
*
* 程序测试执行过程:
* 1. 父进程main函数启动后立即fork一个子进程,然后创建管道监听
* 2. 子进程启动后,等待5秒钟后(保证父进程管道创建完毕),连接父进程管道
* 3. 父进程收到子进程的管道连接后,保存管道通讯句柄,然后创建tcp侦听(端口30098)
* 4. 子进程连接父进程完毕后,等待接收父进程的管道消息
*
* 4. 远程启动一个telnet连接到30098端口。
* 5. 父进程收到连接后,首先向远程发送"Hello Client"消息
* 6. 然后父进程将tcp连接句柄通过管道发送给子进程(发送过程中句柄被复制)
* 7. 发送完毕后,父进程关闭tcp连接句柄
* 8. 子进程收到tcp连接句柄后,向远程telnet发送"This is child process speaking"消息
* 然后准备读取该tcp连接句柄。
* 9. 远程telnet端输入并发送一条文本消息,子进程在收到消息后会将其打印出(以[child]为前缀)
* 10. 子进程打印出消息后,关闭tcp连接句柄,telnet端连接同时关闭。
*/
int client_pipe_fd = 0;
int create_inet_server(uint16_t port)
{
int fd = socket(PF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0);
if ( fd < 0 ) {
printf("failed to create socket, err=%d\n", errno);
return fd;
}
struct sockaddr_in laddr;
laddr.sin_family = AF_INET;
laddr.sin_port = htons(port);
laddr.sin_addr.s_addr = htonl(INADDR_ANY);
int ret = bind(fd, (struct sockaddr*)&laddr, sizeof(laddr));
if ( ret < 0 ) {
printf("failed to bind local port %d, err=%d\n", port, errno);
return ret;
}
ret = listen(fd, 10);
if ( ret < 0 ) {
printf("failed to listen, err=%d", errno);
return ret;
}
return fd;
}
int create_pipe_server(const char * path)
{
int fd = socket(PF_UNIX, SOCK_STREAM , 0);
if ( fd < 0 ) {
printf("failed to create pipe, err=%d\n", errno);
return fd;
}
struct sockaddr_un laddr;
memset(&laddr, 0, sizeof(laddr));
laddr.sun_family = AF_LOCAL;
strcpy(laddr.sun_path, path);
//laddr.sun_len = sizeof(laddr.sun_length) + sizeof(laddr.sun_family) + strlen(laddr.sun_path) + 1;
int ret = bind(fd, (struct sockaddr*)&laddr, sizeof(laddr));
if ( ret < 0 ) {
printf("failed to bind local path %s, err=%d\n", path, errno);
return ret;
}
ret = listen(fd, 10);
if ( ret < 0 ) {
printf("failed to listen pipe, err=%d", errno);
return ret;
}
return fd;
}
int pipe_connect(const char * local, const char * remote)
{
struct sockaddr_un laddr;
struct sockaddr_un raddr;
laddr.sun_family = AF_LOCAL;
raddr.sun_family = AF_LOCAL;
strcpy(laddr.sun_path, local);
strcpy(raddr.sun_path, remote);
int llen = strlen(laddr.sun_path) + sizeof(laddr.sun_family) + 1;
int rlen = strlen(raddr.sun_path) + sizeof(raddr.sun_family) + 1;
unlink(local);
int fd = socket(PF_UNIX, SOCK_STREAM, 0);
if (fd < 0) {
printf("create client pipe socket fail, err=%d\n", errno);
return fd;
}
int ret = bind(fd, (struct sockaddr *)&laddr, llen);
if ( ret < 0) {
printf("bind local pipe path fail - %s, %d\n", local, errno);
return ret;
}
ret = connect(fd, (struct sockaddr *)&raddr, rlen );
if (ret < 0 ) {
printf("connect to remote pipe fail, errno=%d\n"