草庐IT

delphi - HawkNL 库,nlClose 不关闭套接字

coder 2023-09-19 原文

谁能帮我解决以下问题。

我有客户端和服务器 tcp 可靠连接。

客户端连接到服务器,服务器接收数据包。然后客户端关闭套接字(nlclose) 并且在服务器中 nlRead 仍然返回 0(这意味着仍然存在事件连接) 它没有通知我客户端关闭了套接字,为什么?

只有客户端的 nlshutdown 会强制服务器停止监听套接字,这是为什么?

你们中有人使用过 hawkNL 吗?

谢谢!

代码在 Windows XP Sp3 机器上运行。

编辑:

客户端代码:

procedure Client;
const
  TCP_PORT = 9800;
  READ_SIZE_CHUNK = 1048576;//1mb
Type
  TChunk = record
    data: pointer;
    datasize: NLint;
  end;
var
  LRslt: NLboolean;
  LClientSocket: NLsocket;
  LChunkData: TChunk;
  LNumRead: Integer;
  LReadError: NLenum;
  LAddress: NLaddress;
  LWrittenBytes: Integer;
  LBuffer: array [0..10] of byte;

  procedure PopUpMessage(Rslt: NLboolean);
  var
    LError: NLenum;
    LStrRslt: String;
  begin
    if Rslt
      then exit;
    LError := nlGetError();
    if LError = NL_SYSTEM_ERROR
      then LStrRslt := nlGetSystemErrorStr(nlGetSystemError())
      else LStrRslt := nlGetErrorStr(error);
    showmessage (LStrRslt);
    abort;
  end;

begin
  LReadError := 0;
  LRslt := nlInit();PopUpMessage(LRslt);
  LRslt := nlSelectNetwork(NL_IP);PopUpMessage(LRslt);

  LClientSocket := nlOpen(0, NL_TCP);
  if (LClientSocket = NL_INVALID)
    then PopUpMessage(false);

  nlGetLocalAddr(LClientSocket, LAddress);

  //Ustawienie adresu drukarki
  LRslt := nlStringToAddr(PChar('127.0.0.1:'+Inttostr(TCP_PORT)), LAddress); PopUpMessage(Lrslt);
  //Połączenie z drukarką
  LRslt := nlConnect(LClientSocket, LAddress); PopUpMessage(Lrslt);

  LWrittenBytes := nlWrite(LClientSocket, LBuffer, 5);

  if (LWrittenBytes = NL_INVALID)
    then PopUpMessage(false);

  //nlClose(LClientSocket);
end;

服务器代码:

procedure Serwer;
const
  TCP_PORT = 9800;
  READ_SIZE_CHUNK = 1048576;//1mb
Type
  TChunk = record
    data: pointer;
    datasize: NLint;
  end;
var
  LRslt: NLboolean;
  LServerSock, LNewSock: NLsocket;
  LChunkData: TChunk;
  LNumRead: Integer;
  LReadError: NLenum;

  procedure PopUpMessage(Rslt: NLboolean);
  var
    LError: NLenum;
    LStrRslt: String;
  begin
    if Rslt
      then exit;
    LError := nlGetError();
    if LError = NL_SYSTEM_ERROR
      then LStrRslt := nlGetSystemErrorStr(nlGetSystemError())
      else LStrRslt := nlGetErrorStr(error);
    showmessage (LStrRslt);
    abort;
  end;

