当前位置:  编程技术>软件工程/软件设计
本页文章导读:
    ▪高性能大容量SOCKET并发(九):稳定性问题解决      IOCP接收缓存导致的内存错乱 在用IOCP控件写了一个ERP服务器后,服务器会发生运行3天后,出现莫名的内存错误,用FastMM检测,是本没有内存错误的地方,而且内存错误出现的地方也不固定。.........
    ▪Excel2007格式分析和XML解析         在物料清单采购中,用到excel上传文件解析功能,不过使用poi来解析,发现如果某个单元格为空,则使用poi的官网示例则会被忽略,导致某些非必填的单元格为空,而解析出来.........
    ▪第九章 关系映射 组件关联映射       组件是针对同一张表中的字段进行映射,作用是将字段多的一张表分成多个实体类来表示。 如:name与user user表中有first_name及last_name。在实体类中,自定义一个Name类来表示first_name与last_name; N.........

[1]高性能大容量SOCKET并发(九):稳定性问题解决
    来源: 互联网  发布时间: 2013-11-19

IOCP接收缓存导致的内存错乱

在用IOCP控件写了一个ERP服务器后,服务器会发生运行3天后,出现莫名的内存错误,用FastMM检测,是本没有内存错误的地方,而且内存错误出现的地方也不固定。这是一个不可重现的Bug,后续通过打日志把错误范围缩小后发现,每次出现内存错误之前都是由于有链接断开释放,因此就加了日志逐步定位到是TSocketHandle释放引起的,具体原因是:在IOCP中,每个Socket连接需要投递一个接收请求,并给出数据存放内存,原来是销毁TSocketHandle的同时,销毁投递接收请求的缓存,这样有可能对象销毁后,IOCP返回一个异步接收消息,会导致写入到已销毁的接收缓存,造成内存被重写,导致内存错误。

解决办法,是用锁和对象分离相同的机制,把接收缓存和对象分离,在释放对象的时候不释放接收缓存,等待超过30分钟后,重新使用这个锁和接受缓存,这样做即可以解决内存错乱问题,也起到了锁和接收缓存的池化处理。

具体代码处理:

投递请求缓存和对象分开,采用是锁和对象分离相同的机制。

  {* 客户端对象和锁 *}
  TClientSocket = record
    Lock: TCriticalSection;
    SocketHandle: TSocketHandle;
    IocpRecv: TIocpRecord; //投递请求结构体
    IdleDT: TDateTime;
  end;
  PClientSocket = ^TClientSocket;
在释放TSocketHandle的时候,只释放对象,投递请求缓存不释放,和锁一起保留,加入到空闲列表中。
procedure TSocketHandles.Delete(const AIndex: Integer);
var
  ClientSocket: PClientSocket;
begin
  ClientSocket := FList[AIndex];
  ClientSocket.Lock.Enter;
  try
    ClientSocket.SocketHandle.Free;
    ClientSocket.SocketHandle := nil;
  finally
    ClientSocket.Lock.Leave;
  end;
  FList.Delete(AIndex);
  ClientSocket.IdleDT := Now;
  FIdleList.Add(ClientSocket);
end;
在加入对象的时候,检测空闲列表是否有超过30分钟没使用的,如果有则重复利用。
function TSocketHandles.Add(ASocketHandle: TSocketHandle): Integer;
var
  ClientSocket, IdleClientSocket: PClientSocket;
  i: Integer;
begin
  ClientSocket := nil;
  for i := FIdleList.Count - 1 downto 0 do
  begin
    IdleClientSocket := FIdleList.Items[i];
    if Abs(MinutesBetween(Now, IdleClientSocket.IdleDT)) > 30 then
    begin
      ClientSocket := IdleClientSocket;
      FIdleList.Delete(i);
      Break;
    end;
  end;
  if not Assigned(ClientSocket) then
  begin
    New(ClientSocket);
    ClientSocket.Lock := TCriticalSection.Create;
    ClientSocket.IocpRecv.WsaBuf.buf := GetMemory(MAX_IOCPBUFSIZE);
    ClientSocket.IocpRecv.WsaBuf.len := MAX_IOCPBUFSIZE;
  end;
  ClientSocket.SocketHandle := ASocketHandle;
  ClientSocket.IdleDT := Now;
  ASocketHandle.FLock := ClientSocket.Lock;
  ASocketHandle.FIocpRecv := @ClientSocket.IocpRecv;
  Result := FList.Add(ClientSocket);
