首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 操作系统 > UNIXLINUX >

Linux socket联接句柄进程间传送示例代码

2013-03-27 
Linux socket连接句柄进程间传送示例代码准备做一个网络侦听进程和数据处理进程分离的模块,侦听进程和数据

Linux socket连接句柄进程间传送示例代码

准备做一个网络侦听进程和数据处理进程分离的模块,侦听进程和数据处理进程一对多关系,希望侦听进程在收到连接后,把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", errno);return ret;}return fd;}int inet_client_connected(int sock, const struct sockaddr * raddr, socklen_t size){printf("Connection comming\n");int ret = write(sock, "Hello Client!\n", 15);struct cmsghdr *  cmptr = 0;struct msghdr msg;struct iovec  iov[1];char   buf[2];iov[0].iov_base = buf;iov[0].iov_len  = 2;msg.msg_iov = iov;msg.msg_iovlen = 1;msg.msg_name = NULL;msg.msg_namelen = 0;cmptr = (struct cmsghdr *)malloc(sizeof(struct cmsghdr) + sizeof(int));cmptr->cmsg_level = SOL_SOCKET;cmptr->cmsg_type  = SCM_RIGHTS;cmptr->cmsg_len   = sizeof(struct cmsghdr) + sizeof(int);*(int *)CMSG_DATA(cmptr) = sock;msg.msg_control = cmptr;msg.msg_controllen = sizeof(struct cmsghdr) + sizeof(int);buf[1] = 0; buf[0] = 1;ret = sendmsg(client_pipe_fd, &msg, 0);if ( ret != 2) {printf("send socket fd failed, ret=%d, err=%d\n", ret, errno);}free(cmptr);close(sock);return 0;}int pipe_client_connected(int sock, const struct sockaddr * addr, socklen_t size){const struct sockaddr_un * paddr = (const struct sockaddr_un *)addr;printf("client pipe connected fd=%d\n", sock);client_pipe_fd = sock;return -1;}#define INET_SOCK 0#define PIPE_SOCK 1int wait_for_connect(int sock, int type){fd_set rds;int ret = 0;struct timeval times;struct sockaddr_in riaddr;struct sockaddr_un ruaddr;socklen_t rsize[] = { sizeof(riaddr), sizeof(ruaddr) };struct sockaddr  * paddrs[] = { (struct sockaddr*)&riaddr, (struct sockaddr*)&ruaddr};while ( !ret ) {times.tv_sec = 1;times.tv_usec = 0;FD_ZERO(&rds);FD_SET(sock, &rds);ret = select(sock + 1, &rds, 0, 0, ×);if ( ret < 0 ) {printf("select fail. err=%d\n", errno);break;} else if ( ret == 0) {continue;} else {ret = accept(sock, paddrs[type], &rsize[type]);if ( ret < 0 ) {break;} else {if ( type == INET_SOCK) {ret = inet_client_connected(ret, paddrs[INET_SOCK], rsize[INET_SOCK]);} else if ( type == PIPE_SOCK ) {ret = pipe_client_connected(ret, paddrs[PIPE_SOCK], rsize[PIPE_SOCK]);}if ( ret < 0 ) break;}}ret = 0;} // whilereturn 0;}int recv_fd(int pipefd){char buf[2];int newfd = -1;struct iovec   iov[1];struct msghdr  msg;struct cmsghdr * cmptr = (struct cmsghdr *)malloc(sizeof(struct cmsghdr) + sizeof(int));iov[0].iov_base = buf;iov[0].iov_len  = sizeof(buf);msg.msg_iov     = iov;msg.msg_iovlen  = 1;msg.msg_name    = NULL;msg.msg_namelen = 0;msg.msg_control = cmptr;msg.msg_controllen = sizeof(struct cmsghdr) + sizeof(int);int ret = recvmsg(pipefd, &msg, 0);printf("[child] recvmsg returned, ret=%d\n", ret);if ( ret < 0 ) {printf("recvmsg failed, err=%d\n", errno);} else {newfd = *(int*)CMSG_DATA(cmptr);printf("[child] recv the socket fd: %d\n", newfd);}free(cmptr);return newfd;}int child_main(){printf("[child] child process running, wait 5 secs for pipe server creation\n");sleep(5);int fd = pipe_connect("/tmp/pipe_local", "/tmp/fd_trans");printf("[child] connect to remote pipe fd = %d\n", fd);int newfd = recv_fd(fd);int ret = write(newfd, "[child] This is child process speaking!\n", 41);if ( ret < 0 ) {printf("[child] write message to remote fail: ret=%d, err=%d\n", ret, errno);}char buf[256];memset(buf, 0, sizeof(buf));ret = read(newfd, buf, 256);if ( ret < 0) {printf("[child] failed to recv remote message: \n");} else {buf[ret] = 0;printf("[child] remote message arrived: %s\n", buf);}printf("[child] child exiting\n");close(fd);close(newfd);return 0;}int main(int argc, char *argv){if ( fork() == 0 ) {exit(child_main());}unlink("/tmp/fd_trans");int pipesock = create_pipe_server("/tmp/fd_trans");if (pipesock >= 0) {printf("pipe server created, now wait for child connecting\n");wait_for_connect(pipesock, PIPE_SOCK);}int inetsock = create_inet_server(30098);if ( inetsock >= 0 ) wait_for_connect(inetsock, INET_SOCK);close(client_pipe_fd);close(pipesock);close(inetsock);return 0;}


 

热点排行