بلدي المتشعب الخادم في ج ++ لا ترسل جميع الملفات مرة أخرى بشكل صحيح

StackOverflow https://stackoverflow.com/questions/1810277

  •  05-07-2019
  •  | 
  •  

سؤال

وأعمل على ملقم HTTP في ج ++، والآن يعمل لطلبات ملفات نصية، ولكن عندما تحاول الحصول على الحياة السياسية في فرنسا أو شيء من هذا، ويحصل على إرسالها فقط جزء من الملف. يبدو أن المشكلة أن يكون ذلك عند استخدام fgets (العازلة، 2000، returned_file) على ما يبدو لزيادة مؤشر موقف ملف أكثر بكثير من أن ينتهي فعليا حتى وضع في المخزن المؤقت. لماذا يحدث هذا؟ أضع كل ما عندي من التعليمات البرمجية أدناه. وتحدث هذه المشكلة في حين أن (الحقيقية) حلقة الذي يحدث عند رمز الاستجابة 200. شكرا لكل من الردود.

// Interpret the command line arguments
unsigned short port = 8080;

if ( (argc != 1) && (argc != 3) && (argc != 5) ) {
  cerr << "Usage: " << argv[0];
  cerr << " -p <port number> -d <base directory>" << endl;
  return 1;
}
else {
  for (int i = 1; i < argc; ++i) {
    if (strcmp(argv[i], "-p") == 0)
      port = (unsigned short) atoi(argv[++i]);
    else if (strcmp(argv[i], "-d") == 0)
      base_directory = argv[++i];
  }
}
// if base_directory was not given, set it to current working directory
if ( !base_directory ) {
  base_directory = getcwd(base_directory, 100);
}

// Create TCP socket
int tcp_sock = socket(AF_INET, SOCK_STREAM, 0);
if (tcp_sock < 0) {
  cerr << "Unable to create TCP socket." << endl;
  return 2;
}

// Create server socket
sockaddr_in server;
server.sin_family = AF_INET;
server.sin_port = htons( port );
server.sin_addr.s_addr = INADDR_ANY;

// Bind the socket
if (bind(tcp_sock, (sockaddr*)&server, sizeof(server)) < 0) {
  cerr << "Unable to bind TCP socket." << endl;
  return 3;
}

// Listen for a connection request on TCP port
listen(tcp_sock, 5);

// Create HTTP_Request object and start a while loop of accepting connections
char buffer[2000];
int bytes_recv = 0;
int recv_len = 0;
string error_reply;

HTTP_Response* response;

while (true) {
  int acc_tcp_sock = accept(tcp_sock, NULL, NULL);
  if (acc_tcp_sock == -1) {
    cerr << "Unable to open TCP connection with client." << endl;
  }
  do {
    // may want to do just one recv
    recv_len = recv( acc_tcp_sock, buffer + bytes_recv,
      2000 - bytes_recv, 0 );
    bytes_recv += recv_len;
  } while (false);
  bytes_recv = 0;
  // may want to see if this causes a memory leak
  HTTP_Request* request = HTTP_Request::Parse(buffer, 2000);

  response = handle_request(request); // function to handle the request

  // Put response header into buffer
  response->Print( buffer, 2000 );

  // if 200 and GET then send header with file
  if ( response->Get_code() == 200 ) {
    // send response header
    if ( send( acc_tcp_sock, buffer, strlen(buffer), 0 ) < 0 ) {
      cerr << "Unable to send response header to client." << endl;
    }
    if ( method == "GET" ) {
      // send file
      while ( true ) {
        fgets( buffer, 2000, returned_file );
        if ( feof( returned_file ) ) break;
        if ( send( acc_tcp_sock, buffer, strlen(buffer), 0 ) < 0 ) {
          cerr << "Unable to send file in response to client." << endl;
        }
      }
    }
    fclose( returned_file ); // close file
  }
  else {
    if ( method == "GET" ) {
      error_reply = buffer + error_page;
      if ( send( acc_tcp_sock, error_reply.c_str(), error_reply.length(), 0 ) < 0 ) {
        cerr << "Unable to send response to client." << endl;
      }
    }
    else {
      if ( send( acc_tcp_sock, buffer, strlen(buffer), 0 ) < 0 ) {
        cerr << "Unable to send respone header to client." << endl;
      }
    }
  }

  close( acc_tcp_sock ); // close the connection
}

return 0;
هل كانت مفيدة؟

المحلول

لا تستخدم fgets() لقراءة البيانات الثنائية التي تحتاج إلى البقاء على قيد الحياة قليلا لبت. كنت لا تريد ترجمة سجل فاصل، وبعض النظم قد تفترض انها النص إذا كنت تقرأ على هذا النحو. لهذه المسألة، أسطر جديدة وسجل فاصلة لا معنى لها تماما حتى fgets () `ظيفة المسح الضوئي بالنسبة لهم هي في أحسن الأحوال عدم الكفاءة مربكة، وفي أسوأ الأحوال ببساطة لا-ثنائي قادرة على الإطلاق.

استخدم fread(3)، أو الأفضل من ذلك، استخدم استدعاء نظام الخام (POSIX API على أي حال، بشأن عدم يونكس) قراءة (2). هذا وسوف تقرأ قدرا معينا من البيانات بت لبت واقول لكم كم هو قراءة. (فيما يتعلق <م> التي API ثنائي قادرة على استخدام: عادة، نحن ينصح العازلة البيانات لأن نقوم بمعالجة عادة في وحدات صغيرة مثل خطوط ومع ذلك، عندما تتحرك ملف كامل من مكان إلى التخزين المؤقت آخر فقط. يبطئ أنت إلى أسفل. في هذه الحالة هو أبسط وأسرع لمجرد استخدام read()).

وأنت أيضا لا يمكن strlen() البيانات الثنائية. لديك لمجرد استخدام عدد وحدات البايت من استدعاء API.

نصائح أخرى

ولن باستخدام strlen كسر في الملفات الثنائية؟

send( acc_tcp_sock, buffer, strlen(buffer), 0 )

ومن المحتمل جدا أن الملفات الثنائية الخاصة بك تحتوي على بايت فارغة ('\0'). عند قراءة البيانات مع fgets، قد وضعها في المخزن، ولكن عند إحالته كل شيء بعد يضيع \0 (دعوة strlen بك يضمن هذا).

وهكذا، تحتاج إلى استخدام fread لقراءة البيانات. تقوم بإرجاع عدد البايتات التي تم قراءتها في الواقع، لذلك لا تحتاج إلى استخدام strlen على الإطلاق. و لا تنسى لفتح ملف في الوضع الثنائي!

وأفضل، قرأت عن ملفات التعيين في الذاكرة، وبهذه الطريقة لم يكن لديك لإدارة المخازن لقراءة محتوى الملف، ويمكنك تمرير هذا المخزن إلى send وتحصل على حجم ملف في اتجاه واحد.

إذا كنت تريد حقا لقراءة بايت من الملف، ثم عليك أن تميز قراءة الملفات الثنائية (مع نوع التمثيل الصامت الصحيح أو application/octet-stream وتخزين بايت قراءة الاعتماد مع العازلة) وفتح الملفات كنص (text/* التمثيل الصامت-أنواع، ويمكنك استخدام strlen).

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top