end;

CheckDisconnectedClient方法加锁及判断是否正在执行

原来检测释放断开连接的方法如下:

procedure TIocpServer.CheckDisconnectedClient;
var
  i: Integer;
begin
  FSocketHandles.Lock;
  try
    for i := FSocketHandles.Count - 1 downto 0 do
    begin
      if not FSocketHandles.Items[i].SocketHandle.Connected then
      begin
        FSocketHandles.Delete(i);
      end;
    end;
  finally
    FSocketHandles.UnLock;
  end;
end;
这个方法存在以下问题:

1、对整个FSocketHandles加锁,FSocketHandles.Delete在释放的时候又加了一次锁,如果Delete加锁等待,则导致整个FSocketHandles被锁住,这时再加连接就会等待,造成IOCP无法接收连接,从而存在问题。

2、如果某个TScoketHandle执行很长时间,它的Connected属性为False,则FSocketHandles.Delete会锁住,造成和1相同的问题。

解决办法:

1、不对整个FSocketHandles加锁,我每次查找一个Connected为False的连接,避免一次加两个锁。

2、TSocketHandle增加一个属性标识是否正在执行中,在检测断开连接的时候如果正在执行中则跳过。

具体代码如下:

procedure TIocpServer.CheckDisconnectedClient;
var
  iCount: Integer;
  ClientSocket: PClientSocket;

  function GetDisconnectSocket: PClientSocket;
  var
    i: Integer;
  begin
    Result := nil;
    FSocketHandles.Lock;
    try
      for i := FSocketHandles.Count - 1 downto 0 do
      begin
        if (not FSocketHandles.Items[i].SocketHandle.Connected)
          and (not FSocketHandles.Items[i].SocketHandle.Executing) then
        begin
          Result := FSocketHandles.Items[i];
          Break;
        end;
      end;
    finally
      FSocketHandles.UnLock;
    end;
  end;
begin
  ClientSocket := GetDisconnectSocket;
  iCount := 0;
  while (ClientSocket <> nil) and (iCount < 1024 * 1024) do
  begin
    ClientSocket.Lock.Enter;
    try
      if Assigned(ClientSocket.SocketHandle) then
        FreeSocketHandle(ClientSocket.SocketHandle);
    finally
      ClientSocket.Lock.Leave;
    end;
    ClientSocket := GetDisconnectSocket;
    Inc(iCount);
  end;
end;
主要是使用GetDisconnectSocket来返回一个已经断开的连接。TSocketHandle.Executing的赋值只需要在下面方法中赋值即可,因为他执行的进入口和返回口。

procedure TSocketHandle.ProcessIOComplete(AIocpRecord: PIocpRecord;
  const ACount: Cardinal);
begin
  FExecuting := True;
  try
    case AIocpRecord.IocpOperate of
      ioNone: Exit;
      ioRead: //收到数据
      begin
        FActiveTime := Now;
        ReceiveData(AIocpRecord.WsaBuf.buf, ACount);
        if FConnected then
          PreRecv; //投递请求
      end;
      ioWrite: //发送数据完成,需要释放AIocpRecord的指针
      begin
        FActiveTime := Now;
        FSendOverlapped.Release(AIocpRecord);
      end;
      ioStream:
      begin
        FActiveTime := Now;
        FSendOverlapped.Release(AIocpRecord);
        WriteStream; //继续发送流
      end;
    end;
  finally
    FExecuting := False;
  end;
end;

解决这两个稳定性问题后,IOCP支持的ERP服务器已经能支持7*24小时运行。一般当服务器出现稳定性问题后,日志就开始发挥作用,但是太多无用的日志不利于定位到问题点,太少的日志又无法定位,一般写日志的原则是在调用顺序关键点上加日志、继承关键点上加日志、数据流输入输出关键点上加日志;这样出现问题后,可以快速把问题定位到一段代码上,能帮助缩短解决问题的周期。如果出现一个不可重现BUG,能控制在3天解决,出现一个内存错乱BUG,能控制在半个月解决,哪你的日志辅助调试就是有效的。

