使用ip_conntrack达成UDP服务的多进程处理
发布时间:2021-11-21 19:09:19 所属栏目:PHP教程 来源:互联网
导读:UDP是无连接的,一个UDP包发出之后,对端接收到,事情就完了,即使对端没有接收到,事情也随之结束,两端都不会保存任何信息(UDP connect函数仅仅绑定了一个元组,不会对协议通信有影响)。因此无法像TCP那样实现accept。而TCP服务的多处理机制基本都是基于
UDP是无连接的,一个UDP包发出之后,对端接收到,事情就完了,即使对端没有接收到,事情也随之结束,两端都不会保存任何信息(UDP connect函数仅仅绑定了一个元组,不会对协议通信有影响)。因此无法像TCP那样实现accept。而TCP服务的多处理机制基本都是基于accept的,TCP的侦听socket只负责接受连接,进而调度给一个进程或者线程,accept/fork机制已经成了多处理的必杀技,由于UDP无法实现accept,也就很难实现多处理以及xinetd那样的服务调度程序,可是事情并没有完! 虽然UDP不保存任何连接信息,可是Linux内核Netfilter的nf_conntrack为之保存了一个连接,这个conntrack如果能被使用,那么就可以利用它实现UDP的多处理,接下来唯一的问题就是端口的问题。多进程的UDP服务必须绑定不同的端口(或者不同secondary IP的同一个端口),比如6000-6004五个端口对应五个UDP服务进程,剩下的工作就是将客户端的访问定向到这五个服务中的一个: iptables -t nat -A LBalance -p udp --dport $port_base -j DNAT --to-destination $LISTEN_ADDR:6000-6004 这样就好了。NAT是有状态的,conntrack模块负责保持这个连接,且NAT仅仅对一个流的头包有效,这样就可以把同一个连接的数据定向到同一个进程了,唯一需要注意的就是,nf_conntrack模块对于保持的连接是有超时时间的,如果过了超时时间,连接数据结构就会被释放掉,因此如果不能保证数据持续传输的情形下,最好在应用层有一定的心跳机制。 何时?iptables可以拥有一个模块,可以将连接定向到一个进程,进程PID可以通过procfs或者sysfs设置,到那时,UDP服务就可以不绑定那么多的端口了。左右思索,觉得还是自己实现一个为好,可以参考TPROXY以及2.4内核Netfilter的owner-pid来实现,在HOOK function中可以有以下的片断: struct task_struct *p; struct files_struct *files; int i; p = pid_task(find_get_pid(进程PID,可以通过procfs来配置), PIDTYPE_PID); if (!p) goto out; task_lock(p); files = p->files; if(files) { for (i=0; i < 目前打开的描述符; i++) { struct file *f = files->fd_array[i]; if (S_ISSOCK(f->f_path.dentry->d_inode->i_mode)){ 从file结构体中取出private_data; 从private_data映射到socket,进而取出sock结构体; 将sock结构体和skb关联; } } } task_unlock(p); 以上只是一个片断,其实还要和conntrack结合对应到具体的流,可能还需要mark机制。 如果一个技术本身没有提供某个机制,那么肯定有其它的层可以为之提供该种功能,这个层可以在上面也可以在下面,对于UDP,你可以在应用层为之封装一个层,类似OpenVPN或者DTLS那样,也可以利用底层的ip_conntrack。 ![]() (编辑:云计算网_泰州站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |