我用的是d5 TClientSocket和TServerSocket的非阻塞方式,接收用OnRead和OnClientRead事件处理,在事件中先调用Socket.ReceiveBuf接收到的包头,读取包长度,再调用Socket.ReceiveBuf接收数据,
我的问题是,在发送和接收文件时,会不定时的出现异常,这异常会把程序搞死,我不知道这样做是否安全,如不安全有什么办法解决,大家有没有出现过这样的问题,请高手指教...

解决方案 »

  1.   

    说说看
    先说阻塞方式, send&recv 异常说明了几种可能, 网络断了, 系统缓冲资源不够, 不管是哪种都应直接关socket非阻塞方式的话 SendBuf 会立即返回, 接下来的事由系统去干了, 不过这时如果在 SendBuf 没完成前又调用 SendBuf 就会异常, 对应的可能性就多点, 也不好说应不应关闭 socket, 但在 send & recv 前判断一下 socket 状态的话就可以像阻塞一样的处理了, 至少, 我是这么作的不记得 ServerSocket&ClientSocket 有类下面这样函数, 贴出来参考, 
    function Select(ReadReady, WriteReady, ExceptFlag: PBoolean; TimeOut: Integer = -1): Boolean;send 比方
    var
      WriteReady: Boolean;
    begin
      Select(nil, WriteReady, nil, 100); // 看看是否写是空闲的, 这个也可以作阻塞用, 最后一个 timeout 就是阻塞时间
      if not WriteReady then
        // socket is busying
      else send...
    end;select 函数体, 其中用到的 FHandle 是 socket.Handle
    function Select(ReadReady, WriteReady, ExceptFlag: PBoolean; TimeOut: Integer = -1): Boolean;
    var
      ReadFds: TFDset;
      ReadFdsptr: PFDset;
      WriteFds: TFDset;
      WriteFdsptr: PFDset;
      ExceptFds: TFDset;
      ExceptFdsptr: PFDset;
      tv: timeval;
      Timeptr: PTimeval;
    begin
      if FHandle = INVALID_SOCKET then
      begin
        result := false;
        Exit;
      end;  if Assigned(ReadReady) then
      begin
        ReadFdsptr := @ReadFds;
          FD_ZERO(ReadFds);
          FD_SET(FHandle, ReadFds);
      end
      else ReadFdsptr := nil;  if Assigned(WriteReady) then
      begin
        WriteFdsptr := @WriteFds;
        FD_ZERO(WriteFds);
        FD_SET(FHandle, WriteFds);
      end
      else WriteFdsptr := nil;  if Assigned(ExceptFlag) then
      begin
        ExceptFdsptr := @ExceptFds;
        FD_ZERO(ExceptFds);
        FD_SET(FHandle, ExceptFds);
      end
      else ExceptFdsptr := nil;  if TimeOut >= 0 then
      begin
        tv.tv_sec := TimeOut div 1000;
        tv.tv_usec :=  1000 * (TimeOut mod 1000);
        Timeptr := @tv;
      end
      else Timeptr := nil;  try
      {$IFDEF MSWINDOWS}
        result := CheckError(WinSock.select(FHandle, ReadFdsptr,
          WriteFdsptr, ExceptFdsptr, Timeptr), 'select') > 0;
      {$ENDIF}
      {$IFDEF LINUX}
        result := CheckError(Libc.select(FHandle, ReadFdsptr, WriteFdsptr,
          ExceptFdsptr, Timeptr), 'select') > 0;
      {$ENDIF}
      except
        result := false;
      end;  if Assigned(ReadReady) then
        ReadReady^ := FD_ISSET(FHandle, ReadFds);
      if Assigned(WriteReady) then
        WriteReady^ := FD_ISSET(FHandle, WriteFds);
      if Assigned(ExceptFlag) then
        ExceptFlag^ := FD_ISSET(FHandle, ExceptFds);
    end;
      

  2.   

    TServerSocket阻塞模式下的Chat Demo 源代码
    ftp://61.152.210.98:20/ThreadBlocking.rar  
      

  3.   

    阻塞与不阻塞都有其技术的特点,非阻塞容易丢数据,并容易造成程序错误,ServerSocket&ClientSocket 就是波兰公司希望丢弃的组件,但又怕赶走大批delphi程序员,
    所以在7.0版本以后,其默认是没有的,需手动添加其包,同时该组件只适用于windows,并不支持其他操作系统,所以,建议用indy的Socket组件。如果你掌握了indy的socket,那么你将对通讯原理开发将会了解的更加透彻。
      

  4.   

    ServerSocket&ClientSocket 缺点是封装得不如INDY控件那样彻底和功能完备,也缺少跨平台能力而已,本身在稳定上没无什么问题.用它写程序较易出现使用上的错误.
    楼主使用非阻塞方式传输是可以的.
    问题全出在具体编码细节上,估计至少这几点没有处理好,这也是很多程序员都容易犯的错误:1,非阻塞SOCKET异常处理,
       ONERROR事件一定要处理好的.
    2,SOCKET数据'流'读写解析
       TCLIENTSOCKET/TSERVERSOCKET没提供数据内容同步的封装(INDY提供得有),这需要自己处理好,需自己根据读到的内容拼接分解.
    3,非阻塞SOCKET发送与接收
       非阻塞SOCKET发送接收与阻塞SOCKET有区别,发送是进本地队列,失败需延时重发.
    4,有可能自定义的应用协议不妥