0

接続をオンにするとO_NONBLOCK、lenが戻り0、errnoが戻りますEIO。lenがで-1あり、errnoがであると期待しています EAGAIN。私が得ているものに基づいて、最初の接続に問題があると推測できます。私が理解していないのは、なぜ私がそれを手に入れているのかということです。オンにした場所をコメントアウトしてO_NONBLOCKも、この問題はまったく発生しません。オンにすることに関して何かが足りませO_NONBLCOKんか?

マイコード(MAIN())

long len;

//Var for O_NONBLOCKING
int flags;

printf("R thread - starting\n");

MainTcpipIndex = TcpipIndex = 0;
while ( fMainShutdown == FALSE )
  {

  s_MuxWait(5000, "", &hevTcpipBuffAvail[MainTcpipIndex], 0);
  if ( hevTcpipBuffAvail[MainTcpipIndex] == 0)
     continue;

  len = s_recv( lSocket, TcpipRecord[MainTcpipIndex].TcpipBuffer,
              sizeof(TcpipRecord[MainTcpipIndex].TcpipBuffer));

    //initialize flags var      
  flags = fcntl(lSocket, F_GETFL, 0);

  //turns on O_NONBLOCKING
  fcntl(lSocket, F_SETFL, flags | O_NONBLOCK);

  if (len == -1  ||  len == 0 && errno != EAGAIN)  //0 = connection broken by host
     {
         ReceiveError = errno;
         hevReceiveError = 1;
         printf("R_main - set hevReceiveError ON\n");
         pthread_exit(NULL);
     }
 //catches O_NONBLOCK
 if (len == -1 && errno == EAGAIN)
     {
         LogMessage(&LogStruct, INFO, LOGQUEUE + LOGSCREEN, "Caught the
                     O_NONBLOCKING\n");
         len = 0;
         continue;
     }

  // Record Length
  TcpipRecord[MainTcpipIndex].ulTcpipBufLen = len;

  // Tell T Thread we have a message
  hevTcpipBuffUsed[MainTcpipIndex] = 1;
  hevTcpipBuffAvail[MainTcpipIndex] = 0;

  // Maintain Index
  if ( ++MainTcpipIndex >= MAX_TCPIP_BUFFS )
     MainTcpipIndex = 0;

  }//end while

編集

初めてこれを明確にしなかったかもしれませんが、errnoとlenがs_recv 私の問題に関係していることを理解しています。O_NONBLOCKをオンにすると、望ましくない結果が得られるということです。s_recvのerrnoはEIOで、lenは0です。オフO_NONBLOCKにすると、すべての問題が解決します。lenは1以上であり、errnoをチェックする必要はありません。

以下は、私が期待するシナリオの例です。

最初の悪いシナリオs_recvでは、Lenが0または-1であり、errnoはEAGAINではなく、接続がリセットされます。

2番目の悪いsceanrios_recvのLenは-1で、errnoはEAGAINです。これは、マニュアルページに基づいてO_NONBLOCKがオンになっている場合に想定されるシナリオです。

良いsceanrios_recvのlenは1以上であり、errnoをチェックする必要はありません。

4

2 に答える 2

1

への変更は、次の読み取りO_NONBLOCKの前には関係ありません。

したがって、電話をかける前に確認する必要lenがありerrno ますfcntlfcntlもちろん、戻り値も失敗する可能性があるため、戻り値を確認する必要があります。

要約すると、への変更len == 0errno == EIOは何の関係もありませんがO_NONBLOCKs_recv以前とは関係ありません。

さらに、

if (len == -1 || len == 0 && errno != EAGAIN)

と同じです

if (len == -1 || (len == 0 && errno != EAGAIN) )

戻り値が、でない -1場合、errnoは無視する必要があるため、これは意味がありません。戻り値が0の場合、ピアは接続を閉じています。

更新

シンプルなエコークライアントを構築しました

fd = socket(AF_INET, SOCK_STREAM, 0);
if (fd == -1)
    error("socket");

he = gethostbyname("localhost");
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = ((struct in_addr*)he->h_addr)->s_addr;
addr.sin_port = htons(7); /* echo */
if (connect(fd, (struct sockaddr*) &addr, sizeof(addr)) == -1)
    error("connect");

while (fgets(buf, sizeof(buf), stdin)) {
    n = strlen(buf);
    printf("fgets=%d, %s", n, buf);
    if (send(fd, buf, n, 0) == -1)
        error("send");

    n = recv(fd, buf, sizeof(buf), 0);
    if (n == -1)
        error("recv");

    printf("recv=%d, %s", n, buf);

    flags = fcntl(fd, F_GETFL, 0);
    printf("flags=%d\n", flags);
    if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1)
        error("fcntl");
}

設定後O_NONBLOCK

errno = 11
recv:リソースが一時的に利用できません

fcntl(O_NONBLOCK)ループの前に移動すると、すべてが正常に機能します。

したがって、ソケットの読み取りまたは書き込み後にノンブロッキングをいじるのはお勧めできません。

于 2013-02-11T22:19:45.293 に答える
0

問題は次の行です。

if (len == -1  ||  len == 0 && errno != EAGAIN)

これは同等です

if (len == -1  ||  (len == 0 && errno != EAGAIN))

したがって、使用可能なデータがない場合(len == -1)はチェックせずerrno、無条件にエラーにフラグを立てて終了します。さらに、EOF(len == 0)がある場合、errnoは設定されないため、これをチェックすると、以前の呼び出しで発生したものがすべて取得されます。

あなたはおそらく欲しい:

if ((len < 0 && errnor != EGAIN) || len == 0) {
    ReceiveError = (len < 0) ? errno : 0;

また、fcntlからエラーが発生した場合、errnoが破壊されます(ただし、これは発生していないと思います。GETFL/ SETFLで発生する可能性のある唯一の失敗はEBADFです)。おそらく、recv呼び出しの前にfcntl呼び出しを実行する必要があります。 。

于 2013-02-12T18:17:50.817 に答える