下载地址:http://download.csdn.net/detail/sqldebug_fan/4510076

免责声明:此代码只是为了演示IOCP编程,仅用于学习和研究,切勿用于商业用途。水平有限,错误在所难免,欢迎指正和指导。邮箱地址:fansheng_hx@163.com


作者:SQLDebug_Fan 发表于2013-6-7 22:23:12 原文链接
阅读:17 评论:0 查看评论

    
[2]Excel2007格式分析和XML解析
    来源: 互联网  发布时间: 2013-11-19


 


在物料清单采购中,用到excel上传文件解析功能,不过使用poi来解析,发现如果某个单元格为空,则使用poi的官网示例则会被忽略,导致某些非必填的单元格为空,而解析出来则认为不符合格式。找了半天,也没发现poi正确解析的示例和一些资料,只能自己查查excel的格式,然后再解析了。官网地址示例:http://poi.apache.org/spreadsheet/how-to.html#xssf_sax_api

那么我们就看看excel2007的格式了。

 

1.    excel2007是使用xml格式来存储的,把一个excel文件后缀改为.zip,打开之后就直接可以看到一个excel文件对应的xml格式的文件了。

这里面有几部分



 



 


<!--[if !supportLists]-->1.       1 <!--[endif]-->对于docProps目录下  这里core是文件的创建时间和修改时间,标题,主题和作者,app是文档的其他属性,文档类型,版本,是否只读,是否共享,安全属性等文档属性信息。


 



 Core.xml       <dc:creator></dc:creator>       <cp:lastModifiedBy></cp:lastModifiedBy>       <dcterms:created xsi:type="dcterms:W3CDTF">2006-09-13T11:21:51Z</dcterms:created>       <dcterms:modified xsi:type="dcterms:W3CDTF">2013-06-05T09:28:23Z</dcterms:modified> App.xml        <Application>Microsoft Excel</Application>       <DocSecurity>0</DocSecurity>       <ScaleCrop>false</ScaleCrop>       <Company></Company>       <LinksUpToDate>false</LinksUpToDate>       <SharedDoc>false</SharedDoc>       <HyperlinksChanged>false</HyperlinksChanged>       <AppVersion>12.0000</AppVersion>     ……
 


 2.在xl目录下是文档的具体内容信息

先看workbook.xml

<workbook xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main"       xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">       <fileVersion appName="xl" lastEdited="4" lowestEdited="4"              rupBuild="4507" />       <workbookPr filterPrivacy="1" defaultThemeVersion="124226" />       <bookViews>              <workbookView xWindow="0" yWindow="90" windowWidth="19200"                     windowHeight="11640" />       </bookViews>       <sheets>              <sheet name="Sheet1" sheetId="1" r:id="rId1" />              <sheet name="Sheet2" sheetId="2" r:id="rId2" />              <sheet name="Sheet3" sheetId="3" r:id="rId3" />       </sheets>       <calcPr calcId="125725" /></workbook>
 



workbook.xml文件包含一对<sheets>标签,其中的每个<sheet>元素都代表Excel 2007文件中的一个,工作表的名称就是其name属性的值,这里有三个sheet。

 

xl/_rels/workbook.xml.rels定义每个sheetid对应的sheet内容文件sheet1.xml,共享的单元格内容文件sharedstring.xml,样式文件style.xml是当前单元格的样式字体,颜色等样式的xml配置。

Theme存放的是当前的设置导航栏的默认样式。这两个看看大概也就能明白。

 

关键我们看看下面每个sheet的内容格式,

 

