0

クライアントとサーバーがあり、クライアントがサーバーに接続すると、サーバーはテキストファイルを読み取り、大文字に変換して、行ごとにクライアントに送信します。テキスト ファイルの名前は「text.txt」で、次のようになります。

ここに画像の説明を入力

サーバーコード

 #include<io.h>
 #include<iostream>
 #include <string>
 #include<fstream>
 #include<winsock2.h>
 #include<winsock2.h>


 #pragma comment(lib,"ws2_32.lib") //Winsock Library

  using namespace std;

void stringToUpper(string &s)
  {
 for(unsigned int l = 0; l < s.length(); l++)
  {
   s[l] = toupper(s[l]);
  }
  }

   int main()
  {
    WSADATA wsa;
    SOCKET s , new_socket;
     struct sockaddr_in server , client;
     int c;
    char *message;

     cout<<"\nInitialising Winsock...";
    if (WSAStartup(MAKEWORD(2,2),&wsa) != 0)
    {
       cout<<"Failed. Error Code"<<WSAGetLastError();
        return 1;
     }

   cout<<"Initialised.\n";

     //Create a socket
     if((s = socket(AF_INET , SOCK_STREAM , 0 )) == INVALID_SOCKET)
    {
        cout<<"Could not create socket "<< WSAGetLastError();
     }

      cout<<"Socket created.\n";

    //Prepare the sockaddr_in structure
      server.sin_family = AF_INET;
    server.sin_addr.s_addr = INADDR_ANY;
     server.sin_port = htons( 8888 );

    //Bind
    if( bind(s ,(struct sockaddr *)&server , sizeof(server)) == SOCKET_ERROR)
    {
      cout<<"Bind failed with error code : "<< WSAGetLastError();
       exit(EXIT_FAILURE);
  }

   puts("Bind done");

    //Listen to incoming connections
     listen(s , 3);

    //Accept and incoming connection
    puts("Waiting for incoming connections...");

     c = sizeof(struct sockaddr_in);

 while( (new_socket = accept(s , (struct sockaddr *)&client, &c)) != INVALID_SOCKET )
    {
       puts("Connection accepted");

      //Reply to the client
    string STRING;
ifstream infile;
infile.open ("text.txt");
     while(!infile.eof()) 
         {
        getline(infile,STRING); 
    stringToUpper(STRING);
        const char *STRING_mod = STRING.c_str();
        send(new_socket , STRING_mod , strlen(STRING_mod) , 0);
        }
         char *end_msg="end";
    send(new_socket , end_msg , strlen(end_msg) , 0);

   infile.close();



       }

     if (new_socket == INVALID_SOCKET)
      {
        cout<<"accept failed with error code : " << WSAGetLastError();
         return 1;
      }

       closesocket(s);
       WSACleanup();



      return 0;
       }

クライアントコード

  #include<iostream>
  #include<winsock2.h>

   #pragma comment(lib,"ws2_32.lib") //Winsock Library

   using namespace std;
 int main(int argc , char *argv[])
  {
   WSADATA wsa;
   SOCKET s;
   struct sockaddr_in server;
   char *message , server_reply[2000];
int recv_size;

   printf("\nInitialising Winsock...");
   if (WSAStartup(MAKEWORD(2,2),&wsa) != 0)
    {
    cout<<"Failed. Error Code : "<<WSAGetLastError();
    return 1;
    }

     cout<<"Initialised.\n";

    //Create a socket
      if((s = socket(AF_INET , SOCK_STREAM , 0 )) == INVALID_SOCKET)
   {
     cout<<"Could not create socket : " << WSAGetLastError();
   }

   cout<<"Socket created.\n";


   server.sin_addr.s_addr = inet_addr("127.0.0.1");
   server.sin_family = AF_INET;
   server.sin_port = htons( 8888 );

    //Connect to remote server
     if (connect(s , (struct sockaddr *)&server , sizeof(server)) < 0)
    {
       puts("connect error");
       return 1;
   }

   puts("Connected");






  recv_size = recv(s, server_reply, 2000, 0);
    server_reply[recv_size] = '\0';
    while ( server_reply != "end"){

        cout<<server_reply<<endl;
       recv_size = recv(s, server_reply, 2000, 0);
       server_reply[recv_size] = '\0';

    }






       closesocket(s);
      WSACleanup();


   return 0;
    }

サーバーを実行してからクライアントを実行すると、次の応答があります。

ここに画像の説明を入力

しかし、これは必要な動作ではありません。テキストファイルに表示されているとおりにテキストを表示したいのですが、「1行ずつ」.....コードのどこに問題があり、どのように修正できますか? クライアントが while ループで動かなくなったのはなぜですか?

ありがとう。

4

3 に答える 3

1

改行も送信する必要があります。getline改行まですべての文字を読み取りますが、文字列に改行を保存しません。したがって、文字列を送信すると、改行がありません。

単独で送信することもでき"\n"ますが、既存の文字列に改行を追加する方がよいでしょう。

例:

  stringToUpper(STRING);
  STRING += "\n";
  ... 
于 2013-08-31T10:00:59.687 に答える
1

プログラムにいくつかの問題があります。それらはコメントにリストするには多すぎるため、ここに回答として記載します。

  • クライアントでは、サーバーの応答が配列に格納され、その配列を使用して、機能し"end"ない文字列リテラルと比較します。文字列を に変換するか、 をstd::string使用しますstrcmp
  • クライアントは にデータを持っていますが、生の文字列ポインタを取得し、それを使用して のメソッドの代わりに をstd::string使用して文字列の長さを計算します。strlenlengthstd::string
  • エラーチェックはまったくないようです。すべてのソケット関数はエラー時に-1(または) を返し、接続が閉じられると関数が戻ります。SOCKET_ERRORrecv0
  • クライアントで受信するときの配列のサイズなど、コードで「マジック ナンバー」を使用します。そうしないでください。代わりに (クライアントrecv呼び出しの場合) を使用しますsizeof(server_reply)

そして何よりも重要なこと:

  • TCP ソケットはストリーミングソケットです。つまり、メッセージの境界がなく、クライアントは 1 回の呼び出しで、recv要求したよりも少ない量を実際に受信したり、1 回のsend呼び出しで送信した量よりも多く受信したりできます。これはあなたに起こる最後のことです。呼び出しは、サーバーから送信されたすべてrecvを 1 回の呼び出しで実際に受信します。また、改行なしで文字列を送信したため、改行なしで受信します。

    TCP ソケットを使用するほとんどのプロトコルには、メッセージにメッセージ長が含まれているか、ある種の特別な境界シーケンス (ほとんどの場合、キャリッジ リターンと改行 (つまり"\r\n")) があります。

于 2013-08-31T10:01:52.407 に答える
1

getlineは、区切り文字を除くすべてを読み取ります。送信する前に、文字列に LF または CR+LF を追加する必要があります。

于 2013-08-31T10:02:33.770 に答える