处理网络上的越权访问(逐步详述)
通知:博客已搬家到****地址为:
https://blog.****.net/hdp134793
用户越权访问的处理
一般来说,越权放问就好比你是非系统管理员用户,却偷偷的跑进了系统管理菜单,僭越权利访问里面的信息甚至修改其中的数据(不同级别的越权又称垂直越权访问),因此对数据的安全性造成极大的威胁,是故每家企业都有其方法来保证企业内部数据的安全性,也就是解决越权访问的问题。
有关改业务处理主要考虑下面两个方面:
url的越权访问和接口方法的越权访问
- 通过角色用户来判断是否越权访问
分下面几种情况来讨论:
a.当没有用户登录的时候:
只允许登录界面和一些js,css等非jsp/html的页面访问,这样算是越权
b.当用户登录了之后:
首先通过角色关系去数据库中查找他能够访问的页面,这样的话就可以针对能访问的做一个放行处理,非权限内的页面属于越权,这个时候拦截掉,可以直接让其跳转到登陆界面表示他越权了已经(自行处理越权后的操作)。
2.具体实现流程
a.统计好每个菜单url对应的接口方法和子页面访问路径(jsp或html等)
b.将统计好的数据一一对应起来,存放在配置文件中或者数据库某个表中,这些数据随着业务的新增或者裁剪应有相关对应的维护,暂时以配置文件为例
c.在登录模块中通过登录的用户角色查找它能够访问的菜单URL(写一个接口方法),存放在一个静态公有list变量中,如下定义:
public static List<String> MENU_URLS = new ArrayList<>();
将查询返回过来的url集合塞给MENU_URLS。
d,定义一个静态公有Properties变量,用来存放配置文件中的键值对,如下定义:
public static Properties MENU_INTERFACE = null;
然后对其进行读取配置文件并赋值
String url = request.getSession().getServletContext().getRealPath("/WEB-INF/classes/porturl.properties"); File file = new File(url); try { MENU_INTERFACE = new Properties(); FileInputStream inStream = new FileInputStream(file); MENU_INTERFACE.load(inStream); } catch (Exception e) { System.out.println(e); }
e.SpringMVC拦截器,判断session中用户是否过期,在doFilter 方法里匹配,只要js,css,pdf,png,jpg等文件可放行,在里面判断用户是否登录,没有登录的话只要是非登录页面的页面,统一视为越权访问。如果是已经登录的用户,我们可以取到登录后的MENU_URLS 和 MENU_INTERFACE 的信息,可以做如下判断:
如果访问的路径checkURL和MENU_URLS 中的任意子串能匹配的上的话说明是可以访问的,这种情况放行,否则拦截下来跳转登录,记录越权访问信息;
在上面的情况下,还会存在一种情况,当访问的路径是子页面的时候,这个时候需要去匹配,能匹配上的可以放行,这个需要通过checkURL去配置文件中找到对应的父URL,然后再进行匹配MENU_URLS,这个里面的父URL是唯一的,配置文件中一(父)对多(子)。
接口访问的也是同样的道理。
其中放行方法:
//正常访问,直接放行 filterChain.doFilter(servletRequest, servletResponse); return; //初始化printWriterURL String printWriterURL="<script>window.location.href='"+httpRequest.getContextPath()+ "/jsps/login/login.jsp';</script>"; //其他jsp的时候算是越权访问 logger.info("用户越权访问!!!!" + url); PrintWriter p = httpResponse.getWriter(); p.write(printWriterURL); p.flush(); p.close(); return;
这样就大功告成,具体代码细节如下所示:
public class SystemFilter implements Filter { private static Logger logger = Logger.getLogger(SystemFilter.class); @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { HttpServletRequest httpRequest = (HttpServletRequest) servletRequest; HttpServletResponse httpResponse = (HttpServletResponse) servletResponse; HttpSession session = httpRequest.getSession(true); String url = httpRequest.getRequestURI(); String printWriterURL = "<script>window.location.href='" + httpRequest.getContextPath() + "/jsps/login/login.jsp';</script>"; String checkURL = url; if(checkURL.endsWith("/")){ checkURL = checkURL.substring(0, checkURL.length()-1); if(checkURL.split("/").length == 2){ PrintWriter p = httpResponse.getWriter(); p.write(printWriterURL); p.flush(); p.close(); return; } } Object object = session.getAttribute("user"); User user = object == null ? null : (User) object; boolean isAjaxRequest = false; if (!StringUtils.isBlank(httpRequest.getHeader("x-requested-with")) && httpRequest.getHeader("x-requested-with").equals("XMLHttpRequest")) { isAjaxRequest = true; } StringBuffer server = httpRequest.getRequestURL(); if (server.toString().contains(".css") || server.toString().contains(".jsp") || (server.toString().contains(".js") && !server.toString().contains(".jsp")) || server.toString().contains(".png") || server.toString().contains(".jpg") || server.toString().contains(".gif") || server.toString().contains(".svg") || server.toString().contains(".so") || server.toString().contains(".woff") || server.toString().contains(".ttf") || server.toString().endsWith("/downPDF") // 下载放行 || server.toString().contains("/websocket") // 推送放行 ){ if(user ==null && server.toString().contains(".jsp")){ if(server.toString().contains("index.jsp")){ logger.info("!!!用户未登录且使用index.jsp页面:" + url); PrintWriter p = httpResponse.getWriter(); p.write(printWriterURL); p.flush(); p.close(); return; }else if(server.toString().contains("login.jsp")){ //当访问的是login.jsp的时候放行 filterChain.doFilter(servletRequest, servletResponse); return; }else{ //其他jsp的时候算是越权访问 logger.info("用户越权访问!!!!" + url); PrintWriter p = httpResponse.getWriter(); p.write(printWriterURL); p.flush(); p.close(); return; } }else if(user !=null && server.toString().contains(".jsp") && !(server.toString().contains("login.jsp"))){ Boolean ISURL = false; //获取访问url的字符串 int urllen = checkURL.split("/").length; String checkurl = ""; for(int i=2;i<urllen;i++){ if(i<urllen-1){ checkurl+=checkURL.split("/")[i]+"/"; }else{ checkurl+=checkURL.split("/")[i]; } } c:for(int j=0;j<LoginService.MENU_URLS.size();j++){ //获取角色用户对应二级菜单的URL String _orUrls = LoginService.MENU_URLS.get(j); if(_orUrls.equals(checkurl)){ System.out.println("符合条件的:"+checkurl); ISURL = true; break c; } } //当上一个判断时不能访问考虑第二种情况 if(!ISURL){ //通过二级菜单读取配置文件中对应的子url,防止空指针异常 String purls = LoginService.MENU_INTERFACE.get(checkurl)==null?"":LoginService.MENU_INTERFACE.get(checkurl).toString(); d:for(int j=0;j<LoginService.MENU_URLS.size();j++){ String _orUrls = LoginService.MENU_URLS.get(j); //获取角色用户对应二级菜单的URL和通过访问路径去查配置文件时候存在吻合则放行 if(_orUrls.equals(purls)){ System.out.println("符合条件的:"+purls); ISURL = true; break d; } } } if(!ISURL){ //越权访问 String msg = "ip=" + user.getIpaddr() + "&name=" + user.getUsername(); logger.info("!!!越权访问:" + url + ";用户信息:" + msg); printWriterURL = "<script>window.location.href='" + httpRequest.getContextPath() + "/jsps/login/login.jsp?" + msg + "';</script>"; }else{ System.out.println("========>"+LoginService.MENU_INTERFACE.get(checkURL.split("/")[2]+"/"+checkURL.split("/")[3])); //正常访问,直接放行 filterChain.doFilter(servletRequest, servletResponse); return; } PrintWriter p = httpResponse.getWriter(); p.write(printWriterURL); p.flush(); p.close(); return; } // 如果发现是css或者js文件,直接放行 filterChain.doFilter(servletRequest, servletResponse); return; } if (!isAjaxRequest) { if (user != null && (server.toString().contains("index.jsp") || server.toString().contains("login.jsp"))) { // 如果发现是css或者js文件,直接放行 filterChain.doFilter(servletRequest, servletResponse); return; } else { if(user != null){ System.out.println("-----------1-----------"+checkURL); if(LoginService.MENU_INTERFACE != null && LoginService.MENU_INTERFACE.size() != 0 && LoginService.MENU_URLS != null && LoginService.MENU_URLS.size() != 0 ){ if(checkURL.split("/").length == 4){ System.out.println("-----------2-----------"+LoginService.MENU_INTERFACE.get(checkURL.split("/")[2]+"/"+checkURL.split("/")[3])); // if(LoginService.MENU_INTERFACE.get(checkURL.split("/")[2]+"/"+checkURL.split("/")[3]) == null){ // // 如果发现是css或者js文件,直接放行 // filterChain.doFilter(servletRequest, servletResponse); // return; // } Boolean hasIn = false; if(null != LoginService.MENU_INTERFACE.get(checkURL.split("/")[2]+"/"+checkURL.split("/")[3])){ String[] urls = LoginService.MENU_INTERFACE.get(checkURL.split("/")[2]+"/"+checkURL.split("/")[3]).toString().split(","); // jsp/pages/configmgt/device/deviceList.jsp,jsp/pages/configmgt/systemmgt/systemmgtList.jsp a:for(int i=0;i<urls.length;i++){ String _url = urls[i]; for(int j=0;j<LoginService.MENU_URLS.size();j++){ String _orUrls = LoginService.MENU_URLS.get(j); if(_orUrls.equals(_url)){ System.out.println("符合条件的:"+_url); hasIn = true; break a; } } } } if(!hasIn){ //越权访问 String msg = "ip=" + user.getIpaddr() + "&name=" + user.getUsername(); logger.info("!!!越权访问:" + url + ";用户信息:" + msg); printWriterURL = "<script>window.location.href='" + httpRequest.getContextPath() + "/jsps/login/login.jsp?" + msg + "';</script>"; }else{ System.out.println("========>"+LoginService.MENU_INTERFACE.get(checkURL.split("/")[2]+"/"+checkURL.split("/")[3])); //正常访问,直接放行 filterChain.doFilter(servletRequest, servletResponse); return; } } } } PrintWriter p = httpResponse.getWriter(); p.write(printWriterURL); p.flush(); p.close(); return; } } if (url.toString().contains(".jsp")) { logger.info(httpRequest.getSession().getServletContext().getRealPath("/") + "-------"); logger.info("拦截器放行地址:-------------------" + url); } filterChain.doFilter(servletRequest, servletResponse); return; } /** * 判断是否为Ajax请求 * * @param request * HttpServletRequest * @return 是true, 否false */ public static boolean isAjaxRequest(HttpServletRequest request) { return request.getRequestURI().startsWith("/api"); // String requestType = request.getHeader("X-Requested-With"); // return requestType != null && requestType.equals("XMLHttpRequest"); } @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void destroy() { // To change body of implemented methods use File | Settings | File // Templates. } }
上一篇: 横向越权与纵向越权
下一篇: WEB 漏洞逻辑覆盖漏洞详解
推荐阅读
-
Microsoft 365 新功能 Flash:离线时使用 OneDrive Web 应用程序-作为管理员,您可以使用概述的组策略控制离线模式的各个方面。 为组织中的用户启用此功能后,当用户访问 OneDrive for Web 时,将首次设置离线模式。OneDrive for Web 的用户文件元数据副本会安全地本地存储在用户的设备上。用户设备上的这些数据只能由该用户使用和访问。如果其他人在您的设备上登录,他们将无法使用设备上的本地数据。 用户设备上的安全本地网络服务器将处理用户在 OneDrive for Web 中对其文件执行的操作,如查看、排序、重命名、移动和复制,这些操作传统上需要由 OneDrive 云服务处理。通过消除网络在加载和使用 OneDrive for Web 时的瓶颈,可以快速、流畅地与用户文件进行交互,如加载文件和文件夹、排序、重命名、移动和重命名。即使用户离线、失去互联网连接或服务中断,所有这些操作也将继续运行。 - OneDrive 离线模式允许您在离线状态下通过浏览器、OneDrive PWA(渐进式 Web 应用程序)和 Microsoft Teams 在 OneDrive 上工作,从而提高在各种网络上的性能,并帮助减轻与处理大型文件集相关的限制。 - 目前,安装了 OneDrive Sync 应用程序的 Windows 设备(Windows 10 或更高版本)和 macOS 设备(macOS 12 Monterey 或更高版本)以及基于 Chromium 的浏览器(Microsoft Edge、Google Chrome)都支持 OneDrive 离线模式。 - 默认情况下,OneDrive 将为网络上的用户提供离线模式,用户和管理员都可以选择禁用 OneDrive 的离线模式。 - 脱机模式是针对每台设备的设置(为用户在网络*问 OneDrive 所使用的每台设备单独配置)。 - 数据会安全地存储在用户配置文件目录下的本地数据库中,并通过安全的本地主机 HTTP 服务器处理请求。离线模式由一个单独的后台进程(Microsoft.SharePoint.exe)支持。 - 开启离线模式后,用户将在网络上的 OneDrive 顶部导航栏看到一个新图标。 这将如何影响您的组织
-
处理网络上的越权访问(逐步详述)
-
包婷婷 (201550484)作业一 统计软件简介与数据操作-SPSS(Statistical Product and Service Solutions),"统计产品与服务解决方案"软件。最初软件全称为"(SolutionsStatistical Package for the Social Sciences),但是随着SPSS产品服务领域的扩大和服务深度的增加,SPSS公司已于2000年正式将英文全称更改为"统计产品与服务解决方案",标志着SPSS的战略方向正在做出重大调整。为IBM公司推出的一系列用于统计学分析运算、数据挖掘、预测分析和决策支持任务的软件产品及相关服务的总称SPSS,有Windows和Mac OS X等版本。 1984年SPSS总部首先推出了世界上第一个统计分析软件微机版本SPSS/PC+,开创了SPSS微机系列产品的开发方向,极大地扩充了它的应用范围,并使其能很快地应用于自然科学、技术科学、社会科学的各个领域。世界上许多有影响的报刊杂志纷纷就SPSS的自动统计绘图、数据的深入分析、使用方便、功能齐全等方面给予了高度的评价。 R统计软件介绍 R是一套完整的数据处理、计算和制图软件系统。其功能包括:数据存储和处理系统;数组运算工具(其向量、矩阵运算方面功能尤其强大);完整连贯的统计分析工具;优秀的统计制图功能;简便而强大的编程语言:可操纵数据的输入和输出,可实现分支、循环,用户可自定义功能。 与其说R是一种统计软件,还不如说R是一种数学计算的环境,因为R并不是仅仅提供若干统计程序、使用者只需指定数据库和若干参数便可进行一个统计分析。R的思想是:它可以提供一些集成的统计工具,但更大量的是它提供各种数学计算、统计计算的函数,从而使使用者能灵活机动的进行数据分析,甚至创造出符合需要的新的统计计算方法。 该语言的语法表面上类似 C,但在语义上是函数设计语言(functional programming language)的变种并且和Lisp 以及 APL有很强的兼容性。特别的是,它允许在"语言上计算"(computing on the language)。这使得它可以把表达式作为函数的输入参数,而这种做法对统计模拟和绘图非常有用。 R是一个免费的*软件,它有UNIX、LINUX、MacOS和WINDOWS版本,都是可以免费下载和使用的。在R主页那儿可以下载到R的安装程序、各种外挂程序和文档。在R的安装程序中只包含了8个基础模块,其他外在模块可以通过CRAN获得。 二、R语言 R是用于统计分析、绘图的语言和操作环境。R是属于GNU系统的一个*、免费、源代码开放的软件,它是一个用于统计计算和统计制图的优秀工具。 R作为一种统计分析软件,是集统计分析与图形显示于一体的。它可以运行于UNIX,Windows和Macintosh的操作系统上,而且嵌入了一个非常方便实用的帮助系统,相比于其他统计分析软件,R还有以下特点: 1.R是*软件。这意味着它是完全免费,开放源代码的。可以在它的网站及其镜像中下载任何有关的安装程序、源代码、程序包及其源代码、文档资料。标准的安装文件身自身就带有许多模块和内嵌统计函数,安装好后可以直接实现许多常用的统计功能。[2] 2.R是一种可编程的语言。作为一个开放的统计编程环境,语法通俗易懂,很容易学会和掌握语言的语法。而且学会之后,我们可以编制自己的函数来扩展现有的语言。这也就是为什么它的更新速度比一般统计软件,如,SPSS,SAS等快得多。大多数最新的统计方法和技术都可以在R中直接得到。[2] 3. 所有R的函数和数据集是保存在程序包里面的。只有当一个包被载入时,它的内容才可以被访问。一些常用、基本的程序包已经被收入了标准安装文件中,随着新的统计分析方法的出现,标准安装文件中所包含的程序包也随着版本的更新而不断变化。在另外版安装文件中,已经包含的程序包有:base一R的基础模块、mle一极大似然估计模块、ts一时间序列分析模块、mva一多元统计分析模块、survival一生存分析模块等等.[2] 4.R具有很强的互动性。除了图形输出是在另外的窗口处,它的输入输出窗口都是在同一个窗口进行的,输入语法中如果出现错误会马上在窗口口中得到提示,对以前输入过的命令有记忆功能,可以随时再现、编辑修改以满足用户的需要。输出的图形可以直接保存为JPG,BMP,PNG等图片格式,还可以直接保存为PDF文件。另外,和其他编程语言和数据库之间有很好的接口。[2] 5.如果加入R的帮助邮件列表一,每天都可能会收到几十份关于R的邮件资讯。可以和全球一流的统计计算方面的专家讨论各种问题,可以说是全世界最大、最前沿的统计学家思维的聚集地.[2] R是基于S语言的一个GNU项目,所以也可以当作S语言的一种实现,通常用S语言编写的代码都可以不作修改的在R环境下运行。 R的语法是来自Scheme。R的使用与S-PLUS有很多类似之处,这两种语言有一定的兼容性。S-PLUS的使用手册,只要稍加修改就可作为R的使用手册。所以有人说:R,是S-PLUS的一个“克隆”。 但是请不要忘了:R是免费的(R is free)。R语言源代码托管在github,具体地址可以看参考资料。[3] 。 R语言的下载可以通过CRAN的镜像来查找。 R语言有域名为.cn的下载地址,有六个,其中两个由Datagurn,由 中国科学技术大学提供的。R语言Windows版,其中由两个下载地点是Datagurn和 USTC提供的。 三、stata Stata 是一套提供其使用者数据分析、数据管理以及绘制专业图表的完整及整合性统计软件。它提供许许多多功能,包含线性混合模型、均衡重复反复及多项式普罗比模式。用Stata绘制的统计图形相当精美。 新版本的STATA采用最具亲和力的窗口接口,使用者自行建立程序时,软件能提供具有直接命令式的语法。Stata提供完整的使用手册,包含统计样本建立、解释、模型与语法、文献等超过一万余页的出版品。 除此之外,Stata软件可以透过网络实时更新每天的最新功能,更可以得知世界各地的使用者对于STATA公司提出的问题与解决之道。使用者也可以透过Stata. Journal获得许许多多的相关讯息以及书籍介绍等。另外一个获取庞大资源的管道就是Statalist,它是一个独立的listserver,每月交替提供使用者超过1000个讯息以及50个程序。 四、PYTHON
-
windows下进程间通信的(13种方法)-摘 要 本文讨论了进程间通信与应用程序间通信的含义及相应的实现技术,并对这些技术的原理、特性等进行了深入的分析和比较。 ---- 关键词 信号 管道 消息队列 共享存储段 信号灯 远程过程调用 Socket套接字 MQSeries 1 引言 ---- 进程间通信的主要目的是实现同一计算机系统内部的相互协作的进程之间的数据共享与信息交换,由于这些进程处于同一软件和硬件环境下,利用操作系统提供的的编程接口,用户可以方便地在程序中实现这种通信;应用程序间通信的主要目的是实现不同计算机系统中的相互协作的应用程序之间的数据共享与信息交换,由于应用程序分别运行在不同计算机系统中,它们之间要通过网络之间的协议才能实现数据共享与信息交换。进程间通信和应用程序间通信及相应的实现技术有许多相同之处,也各有自己的特色。即使是同一类型的通信也有多种的实现方法,以适应不同情况的需要。 ---- 为了充分认识和掌握这两种通信及相应的实现技术,本文将就以下几个方面对这两种通信进行深入的讨论:问题的由来、解决问题的策略和方法、每种方法的工作原理和实现、每种实现方法的特点和适用的范围等。 2 进程间的通信及其实现技术 ---- 用户提交给计算机的任务最终都是通过一个个的进程来完成的。在一组并发进程中的任何两个进程之间,如果都不存在公共变量,则称该组进程为不相交的。在不相交的进程组中,每个进程都独立于其它进程,它的运行环境与顺序程序一样,而且它的运行环境也不为别的进程所改变。运行的结果是确定的,不会发生与时间相关的错误。 ---- 但是,在实际中,并发进程的各个进程之间并不是完全互相独立的,它们之间往往存在着相互制约的关系。进程之间的相互制约关系表现为两种方式: ---- (1) 间接相互制约:共享CPU ---- (2) 直接相互制约:竞争和协作 ---- 竞争——进程对共享资源的竞争。为保证进程互斥地访问共享资源,各进程必须互斥地进入各自的临界段。 ---- 协作——进程之间交换数据。为完成一个共同任务而同时运行的一组进程称为同组进程,它们之间必须交换数据,以达到协作完成任务的目的,交换数据可以通知对方可以做某事或者委托对方做某事。 ---- 共享CPU问题由操作系统的进程调度来实现,进程间的竞争和协作由进程间的通信来完成。进程间的通信一般由操作系统提供编程接口,由程序员在程序中实现。UNIX在这个方面可以说最具特色,它提供了一整套进程间的数据共享与信息交换的处理方法——进程通信机制(IPC)。因此,我们就以UNIX为例来分析进程间通信的各种实现技术。 ---- 在UNIX中,文件(File)、信号(Signal)、无名管道(Unnamed Pipes)、有名管道(FIFOs)是传统IPC功能;新的IPC功能包括消息队列(Message queues)、共享存储段(Shared memory segment)和信号灯(Semapores)。 ---- (1) 信号 ---- 信号机制是UNIX为进程中断处理而设置的。它只是一组预定义的值,因此不能用于信息交换,仅用于进程中断控制。例如在发生浮点错、非法内存访问、执行无效指令、某些按键(如ctrl-c、del等)等都会产生一个信号,操作系统就会调用有关的系统调用或用户定义的处理过程来处理。 ---- 信号处理的系统调用是signal,调用形式是: ---- signal(signalno,action) ---- 其中,signalno是规定信号编号的值,action指明当特定的信号发生时所执行的动作。 ---- (2) 无名管道和有名管道 ---- 无名管道实际上是内存中的一个临时存储区,它由系统安全控制,并且独立于创建它的进程的内存区。管道对数据采用先进先出方式管理,并严格按顺序操作,例如不能对管道进行搜索,管道中的信息只能读一次。 ---- 无名管道只能用于两个相互协作的进程之间的通信,并且访问无名管道的进程必须有共同的祖先。 ---- 系统提供了许多标准管道库函数,如: pipe——打开一个可以读写的管道; close——关闭相应的管道; read——从管道中读取字符; write——向管道中写入字符; ---- 有名管道的操作和无名管道类似,不同的地方在于使用有名管道的进程不需要具有共同的祖先,其它进程,只要知道该管道的名字,就可以访问它。管道非常适合进程之间快速交换信息。 ---- (3) 消息队列(MQ) ---- 消息队列是内存中独立于生成它的进程的一段存储区,一旦创建消息队列,任何进程,只要具有正确的的访问权限,都可以访问消息队列,消息队列非常适合于在进程间交换短信息。 ---- 消息队列的每条消息由类型编号来分类,这样接收进程可以选择读取特定的消息类型——这一点与管道不同。消息队列在创建后将一直存在,直到使用msgctl系统调用或iqcrm -q命令删除它为止。 ---- 系统提供了许多有关创建、使用和管理消息队列的系统调用,如: ---- int msgget(key,flag)——创建一个具有flag权限的MQ及其相应的结构,并返回一个唯一的正整数msqid(MQ的标识符); ---- int msgsnd(msqid,msgp,msgsz,msgtyp,flag)——向队列中发送信息; ---- int msgrcv(msqid,cmd,buf)——从队列中接收信息; ---- int msgctl(msqid,cmd,buf)——对MQ的控制操作; ---- (4) 共享存储段(SM) ---- 共享存储段是主存的一部分,它由一个或多个独立的进程共享。各进程的数据段与共享存储段相关联,对每个进程来说,共享存储段有不同的虚拟地址。系统提供的有关SM的系统调用有: ---- int shmget(key,size,flag)——创建大小为size的SM段,其相应的数据结构名为key,并返回共享内存区的标识符shmid; ---- char shmat(shmid,address,flag)——将当前进程数据段的地址赋给shmget所返回的名为shmid的SM段; ---- int shmdr(address)——从进程地址空间删除SM段; ---- int shmctl (shmid,cmd,buf)——对SM的控制操作; ---- SM的大小只受主存限制,SM段的访问及进程间的信息交换可以通过同步读写来完成。同步通常由信号灯来实现。SM非常适合进程之间大量数据的共享。 ---- (5) 信号灯 ---- 在UNIX中,信号灯是一组进程共享的数据结构,当几个进程竞争同一资源时(文件、共享内存或消息队列等),它们的操作便由信号灯来同步,以防止互相干扰。 ---- 信号灯保证了某一时刻只有一个进程访问某一临界资源,所有请求该资源的其它进程都将被挂起,一旦该资源得到释放,系统才允许其它进程访问该资源。信号灯通常配对使用,以便实现资源的加锁和解锁。 ---- 进程间通信的实现技术的特点是:操作系统提供实现机制和编程接口,由用户在程序中实现,保证进程间可以进行快速的信息交换和大量数据的共享。但是,上述方式主要适合在同一台计算机系统内部的进程之间的通信。 3 应用程序间的通信及其实现技术 ---- 同进程之间的相互制约一样,不同的应用程序之间也存在竞争和协作的关系。UNIX操作系统也提供一些可用于应用程序之间实现数据共享与信息交换的编程接口,程序员可以通过自己编程来实现。如远程过程调用和基于TCP/IP协议的套接字(Socket)编程。但是,相对普通程序员来说,它们涉及的技术比较深,编程也比较复杂,实现起来困难较大。 ---- 于是,一种新的技术应运而生——通过将有关通信的细节完全掩盖在某个独立软件内部,即底层的通讯工作和相应的维护管理工作由该软件内部来实现,用户只需要将通信任务提交给该软件去完成,而不必理会它的具体工作过程——这就是所谓的中间件技术。 ---- 我们在这里分别讨论这三种常用的应用程序间通信的实现技术——远程过程调用、会话编程技术和MQSeries消息队列技术。其中远程过程调用和会话编程属于比较低级的方式,程序员参与的程度较深,而MQSeries消息队列则属于比较高级的方式,即中间件方式,程序员参与的程度较浅。 ---- 4.1 远程过程调用(RPC)