打开一个sheet1.xml看看

       <sheetData>              <row r="1" spans="1:7" ht="33.75" customHeight="1"> row标签是表示每一行的数据,r表示第几行,其他几个都是这几行的样式                     <c r="A1" s="9" t="s">c标签表示每个单元格的内容,这里A1 第一行的第一列,r表示位置,s表示这个单元格的样式,                                                          s=9对应style.xml的的index为9的样式即为这个单元格的样式,t=s表示这个单元格有值,里面的v标签即为值的id,id对应到sharedstring.xm里的id对应的值                            <v>2</v>                     </c>                     <c r="B1" s="10" />  没有t属性,表示这个单元格没有值设置                     <c r="C1" s="10" />                     <c r="D1" s="10" />                     <c r="E1" s="10" />                     <c r="F1" s="10" />              </row>              <row r="2" spans="1:7" ht="27.75" customHeight="1">  第二行                     <c r="A2" s="3" t="s">  第二行第二列                            <v>1</v>                     </c>                     <c r="B2" s="4" t="s">                            <v>5</v>                     </c>                     <c r="C2" s="3" t="s">                            <v>0</v>
 



 我们找到对应的第一行第一列的值索引为2对应到sharedStrings.xml里面的index的值,这里si从0开始,第三个即为index为2的值,刚好跟我们的excel的A1值符合

<sst xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main"    count="71" uniqueCount="13">    <si>           <t>物料编号</t>           <phoneticPr fontId="1" type="noConversion" />    </si>    <si>           <t>序号</t>           <phoneticPr fontId="1" type="noConversion" />    </si>    <si>           <t>注意:请不要修改表中蓝色区域文字;带有*号字段是必填项;每张物料清单最多只能导入20条物料信息</t>           <phoneticPr fontId="1" type="noConversion" />    </si>
 


而A1的s=9对应的样式style.xml我们也看看,找到cellXfs里面的第9个,不过这里又引用fontid字体样式,borderid样式,numfmtId格式等


  <cellXfs count="11">       ......              <xf numFmtId="0" fontId="0" fillId="3" borderId="1" xfId="0"                     applyFill="1" applyBorder="1">                     <alignment vertical="center" />              </xf>              <xf numFmtId="0" fontId="2" fillId="0" borderId="2" xfId="0"                  
    
[3]第九章 关系映射 组件关联映射
    来源: 互联网  发布时间: 2013-11-19

组件是针对同一张表中的字段进行映射,作用是将字段多的一张表分成多个实体类来表示。

如:name与user

user表中有first_name及last_name。在实体类中,自定义一个Name类来表示first_name与last_name;


Name实体类:

package cn.framelife.mvc.entity;

public class Name {
	private String firstName;
	private String lastName;

	public String getFirstName() {
		return firstName;
	}

	public void setFirstName(String firstName) {
		this.firstName = firstName;
	}

	public String getLastName() {
		return lastName;
	}

	public void setLastName(String lastName) {
		this.lastName = lastName;
	}

}


User实体类:

package cn.framelife.mvc.entity;

import java.io.Serializable;

public class User implements Serializable {
	private Integer id;
	private Name name;

	public Integer getId() {
		return id;
	}

	public void setId(Integer id) {
		this.id = id;
	}

	public Name getName() {
		return name;
	}

	public void setName(Name name) {
		this.name = name;
	}
}


User.hbm.xml:

<hibernate-mapping>
    <class name="cn.framelife.hibernate.entity.User" table="user" catalog="hibernate">
        <id name="id" type="java.lang.Integer">
            <column name="id" />
            <generator class="native" />
        </id>
        <component name="name" class="cn.framelife.hibernate.entity.Name">
        	<property name="firstName" column="first_name"></property>
        	<property name="lastName" column="last_name"></property>
        </component>
    </class>
</hibernate-mapping>


增加操作:

tx = session.beginTransaction();
			Name name = new Name();
			name.setFirstName("111");
			name.setLastName("2222");
			
			User user = new User();
			user.setName(name);
			session.save(user);
			
			tx.commit();


