python进程间传递文件描述符扩展库

由于python本身的线程基本上比较残废,所以为了利用机器的cpu,就不得不用上多进程。。。

在游戏服务器的设计中,最为常见的方式是:

挂一个前端服务器,专门来维护与客户端的连接,然后将客户端的请求数据转发给后端服务器。。。

上面的方式是现在最为正统的。。。

但是自己因为环境的限制,需要做到对客户端透明,然后将后端的服务器转换成为多进程的。。。所以这里就只有用一点比较别扭的方法了,首先处理登录等一些常规的逻辑放在前端服务器,当进入放进进行匹配战斗之后,将客户端的socket连接直接交给后端服务器,然后进行处理。。。。。

因此这里就需要实现一个python能用的文件描述符传递扩展库。。。。

还好自己用C语言做过类似的东西。。。所以基本上把代码拿过来,再用cython做一层包装,也就能用了,这里就直接贴代码吧:

#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <sys/un.h>
#include <string.h>
#include <unistd.h>

int serv_listen(const char *name);
int send_fd(int sock, int fd, char* data);
int recv_fd(int sock, char *data);
void close_fd(int fd);

上面是头文件的定义,接下来把c语言的代码贴上来:

#include "sr.h"

int sr_connect(const char *name)
{
	int fd, size;
	struct sockaddr_un un;
	memset(&un, 0, sizeof(un));
	un.sun_family = AF_UNIX;

	if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
		printf("no1\n");
		return 0;
	}
	sprintf(un.sun_path, "%s%05d", "tmp", getpid());
	size = offsetof(struct sockaddr_un, sun_path) + strlen(un.sun_path);
	if (bind(fd, (struct sockaddr *)&un, size) < 0) {
		printf("no2\n");
		return 0;
	}
	strcpy(un.sun_path, name);
	size = offsetof(struct sockaddr_un, sun_path) + strlen(un.sun_path);
	if (connect(fd, (struct sockaddr *)&un, size) < 0) {
		printf("no3\n");
		return 0;
	}
	// if (listen(fd, 10) < 0) {
	// 	printf("no3");
	// }

	// char* hello = "hello fjs";
	// ssize_t out = send(fd, (void*)hello, strlen(hello), 0);
	// send_fd(lis, lis);
	return fd;
}

int send_fd(int sock, int fd, char* data)
{
    printf("here1: %s\n", data);
    struct iovec iov[1];
    iov[0].iov_base = data;
    iov[0].iov_len  = strlen(data);
    printf("len: %d\n", strlen(data));
    printf("here2: %s\n", iov[0].iov_base);  

    int cmsgsize = CMSG_LEN(sizeof(int));
    struct cmsghdr* cmptr = (struct cmsghdr*)malloc(cmsgsize);
    if(cmptr == NULL){
        return -1;
    }
    cmptr->cmsg_level = SOL_SOCKET;
    cmptr->cmsg_type = SCM_RIGHTS; // we are sending fd.
    cmptr->cmsg_len = cmsgsize;    

    struct msghdr msg;
    msg.msg_iov = iov;
    msg.msg_iovlen = 1;
    msg.msg_name = NULL;
    msg.msg_namelen = 0;
    msg.msg_control = cmptr;
    msg.msg_controllen = cmsgsize;
    *(int *)CMSG_DATA(cmptr) = fd;    

    int ret = sendmsg(sock, &msg, 0);
    free(cmptr);
    if (ret == -1){
        return -1;
    }
    return 0;
}    

int recv_fd(int sock, char* data)
{
    int cmsgsize = CMSG_LEN(sizeof(int));
    struct cmsghdr* cmptr = (struct cmsghdr*)malloc(cmsgsize);
    if (cmptr == NULL) {
        return -1;
    }
    char buf[33]; // the max buf in msg.
    memset(buf, 0, 33);
    struct iovec iov[1];
    iov[0].iov_base = buf;
    iov[0].iov_len = sizeof(buf);
    struct msghdr msg;
    msg.msg_iov = iov;
    msg.msg_iovlen  = 1;
    msg.msg_name = NULL;
    msg.msg_namelen = 0;
    msg.msg_control = cmptr;
    msg.msg_controllen = cmsgsize;    

    int ret = recvmsg(sock, &msg, 0);  

    if (ret == -1) {
        return -1;
    }
    int fd = *(int *)CMSG_DATA(cmptr);
    strcpy(data, iov[0].iov_base);
    free(cmptr);
    return fd;
}

void close_fd(int fd)
{
    close(fd);
}

// int main()
// {
// 	int lis = serv_listen("/tmp/fjs.sock");
// 	printf("ok\n");
// 	char* hello = "hello fjs";
// 	// ssize_t out = send(lis, (void*)hello, strlen(hello), 0);
// 	send_fd(lis, lis);

// }

最后贴上cython的包装文件:

cdef extern from "sr.h":
	extern int sr_connect(const char *name)
	extern int send_fd(int sock, int fd, char* data)
	extern int recv_fd(int sock, char* data)
	void close_fd(int fd)

cdef extern from "stdlib.h":
	extern void *malloc(unsigned int num_bytes)
	extern void free(void *ptr)