begin
  LReadError := 0;
  LRslt := nlInit();PopUpMessage(LRslt);
  LRslt := nlSelectNetwork(NL_IP);PopUpMessage(LRslt);

  LServerSock := nlOpen(TCP_PORT, NL_RELIABLE);
  if (LServerSock = NL_INVALID)
    then PopUpMessage(false);

  if not nlListen(LServerSock)
    then PopUpMessage(false);

  repeat
    LNewSock := nlAcceptConnection(LServerSock);
    if LNewSock <> NL_INVALID then
    begin
      GetMem (LChunkData.data, READ_SIZE_CHUNK);
      repeat
        LNumRead := nlRead(LNewSock, LChunkData.data^, READ_SIZE_CHUNK);
        //Here I am receiving 0 bytes reads from LNumRead....
        if LNumRead > 0 then
        begin
          beep;
          //I am receiving stream, do nothing with that
        end else
        begin
          if LNumRead = NL_INVALID then
          begin
            LReadError := nlGetError();
            if (LReadError = NL_INVALID_SOCKET) or
               (LReadError = NL_MESSAGE_END)
              then PopUpMessage(false);
          end;
        end;
      until LReadError <> 0;//(LReadError = NL_NO_PENDING)
      beep;//Here it should exit if all would work ok.
    end else
    begin
      if nlGetError() = NL_SYSTEM_ERROR
        then PopUpMessage(false);
    end;
  until 1=2;
  beep;
end;

最佳答案

您确定自己的 API 吗? (documentation I found 对于 0 返回值或套接字的有序关闭非常安静。)

标的recv()read()调用 TCP 堆栈返回 0当对等方关闭连接时。来自recv(2)我的 Linux 系统上的联机帮助页:

RETURN VALUE
   These calls return the number of bytes received, or -1 if an
   error occurred.  The return value will be 0 when the peer has
   performed an orderly shutdown.

请注意,可能有几个字节或 up to a gigabyte of data或更多数据留在套接字中,即使在对等方关闭连接后仍可读取。您的服务器应用程序可能无法获得 FIN客户端完成后很长的套接字关闭通知时间,具体取决于管道的延迟和带宽、应用程序的 IO 策略以及 TCP/IP 堆栈可用于缓冲套接字数据的内存。

下一个 recv()调用(在它返回一次后 0 )将返回一个错误。我假设套接字的 HawkNL 接口(interface)会遵循此行为。

此外, nlShutdown 看起来与 shutdown() 的通常 TCP 含义非常不同| ,它只是通知 TCP 堆栈应用程序已在单个特定套接字上完成读取、写入或读取和写入。在您的客户端中使用它可能有点严苛。

编辑

我稍微查看了 HawkNL 源代码,现在我对您看到的行为更加困惑。

NL_EXP NLint NL_APIENTRY nlRead(NLsocket socket, NLvoid *buffer, NLint nbytes)
{
    if(driver)
    {
        if(nlIsValidSocket(socket) == NL_TRUE)
        {
            if(buffer == NULL)
            {
                nlSetError(NL_NULL_POINTER);
            }
            else
            {
                NLint received;

                if(nlLockSocket(socket, NL_READ) == NL_FALSE)
                {
                    return NL_INVALID;
                }
                received = driver->Read(socket, buffer, nbytes); /* AAA */

                if(received > 0)
                {
                    nlUpdateSocketInStats(socket, received, 1);
                    nlUpdateInStats(received, 1);
                }
                nlUnlockSocket(socket, NL_READ);
                return received;
            }
        }
        else
        {
            nlSetError(NL_INVALID_SOCKET);
        }
        return NL_INVALID;
    }
    nlSetError(NL_NO_NETWORK);
    return NL_INVALID;
}

我标记的点/* AAA */调用每个网络堆栈 Read函数,并简单地返回从 Read 返回的任何值功能:

