发明内容
本发明了提供了一种和客户端进行通信的方法及电子设备,以解决或者部分解决目前在OSX系统下不能够实现一对多的通信的技术问题。
为解决上述技术问题,本发明提供了一种和客户端进行通信的方法,所述方法包括:
注册一虚拟服务名称,并创建微内核的监听端口;
基于多个客户端的获取请求,将所述监听端口发送给多个客户端,使得所述多个客户端基于所述监听端口发送各自的连接请求给所述监听端口;
接收所述多个客户端发送的各自的连接请求;
利用微内核信息服务器的线程为每个连接请求对应创建微内核消息会话实例,并生成各微内核消息会话实例的连接应答消息发送给各连接请求对应的客户端;
封装和各客户端进行通信的通信消息,并发送给对应的客户端。
优选的,所述注册一虚拟服务名称,并创建微内核Mach的监听端口,包括:
调用OSX系统的bootstrap_check_in 函数,将虚拟服务名称对应的字符串注册到OSX系统中,并获取到所述监听端口。
优选的,所述接收所述多个客户端发送的各自的连接请求,具体包括:
利用微内核信息服务器的线程调用调用mach_msg系统函数接收来自各客户端的连接请求,其中各客户端的连接请求中携带有各客户端的端口名。
优选的,所述利用微内核信息服务器的线程为每个连接请求对应创建微内核消息会话实例,具体包括:
通过调用微内核信息服务器的allocSession函数,为各连接请求创建各自的一个MachMessageSession会话实例;
调用MachMessageSession的createFrom方法来初始化该各MachMessageSession会话实例,使各MachMessageSession会话实例包含有两个参数:对应的客户端的端口名,本地端口名。
优选的,所述生成各微内核消息会话实例的连接应答消息发送给对应的客户端,包括:
将各MachMessageSession会话实例的本地端口名封装到各自的连接应答消息中,并发送给对应的客户端的端口。
优选的,所述生成各微内核消息会话实例的连接应答消息发送给对应的客户端之后,所述方法还包括:
将各MachMessageSession会话实例放入到m_sessions列表中进行管理;
在recvSessionMsg函数中对m_sessions列表中的所有MachMessageSession进行读取操作,以获取对应的客户端发送的通信消息。
优选的,各MachMessageData通信消息包含三个字段:第一个字段是类型为mach_msg_header_t的header字段,第二个字段是名称为payloadSize的整型字段,表示要发送的不包括头部结构的负载数据大小,以及名称为payload的负载数据;
所述封装和各客户端进行通信的通信消息,并发送给对应的客户端,具体包括:
各MachMessageData通信消息的数据总量totalSize为MachMessageData的结构大小sizeof(MachMessageData)加上负载数据的大小payloadSize之和;
将各MachMessageData通信消息的数据总量totalSize和数值3进行与运算之后的结果是否为3,若是,则将所述通信消息发送给对应的客户端。
本发明公开了一种电子设备,包括:
注册模块,用以注册一虚拟服务名称,并创建微内核的监听端口;
发送模块,用以基于多个客户端的获取请求,将所述监听端口发送给多个客户端,使得所述多个客户端基于所述监听端口发送各自的连接请求给所述监听端口;
接收模块,用以接收所述多个客户端发送的各自的连接请求;
创建模块,用以利用微内核信息服务器的线程为每个连接请求对应创建微内核消息会话实例,并生成各微内核消息会话实例的连接应答消息发送给各连接请求对应的客户端;
封装模块,用于封装和各客户端进行通信的通信消息,并发送给对应的客户端。
本发明公开了一种计算机可读存储介质,其上存储有计算机程序,该程序被处理器执行时实现上述方法的步骤。
本发明公开了一种计算机设备,包括存储器、处理器及存储在存储器上并可在处理器上运行的计算机程序,所述处理器执行所述程序时实现上述方法的步骤。
通过本发明的一个或者多个技术方案,本发明具有以下有益效果或者优点:
本发明公开了一种和客户端进行通信的方法及电子设备,该方法包括:先注册一虚拟服务名称,并创建微内核的监听端口;会基于多个客户端的获取请求,将监听端口发送给多个客户端,使得多个客户端基于监听端口发送各自的连接请求给监听端口;然后接收多个客户端发送的各自的连接请求,并利用微内核信息服务器的线程为每个连接请求对应创建微内核消息会话实例,并生成各微内核消息会话实例的连接应答消息发送给各连接请求对应的客户端,另外还会封装和各客户端进行通信的通信消息,并发送给对应的客户端。由此可见,本申请通过注册一虚拟服务名称来建立一监听端口,并利用微内核信息服务器的线程为每个连接请求对应创建微内核消息会话实例用来和各自的客户端进行通信,由此实现利用一个监听端口即可以和多个客户端实现‘一对多’的方式的通信。
具体实施方式
为了使本申请所属技术领域中的技术人员更清楚地理解本申请,下面结合附图,通过具体实施例对本申请技术方案作详细描述。
在本发明实施例中,采用了OSX系统的Mach微内核概念。通过在Mach微内核中注册一个虚拟服务名称并创建微内核的一个监听端口,利用该监听端口和多个客户端进行通信,实现一对多的方式。在具体的实施过程中,首先会基于多个客户端的获取请求,将所述监听端口发送给多个客户端,使得所述多个客户端基于所述监听端口发送各自的连接请求给所述监听端口;然后接收所述多个客户端发送的各自的连接请求,并利用微内核信息服务器的线程为每个连接请求对应创建微内核消息会话实例,并生成各微内核消息会话实例的连接应答消息发送给对应的客户端。由此可见,本申请通过注册一虚拟服务名称来建立一监听端口,并利用微内核信息服务器的线程为每个连接请求对应创建微内核消息会话实例用来和各自的客户端进行通信,由此实现利用一个监听端口即可以和多个客户端实现‘一对多’的方式的通信。
下面介绍Mach微内核。
OSX系统是基于Mach微内核的,而Mach微内核中,一切的通信都是基于MachMessage也就是Mach消息来进行的。在Mach消息中,最重要的概念就是Mach port也就是Mach端口的概念。在OSX系统中,消息的传递都是从一个Mach端口传递到另外一个Mach端口。
所以根据上述的OSX特性,要实现进程间的通信,其实就是通过进程A中的Mach 端口将消息发送到进程B中的Mach端口上。由于OSX系统自带的CFMessagePort其底层都是依赖于Mach端口。所以本案也是在Mach端口的基础上,根据自定义服务名称实现一对多的进程间通信的方法。在该通信过程开始时,服务端只需要注册一个虚拟的(也即任意的不存在的)服务名称,客户端便可以建立起连接。从而实现进程间的通信。
而Mach消息的发送与接收的过程中,在OSX中,都是通过mach_msg来接收和发送消息。该函数的第一个参数为mach_msg_header_t的指针,表示要发送或者接收的消息,第二个参数指明是要接收消息还是发送消息,当值为MACH_SEND_MSG时表示要发送消息,值为MACH_RCV_MSG时,表示要接收消息,第三个参数表示要发送的数据大小,第四个参数表示要接收的数据大小。本案后面在利用mach_msg接收和发送消息时,都是按上述方法进行的,所以后面不在赘述。
mach_msg_header_t结构,该结构是一个非常重要的结构,任何的Mach消息的发送和接收都依赖于该结构。该结构的msgh_size表示要发送或者接收的数据大小,msgh_remote_port表示远程端口,在发送消息时一定要设置该字段值;msgh_local_port表示本地端口,在接收消息时一定要设置该字段值。
在本技术方案中有如下的几个名称:
MachMessageServer,表示一个Mach通信的服务器,通过一个具体的服务名称字符,用于处理来自MachMessageClient客户端的连接请求,并创建一个MachMessageSession对象表示一个与MachMessageClient的连接。
MachMessageSession,表示一个由MachMesssageServer服务器类生成的一个会话器,当MachMessageServer检测到一个来自MachMessageClient的连接请求后,就会创建一个MachMessageSession实例,以后就由该MachMessageSession实例与MachMessageClient进行数据的通信。这里便实现了一对多的概念。一个MachMessageServer服务器实例通过创建多个MachMessageSession实例,通过MachMessageSession实例与其相对应的每个MachMessageClient进行通信。
MachMessageClient,该模块表示一个Mach通信的客户端,该客户端通过一个具体的服务名称字符,向MachMessageServer发送连接请求,并等待来自MachMessageServer的请求应答,如果请求通过,便建立起了与MachMessageServer的通信通道,如果请求被拒绝,那么通信失败。
MachMessageConnect,该结构是本案中MachMessageClient向MachMessageServer发送的用于建立连接请求的消息。该消息中的第一个字段为类型为mach_msg_header_t的header字段(任何的Mach消息都必须包括这个mach_msg_header_t的头部结构和一个名称为portName的字符串,该字符串表示MachMessageClient的本地Mach端口名称。
MachMessageConnectResult,该结构是本案中MachMessageServer向MachMessageClient发送的用于应答连接请求的结果消息。同样第一个字段为mach_msg_header_t的header字段,一个名称为sessionId的整型字段,和一个名称为portName的字符串,该字符串表示与该MachMessageClient进行通信的远程Mach端口名称。
MachMessageData,该结构用于封装上层要发送的数据。该结构包含三个字段,第一个字段是类型为mach_msg_header_t的header字段,一个是名称为payloadSize的整型字段,表示要发送的负载数据大小(不包括头部结构),以及名称为payload的负载数据。该结构有一个alloc方法,用于快速的生成一个MachMessageData实例。在利用mach_msg发送MachMessageData数据时,有一个特别重要的地方就是header的msgh_size 与3进行与操作的结果必须等于0,即header.msgh_size & 3 == 0。如果不是,那么mach_msg就会返回MACH_SEND_MSG_TOO_SMALL的错误。为了解决这个问题,本发明实施例在判断时,选择了另一种判断方式,在alloc方法中计算MachMessageData数据的总大小totalSize时,原有的totalSize应该为MachMessageData的结构大小即sizeof(MachMessageData)加上负载数据的大小即payloadSize,那么totalSize = sizeof(MachMessageData) + payloadSize。根据上述大小限制规则,那么totalSize = (totalSize + 3) & ~3。比如要发送的负载数据大小为10个字节,而MachMessageData结构的大小为29字节,那么totalSize大小为39字节,与3进行与运算的结果为3,而调整后的totalSize大小为40字节大小。
通过上述对MachMessageServer、MachMessageSession以及MachMessageClient的介绍,下面来阐述相互怎样进行建立连接以及数据接收的。
参看图1,在本发明实施过程中,公开了一种和客户端进行通信的方法,该方法包括:
步骤11,注册一虚拟服务名称,并创建微内核的监听端口。
在具体的实施过程中,调用OSX系统的bootstrap_check_in 函数,将虚拟服务名称对应的字符串注册到OSX系统中,并获取到所述监听端口。
进一步的,MachMessageServer服务器调用OSX系统的bootstrap_check_in 函数,将服务名称为‘XXX’的字符串注册到系统中,并判断该函数的返回值,如果该函数的返回值为0,则代表注册服务成功,并获取到一个名称为m_listenPort的监听端口,并进入到下面的步骤2)。如果返回值不等于0,则注册服务失败,直接退出系统。
步骤12,基于多个客户端的获取请求,将所述监听端口发送给多个客户端,使得所述多个客户端基于所述监听端口发送各自的连接请求给所述监听端口。
步骤13,接收所述多个客户端发送的各自的连接请求。
具体来说,本发明实施例是利用微内核信息服务器的线程调用调用mach_msg系统函数接收来自各客户端的连接请求,其中各客户端的连接请求中携带有各客户端的端口名。
步骤14,利用微内核信息服务器的线程为每个连接请求对应创建微内核消息会话实例,并生成各微内核消息会话实例的连接应答消息发送给各连接请求对应的客户端。
在具体的实施过程中,主要是通过调用微内核信息服务器的allocSession函数,为各连接请求创建各自的一个MachMessageSession会话实例;然后调用MachMessageSession的createFrom方法来初始化该各MachMessageSession会话实例,使各MachMessageSession会话实例包含有两个参数:对应的客户端的端口名,本地端口名。
进一步的,会将各MachMessageSession会话实例的本地端口名封装到各自的连接应答消息中,并发送给对应的客户端的端口。
而作为一种可选的实施方式,所述生成各微内核消息会话实例的连接应答消息发送给对应的客户端之后,还会将各MachMessageSession会话实例放入到m_sessions列表中进行管理。之后,当服务器和客户端正式通信时,会在recvSessionMsg函数中对m_sessions列表中的所有MachMessageSession进行读取操作,以获取对应的客户端发送的通信消息。
步骤15,封装和各客户端进行通信的通信消息,并发送给对应的客户端。
在具体的实施过程中,各MachMessageData通信消息包含三个字段:第一个字段是类型为mach_msg_header_t的header字段,第二个字段是名称为payloadSize的整型字段,表示要发送的不包括头部结构的负载数据大小,以及名称为payload的负载数据;
所述封装和各客户端进行通信的通信消息,并发送给对应的客户端,具体包括:各MachMessageData通信消息的数据总量totalSize为MachMessageData的结构大小sizeof(MachMessageData)加上负载数据的大小payloadSize之和;将各MachMessageData通信消息的数据总量totalSize和数值3进行与运算之后的结果是否为3,若是,则将所述通信消息发送给对应的客户端。具体来说,各MachMessageData通信消息的数据总量totalSize利用下述公式进行判断:totalSize = (totalSize + 3) & ~3。举例来说,比如要发送的负载数据大小为10个字节,而MachMessageData结构的大小为29字节,那么totalSize大小为39字节,与3进行与运算的结果为3,而调整后的totalSize大小为40字节大小。
上述是本发明针对各客户端建立各MachMessageSession会话实例用以和对应的客户端进行通信的方式。而为了便于说明和解释本发明,下述实施例将采用建立一个MachMessageSession会话实例和一个客户端之间的通信的方式来进行描述。
1)注册服务名称,并创建Mach监听端口
调用OSX系统的bootstrap_check_in 函数,将服务名称为XXX的字符串注册到系统中,并判断该函数的返回值,如果该函数的返回值为0,则代表注册服务成功,并获取到一个名称为m_listenPort的监听端口,并进入到下面的步骤2)。如果返回值不等于0,则注册服务失败,直接退出系统。
2)创建MachMessageServer的线程循环
上一步调用成功后,创建一个线程来循环的处理来自客户端的连接请求,并接收每个MachMessageSession对应的MachMessageClient的消息。在线程循环中,通过调用MachMessageServer的listenPortLoop函数来处理来自客户端的连接请求,通过recvSessionMsg来接收来自客户端的消息
3)listenPortLoop处理连接请求
在该函数中通过调用mach_msg系统函数,来接收来自客户端的连接请求,为了防止该函数阻塞线程循环,在调用该函数时,设定1毫秒的超时时间。如果该函数的返回值为MACH_MSG_SUCCESS,表示成功的接收到了一条Mach消息。然后判断该消息结构的mach_msg_header_t结构中的msgh_id字段是否等于MMT_CONNECT值,如果相等,则代表该消息是一个类型为MachMessageConnect的连接请求消息。进入到下面的步骤a)
a)创建MachMessageSession
通过调用MachMessageServer的allocSession函数,创建一个MachMessageSession会话实例,然后调用MachMessageSession的createFrom方法来初始化该session,该函数有两个特别重要的参数,一个是remotePortName,代表MachMessageClient客户端的端口名,一个是localPortName代表该session的本地端口名。客户端在向MachMessageServer发送MachMessageConnect连接请求消息时,会带有一个portName的字符串,该字符串就是createFrom所需要的remotePortName参数,而localPortName则通过生成一个随机的GUID字符串来代表。在createFrom函数内部,通过调用bootstrap_look_up来获取remotePortName所代表的远程端口,标记为m_remotePort,并通过调用bootstrap_check_in来创建一个本地端口,标记为m_localPort。完成之后,MachMessageSession便可以向m_remotePort发送消息给MachMessageClient,并通过m_localPort接收来自MachMessageClient的消息。
b) 向客户端返回连接请求结果消息
上步骤中的createFrom完成之后,便成功的创建了一个MachMessageSession,同MachMessageClient进行通信。此时必须向MachMessageClient发送一个MessageMessageConnectResult的连接应答消息,该消息中包含有在步骤a)中创建的localPortName字符串。MachMessageClient通过向该localPortName所对应的端口上向该MachMessageSession发送消息。
c)将创建的MachMessageSession放入到m_sessions列表中进行管理。
4)recvSessionMsg接收客户端消息
在recvSessionMsg函数中对m_sessions列表中的所有MachMessageSession进行读取操作,也就是调用MachMessageSession的read方法,来获取来自MachMessageClient的通信消息。
5)MachMessageSession的read方法
调用mach_msg来接收来自该session对应的Client的消息,在调用该函数的方法上,应将m_localPort设置到mach_msg_header_t结构中的msgh_local_port字段中。并且由于该函数是在MachMessageServer的消息循环线程中调用的,所以不能够阻塞该线程,所以在调用mach_msg函数中,还需要设置超时时间,如果超时,那么该函数为返回,否则将一直等待下去。本案中设置的超时时间为1毫秒。
一、MachMessageClient客户端逻辑
上面讲述了MachMessageServer如何监听来自MachMessageClient的连接请求,以及创建相应的MachMessageSession同MachMessageClient进行数据通信,以及向Client发送MachMessageConnectResult连接结果消息。下面主要讲述MachMessageClient向Server发起连接请求的主要步骤
1)获取MachMessageServer注册的服务名称端口
通过调用bootstrap_look_up函数获取Server端所注册的名称为XXX的监听端口,如果该函数的返回值等于0,则进入到下面的步骤2)
2)创建一个随机guid字符串,并通过该字符串创建一个Mach端口
创建一个随机的guid字符串,然后调用bootstrap_check_in来获取该guid字符端所对应的端口,Client并依赖该端口接收消息。
3)发送MachMessageConnect连接请求消息
将步骤2)中的guid字符串填充到MachMessageConnect的portName字段中,然后调用mach_msg函数向Server发送连接请求消息。
4)等待连接请求结果
MachMessageConnect消息发送出去后,调用mach_msg函数接收来自Server的MachMessageConnectResult连接结果消息。然后获取MachMessageConnectResult结构中的portName字段,然后调用bootstrap_loop_up函数获取portName所对应的远程Mach端口,从而Client便可以通过该端口向MachMessageSession发送消息。
5)数据发送
上述的步骤4)成功之后,便可以同MachMessageServer进行数据的传输操作了。通过调用MachMessageData的alloc方法,将要发送的数据payload,和要发送的数据大小payloadSize,传入到alloc方法中,返回一个MachMessageData实例。并且将该结构中的header字段中的msgh_remote_port设置为步骤4)中获取到的m_remotePort,然后利用mach_msg函数,将该数据发送出去。
6)数据接收
步骤4)成功之后,创建一个线程,在该线程中循环的调用mach_msg来接收来自服务端的消息,在调用该函数的方法上,应将m_localPort设置到mach_msg_header_t结构中的msgh_local_port字段中。
通过上述对MachMessageServer和MachMessageClient进行连接请求和应答的介绍,实现了利用Mach端口进行一对多的进程间通信的方法。在该通信过程开始时,服务端只需要注册一个任意的不存在的服务名称,各客户端便可以建立起连接。从而实现进程间的通信。另外,在本发明实施例中,利用MachMessageData进行Server与Client之间的负载数据传输。
基于同一发明构思,本发明实施例还公开了一种电子设备,参看图2,包括:
注册模块21,用以注册一虚拟服务名称,并创建微内核的监听端口;
发送模块22,用以基于多个客户端的获取请求,将所述监听端口发送给多个客户端,使得所述多个客户端基于所述监听端口发送各自的连接请求给所述监听端口;
接收模块23,用以接收所述多个客户端发送的各自的连接请求;
创建模块24,用以利用微内核信息服务器的线程为每个连接请求对应创建微内核消息会话实例,并生成各微内核消息会话实例的连接应答消息发送给各连接请求对应的客户端;
封装模块25,用于封装和各客户端进行通信的通信消息,并发送给对应的客户端。
基于与前述实施例中同样的发明构思,本发明还提供一种计算机可读存储介质,其上存储有计算机程序,该程序被处理器执行时实现前文任一所述方法的步骤。
基于与前述实施例中同样的发明构思,本发明还提供一种计算机设备,包括存储器、处理器及存储在存储器上并可在处理器上运行的计算机程序,所述处理器执行所述程序时实现前文任一所述方法的步骤。
通过本发明的一个或者多个实施例,本发明具有以下有益效果或者优点:
本发明公开了一种和客户端进行通信的方法及电子设备,先注册一虚拟服务名称,并创建微内核的监听端口;会基于多个客户端的获取请求,将监听端口发送给多个客户端,使得多个客户端基于监听端口发送各自的连接请求给监听端口;然后接收多个客户端发送的各自的连接请求,并利用微内核信息服务器的线程为每个连接请求对应创建微内核消息会话实例,并生成各微内核消息会话实例的连接应答消息发送给各连接请求对应的客户端,另外还会封装和各客户端进行通信的通信消息,并发送给对应的客户端。由此可见,本申请通过注册一虚拟服务名称来建立一监听端口,并利用微内核信息服务器的线程为每个连接请求对应创建微内核消息会话实例用来和各自的客户端进行通信,由此实现利用一个监听端口即可以和多个客户端实现‘一对多’的方式的通信。
尽管已描述了本申请的优选实施例,但本领域内的普通技术人员一旦得知了基本创造性概念,则可对这些实施例作出另外的变更和修改。所以,所附权利要求意欲解释为包括优选实施例以及落入本申请范围的所有变更和修改。
显然,本领域的技术人员可以对本申请进行各种改动和变型而不脱离本申请的精神和范围。这样,倘若本申请的这些修改和变型属于本申请权利要求及其等同技术的范围之内,则本申请也意图包含这些改动和变型在内。