作者:p_3er 发表于2013-6-8 10:07:22 原文链接
阅读:0 评论:0 查看评论

    
最新技术文章:
▪主-主数据库系统架构    ▪java.lang.UnsupportedClassVersionError: Bad version number i...    ▪eclipse项目出现红色叉叉解决方案
▪Play!framework 项目部署到Tomcat    ▪dedecms如何做中英文网站?    ▪Spring Batch Framework– introduction chapter(上)
▪第三章 AOP 基于@AspectJ的AOP    ▪基于插件的服务集成方式    ▪Online Coding开发模式 (通过在线配置实现一个表...
▪观察者模式(Observer)    ▪工厂模式 - 程序实现(java)    ▪几种web并行化编程实现
▪机器学习理论与实战(二)决策树    ▪Hibernate(四)——全面解析一对多关联映射    ▪我所理解的设计模式(C++实现)——解释器模...
▪利用规则引擎打造轻量级的面向服务编程模式...    ▪google blink的设计计划: Out-of-Progress iframes    ▪FS SIP呼叫的消息线程和状态机线程
▪XML FREESWITCH APPLICATION 实现    ▪Drupal 实战    ▪Blink: Chromium的新渲染引擎
▪(十四)桥接模式详解(都市异能版)    ▪你不知道的Eclipse用法:使用Allocation tracker跟...    ▪Linux内核-进程
▪你不知道的Eclipse用法:使用Metrics 测量复杂度    ▪IT行业为什么没有进度    ▪Exchange Server 2010/2013三种不同的故障转移
▪你不知道的Eclipse用法:使用Metrics 测量复杂度    ▪IT行业为什么没有进度    ▪Exchange Server 2010/2013三种不同的故障转移 iis7站长之家
▪值班总结(1)——探讨sql语句的执行机制    ▪第二章 IoC Annotation注入    ▪CentOS 6.4下安装Vagrant
▪Java NIO框架Netty1简单发送接受    ▪漫画研发之八:会吃的孩子有奶吃    ▪比较ASP和ASP.NET
▪SPRING中的CONTEXTLOADERLISTENER    ▪在Nginx下对网站进行密码保护    ▪Hibernate从入门到精通(五)一对一单向关联映...
▪.NET领域驱动设计—初尝(三:穿过迷雾走向光...    ▪linux下的块设备驱动(一)    ▪Modem项目工作总结
▪工作流--JBPM简介及开发环境搭建    ▪工作流--JBPM核心服务及表结构    ▪Eclipse:使用JDepend 进行依赖项检查
▪windows下用putty上传文件到远程Linux方法    ▪iBatis和Hibernate的5点区别    ▪基于学习的Indexing算法
▪设计模式11---设计模式之中介者模式(Mediator...    ▪带你走进EJB--JMS编程模型    ▪从抽象谈起(二):观察者模式与回调
▪设计模式09---设计模式之生成器模式(Builder)也...    ▪svn_resin_持续优化中    ▪Bitmap recycle方法与制作Bitmap的内存缓存
▪Hibernate从入门到精通(四)基本映射    ▪设计模式10---设计模式之原型模式(Prototype)    ▪Dreamer 3.0 支持json、xml、文件上传
▪Eclipse:使用PMD预先检测错误    ▪Jspx.net Framework 5.1 发布    ▪从抽象谈起(一):工厂模式与策略模式
▪Eclipse:使用CheckStyle实施编码标准    ▪【论文阅读】《Chain Replication for Supporting High T...    ▪Struts2 Path_路径问题
▪spring 配置文件详解    ▪Struts2第一个工程helloStruts极其基本配置    ▪Python学习入门基础教程(learning Python)--2 Python简...
▪maven springmvc环境配置    ▪基于SCRUM的金融软件开发项目    ▪software quality assurance 常见问题收录
▪Redis集群明细文档    ▪Dreamer 框架 比Struts2 更加灵活    ▪Maven POM入门
▪git 分支篇-----不断更新中    ▪Oracle非主键自增长    ▪php设计模式——UML类图
▪Matlab,Visio等生成的图片的字体嵌入问题解决...    ▪用Darwin和live555实现的直播框架    ▪学习ORM框架—hibernate(二):由hibernate接口谈...
▪(十)装饰器模式详解(与IO不解的情缘)    ▪无锁编程:最简单例子    ▪【虚拟化实战】网络设计之四Teaming
▪OSGi:生命周期层    ▪Javascript/Jquery——简单定时器    ▪java代码 发送GET、POST请求
▪Entity Framework底层操作封装(3)    ▪HttpClient 发送GET、POST请求    ▪使用spring框架,应用启动时,加载数据
▪Linux下Apache网站目录读写权限的设置    ▪单键模式的C++描述    ▪学习ORM框架—hibernate(一):初识hibernate
 


站内导航:


特别声明:169IT网站部分信息来自互联网,如果侵犯您的权利,请及时告知,本站将立即删除!

©2012-2021,,E-mail:www_#163.com(请将#改为@)

浙ICP备11055608号-3