def connect_and_send():
	cdef char* dist = "/tmp/fjs.sock"
	cdef int fd = sr_connect(dist)
	send_fd(fd, fd, "fdsaf");

def fjs_recv_fd(sock):
	cdef int fd = sock
	cdef char* data = <char*>malloc(33)
	fd = recv_fd(fd, data)
	try:
		out_data = data
		return (fd, out_data)
	finally:
		free(data)

def fjs_send_fd(fd1, fd2, data):
	cdef int source = fd1
	cdef int des    = fd2
	send_fd(source, des, data)

def fjs_close_fd(fd):
	cdef int now_fd = fd
	close_fd(fd)

嗯。。就上面这些代码。。。这里需要基于unix域socket。。。。

最后吐槽一下。。。。python真他妈的慢。。。。

时间: 2024-08-25 22:56:57

python进程间传递文件描述符扩展库的相关文章

进程间传递文件描述符

下面的实例展示了如何使用Unix域套接字在进程间传递文件描述符 参考文献:1) <Unix网络编程> 2)  http://book.51cto.com/art/200912/168560.htm 最近学习了使用Unix域套接字在进程间传递文件描述符,仿照参考资料,自己也写了简单的程序来实践这种技术. 其他不多说了,具体理论知识参见参考资料,开始我自己的程序介绍(在OpenSolaris 2009.06平台上测试): 1  程序作用说明:父进程,子进程以及另外一个进程向同一个文件的文件描述符向

进程间传递文件描述符——sendmsg和recvmsg函数

先引入一个例子,该程序的目的是子进程向父进程传递文件描述符,并通过该文件描述符读取buf. #include <func.h> int main(){ int fds[2]; pipe(fds); if(!fork()){ close(fds[1]); int fd; read(fds[0], &fd, sizeof(fd)); printf("child fd = %d\n", fd); char buf[128] = {0}; read(fd, buf, siz

在进程间传递文件描述符

由于fork调用之后,父进程中打开的文件描述符在子进程中仍然保持打开,所以文件描述符可以很方便地从父进程传递到子进程.需要注意的是,传递一个文件描述符并不是传递一个文件描述符的值,而是要在接收进程中创建一个新的文件描述符,并且该文件描述符和发送进程中被传递的文件描述符指向内核中相同的文件表项. 在Linux下,我们可以利用UNIX城socket在进程间传递特殊的辅助数据,以实现文件描述符的传递,它在子进程中打开一个文件描述符,然后将它传递给父进程,父进程则通过读取该文件描述符来获得文件的内容.

UNIX进程之间传递文件描述符recvmsg与sendmsg

socketpair: 功能:创建一个全双工的流管道 原型 int socketpair(int domain, int type, int protocol, int sv[2]); 参数 domain: 协议家族 type: 套接字类型 protocol: 协议类型 sv: 返回套接字对 返回值:成功返回0:失败返回-1 ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags); ssize_t recvmsg(int

0707 父子进程之间传递文件描述符

1 /************************************************************************* 2 > File Name: pass_fd.c 3 > Author:Monica 4 > Mail:[email protected] 5 > Created Time: Mon 07 Jul 2014 09:52:49 PM CST 6 ********************************************

通过UNIX域套接字传递文件描述符

传送文件描述符是高并发网络服务编程的一种常见实现方式.Nebula 高性能通用网络框架即采用了UNIX域套接字传递文件描述符设计和实现.本文详细说明一下传送文件描述符的应用. 1. TCP服务器程序设计范式 ??开发一个服务器程序,有较多的的程序设计范式可供选择,不同范式有其自身的特点和实用范围,明了不同范式的特性有助于我们服务器程序的开发.常见的TCP服务器程序设计范式有以下几种: 迭代服务器 并发服务器,每个客户请求fork一个子进程 预先派生子进程,每个子进程无保护地调用accept 预先

C/C++ 父子进程之间的文件描述符问题

在C程序中,文件由文件指针或者文件描述符表示.ISO C的标准I/0库函数(fopen, fclose, fread, fwrite, fscanf, fprintf等)使用文件指针,UNIX的I/O函数(open, close, read, write, ioctl)使用文件描述符.下面重点来说下,文件描述符是如何工作的. 文件描述符相当于一个逻辑句柄,而open,close等函数则是将文件或者物理设备与句柄相关联.句柄是一个整数,可以理解为进程特定的文件描述符表的 索引.先介绍下面三个概念,

在父子进程间用管道传递文件描述符

#include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <errno.h> #include <sys/socket.h> #define ERR_EXI

[转] linux系统文件流、文件描述符与进程间关系详解

http://blog.sina.com.cn/s/blog_67b74aea01018ycx.html linux(unix)进程与文件的关系错综复杂,本教程试图详细的阐述这个问题. 包括: 1.linux多/单进程与多/单文件对于文件流和描述符在使用时的关联情况及一些需要注意的问题. 2.fork,vfork流缓冲等对文件操作的影响. 1.linux文件系统结构 首先补充一点基础知识,了解一下linux文件系统.如下图所示: 图1 磁盘,分区和文件系统 应该明白,上图所示结构是硬盘中文件存放