NLint sock_Read(NLsocket socket, NLvoid *buffer, NLint nbytes)
{
    nl_socket_t *sock = nlSockets[socket];
    NLint       count;

    if(nbytes < 0)
    {
        return 0;
    }
    if(sock->type == NL_RELIABLE || sock->type == NL_RELIABLE_PACKETS) /* TCP */
    {

        /* I've removed all the code for pending non-blocking connections */

        /* check for reliable packets */
        if(sock->type == NL_RELIABLE_PACKETS)
        {
            return sock_ReadPacket(socket, buffer, nbytes, NL_FALSE);
        }
        count = recv((SOCKET)sock->realsocket, (char *)buffer, nbytes, 0); /* BBB */
        if(count == 0)
        {
            /* end of message */
            nlSetError(NL_MESSAGE_END);
            return NL_INVALID;
        }
    }
    /* I removed UDP handling */

标有/* BBB */的部分是对系统的调用recv()功能。当系统recv()返回 0 (以指示对等方已正常关闭套接字),它会适本地设置错误状态并返回错误。

根据您对问题的描述和这个来源,我真的很惊讶。 0返回看起来只能通过第一个 if sock_Read() 的状况功能:请求读取小于0的数据字节通过NL_RELIABLE_PACKETS当您还没有收到所有更高级别的数据数据包时连接。两者似乎都不可信,所以我真的很想看看您的程序。

关于delphi - HawkNL 库,nlClose 不关闭套接字,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6513030/

有关delphi - HawkNL 库,nlClose 不关闭套接字的更多相关文章

  1. ruby - 如何关闭 ruby​​ gem "Spreadsheet?"中的文件 - 2

    下面的代码在我第一次运行它时就可以正常工作:require'rubygems'require'spreadsheet'book=Spreadsheet.open'/Users/me/myruby/Mywks.xls'sheet=book.worksheet0row=sheet.row(1)putsrow[1]book.write'/Users/me/myruby/Mywks.xls'当我再次运行它时,我会收到更多消息,例如:/Library/Ruby/Gems/1.8/gems/spreadsheet-0.6.5.9/lib/spreadsheet/excel/reader.rb:11

  2. 网络编程套接字 - 2

    网络编程套接字网络编程基础知识理解源`IP`地址和目的`IP`地址理解源MAC地址和目的MAC地址认识端口号理解端口号和进程ID理解源端口号和目的端口号认识`TCP`协议认识`UDP`协议网络字节序socket编程接口`sockaddr``UDP`网络程序服务器端代码逻辑:需要用到的接口服务器端代码`udp`客户端代码逻辑`udp`客户端代码`TCP`网络程序服务器代码逻辑多个版本服务器单进程版本多进程版本多线程版本线程池版本服务器端代码客户端代码逻辑客户端代码TCP协议通讯流程TCP协议的客户端/服务器程序流程三次握手(建立连接)数据传输四次挥手(断开连接)TCP和UDP对比网络编程基础知识

  3. ruby - 是否可以在不实际发送或读取数据的情况下查明 ruby​​ 套接字是否处于 ESTABLISHED 或 CLOSE_WAIT 状态? - 2

    s=Socket.new(Socket::AF_INET,Socket::SOCK_STREAM,0)s.connect(Socket.pack_sockaddr_in('port','hostname'))ssl=OpenSSL::SSL::SSLSocket.new(s,sslcert)ssl.connect从这里开始,如果ssl连接和底层套接字仍然是ESTABLISHED,或者它是否在默认值7200之后进入CLOSE_WAIT,我想检查一个线程几秒钟甚至更糟的是在实际上不需要.write()或.read()的情况下关闭。是用select()、IO.select()还是其他方法完成

  4. ruby-on-rails - Ruby 的 'open_uri' 是否在读取或失败后可靠地关闭套接字? - 2

    一段时间以来,我一直在使用open_uri下拉ftp路径作为数据源,但突然发现我几乎连续不断地收到“530抱歉,允许的最大客户端数(95)已经连接。”我不确定我的代码是否有问题,或者是否是其他人在访问服务器,不幸的是,我无法真正确定谁有问题。本质上,我正在读取FTPURI:defself.read_uri(uri)beginuri=open(uri).readuri=="Error"?nil:urirescueOpenURI::HTTPErrornilendend我猜我需要在这里添加一些额外的错误处理代码...我想确保我采取一切预防措施来关闭所有连接,这样我的连接就不是问题所在,但是我

  5. ruby - Faye WebSocket,关闭处理程序被触发后重新连接到套接字 - 2

    我有一个super简单的脚本,它几乎包含了FayeWebSocketGitHub页面上用于处理关闭连接的内容:ws=Faye::WebSocket::Client.new(url,nil,:headers=>headers)ws.on:opendo|event|p[:open]#sendpingcommand#sendtestcommand#ws.send({command:'test'}.to_json)endws.on:messagedo|event|#hereistheentrypointfordatacomingfromtheserver.pJSON.parse(event.d

  6. ruby - 如何在 watir 测试套件结束时关闭浏览器? - 2

    使用ruby​​的watir测试网络应用程序时,浏览器最后会保持打开状态。网上的一些建议是,要进行真正的单元测试,您应该在每次测试时(在拆卸调用中)打开和关闭浏览器,但这很慢而且毫无意义。或者他们做这样的事情:defself.suites=superdefs.afterClass#Closebrowserenddefs.run(*args)superafterClassendsend但这会导致摘要输出不再显示(诸如“100次测试、100次断言、0次失败、0次错误”之类的内容仍应显示)。我怎样才能让ruby​​或watir在我的测试结束时关闭浏览器? 最佳答案

  7. ruby-on-rails - 如何在一段时间后关闭 Rails 闪现消息? - 2

    我想设置秒数aflash在自动关闭之前向用户显示通知。 最佳答案 您可以在页面上使用一些简单的JavaScript(在此示例中使用jQuery):$('document').ready(function(){setTimeout(function(){$('#flash').slideUp();},3000);});假设保存您的flash消息的HTML元素的id是#flash,这将向上滑动并在3000毫秒(3秒)后将其隐藏。 关于ruby-on-rails-如何在一段时间后关闭Rails

  8. ruby - 使用 ruby​​ 进行套接字编程是个好主意吗? - 2

    我选择的语言是Ruby,但因为Twitter,我知道Ruby不能处理很多请求。将它用于套接字开发是个好主意吗?或者我应该像Twitter开发人员那样使用像erlang或haskell或scala这样的函数式语言吗? 最佳答案 我工作的公司使用Ruby作为我们的网站。到目前为止,我们已经处理了超过34,000,000,000次点击。我们每天处理大约10,000,000次点击没有问题。每天的点击量峰值已超过40,000,000次。可扩展性取决于很多因素。例如,与读取相比,我们的数据库执行的写入比例高得不成比例。虽然大多数网站执行大约90

  9. ruby-on-rails - 如何在关闭 cache_classes 的情况下使用来自中间件的域对象? - 2

    在rails开发环境中,cache_classes是关闭的,所以你可以修改app/下的代码,不用重启服务器就可以看到变化。不过,在所有环境中,中间件只会创建一次。所以如果我有这样的中间件:classMyMiddlewaredefinitialize(app)@app=appenddefcall(env)env['model']=MyModel.firstendend我在config/environments/development.rb中执行此操作:config.cache_classes=false#thedefaultfordevelopmentconfig.middleware.

  10. ruby - 重新连接 tcpsocket(或如何检测已关闭的套接字) - 2

    我有一个连接到服务器的ruby​​tcpsocket客户端。在发送数据之前如何检查套接字是否已连接?我是否尝试“拯救”断开连接的tcpsocket,重新连接然后重新发送?如果是这样,有没有人有一个简单的代码示例,因为我不知道从哪里开始:(我很自豪我设法在rails中获得了一个持久连接的客户端tcpsocket。然后服务器决定杀死客户端,一切都崩溃了;)编辑我已经使用此代码解决了一些问题-如果未连接,它将尝试重新连接,但如果服务器已关闭则不会处理这种情况(它将继续重试)。这是正确方法的开始吗?谢谢defself.write(data)begin@@my_connection.write(

随机推荐