13

TCP/IP ソケットを使用して 2 台のコンピューター間で (サーバーから両方とも Linux を実行しているクライアントに) 画像ファイルを転送できるようにするために、小さな C プログラムを作成していますが、反対側に私の写真が表示されるため、エラーが発生しているようです。破損しています。

私のサーバーのコードは次のとおりです。

#include<stdio.h>
#include<string.h>
#include<sys/socket.h>
#include<arpa/inet.h>   
#include<unistd.h>  
#include<iostream>
#include<fstream>
#include<errno.h>

using namespace std;

int send_image(int socket){

FILE *picture;
int size, read_size;
char send_buffer[10240], verify;

picture = fopen("2.jpg", "r");
printf("Getting Picture Size\n");   

if(picture == NULL) {
   printf("Error Opening Image File");
} 

fseek(picture, 0, SEEK_END);
size = ftell(picture);
fseek(picture, 0, SEEK_SET);

//Send Picture Size
printf("Sending Picture Size\n");
write(socket, (void *)&size, sizeof(int));

if(read_size = read(socket, &verify , sizeof(char)) < 0) {
   puts("\nError Receiving Verification");
}


if(verify == '1'){
    printf("5\n");
    //Send Picture as Byte Array
    printf("Sending Picture as Byte Array\n");

    while(!feof(picture)) {

          //Read from the file into our send buffer
          read_size = fread(send_buffer, 1, sizeof(send_buffer)-1, picture);

          //Send data through our socket 
          write(socket, send_buffer, read_size);                        

          //Wait for the verify signal to be received 
          while(read(socket, &verify , sizeof(char)) < 0);

          if(verify != '1') {
             printf("Error Receiving the Handshake signal\n %s",&verify);
          }

          verify = '';

          //Zero out our send buffer
          bzero(send_buffer, sizeof(send_buffer));
   }
}
}

int main(int argc , char *argv[])
{
int socket_desc , new_socket , c, read_size,buffer = 0;
struct sockaddr_in server , client;
char *readin;

//Create socket
socket_desc = socket(AF_INET , SOCK_STREAM , 0);
if (socket_desc == -1)
{
    printf("Could not create socket");
}

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

//Bind
if( bind(socket_desc,(struct sockaddr *)&server , sizeof(server)) < 0)
{
    puts("bind failed");
    return 1;
}

puts("bind done");

//Listen
listen(socket_desc , 3);

//Accept and incoming connection
puts("Waiting for incoming connections...");
c = sizeof(struct sockaddr_in);

if((new_socket = accept(socket_desc, (struct sockaddr *)&client, (socklen_t*)&c))){
    puts("Connection accepted");
}

fflush(stdout);

if (new_socket<0)
{
    perror("Accept Failed");
    return 1;
}

send_image(new_socket);

    close(socket_desc);
    fflush(stdout);
return 0;
}

データを受信して​​いるクライアント側のコードは次のとおりです。

 #include<stdio.h>
 #include<string.h>    //strlen
 #include<sys/socket.h>
 #include<sys/ioctl.h>
 #include<arpa/inet.h>    
 #include<unistd.h>
 #include<iostream>
 #include<errno.h>
 using namespace std;

 //This function is to be used once we have confirmed that an image is to be sent
 //It should read and output an image file
 int receive_image(int socket){

int buffersize = 0, recv_size = 0,size = 0, read_size, write_size;
char imagearray[10241],verify = '1';
FILE *image;

//Find the size of the image
read(socket, &size, sizeof(int));



//Send our verification signal
write(socket, &verify, sizeof(char));
//Make sure that the size is bigger than 0
if(size <= 0 ){
    printf("Error has occurred. Size less than or equal to 0\n");
    return -1;
}

image = fopen("2.jpg", "w");

if( image == NULL) {
    printf("Error has occurred. Image file could not be opened\n");
    return -1;
}

//Loop while we have not received the entire file yet
while(recv_size < size) {
    ioctl(socket, FIONREAD, &buffersize); 

    //We check to see if there is data to be read from the socket    
    if(buffersize > 0 ) {

        if(read_size = read(socket,imagearray, buffersize) < 0){
            printf("%s", strerror(errno));
        }

        //Write the currently read data into our image file
        write_size = fwrite(imagearray,1,(buffersize), image);

        if(write_size != buffersize) {
          printf("write and buffersizes wrong");
        }

        if(read_size !=write_size) {
            printf("error in read write");
        }

        //Increment the total number of bytes read
        recv_size += read_size;

                    //Send our handshake verification info
        write(socket, &verify, sizeof(char));

    }
 }

fclose(image);
printf("Image successfully Received!\n");
return 1;
}

int main(int argc , char *argv[])
{

int socket_desc;
struct sockaddr_in server;
char *parray;


//Create socket
socket_desc = socket(AF_INET , SOCK_STREAM , 0);

if (socket_desc == -1) {
    printf("Could not create socket");
}

memset(&server,0,sizeof(server));
server.sin_addr.s_addr = inet_addr("10.42.0.1");
server.sin_family = AF_INET;
server.sin_port = htons( 8889 );

//Connect to remote server
if (connect(socket_desc , (struct sockaddr *)&server , sizeof(server)) < 0) {
    cout<<strerror(errno);
    close(socket_desc);
    puts("Connect Error");
    return 1;
}

puts("Connected\n");

receive_image(socket_desc);

close(socket_desc);

return 0;
}

誰か私に手を貸してくれませんか?私の人生でこのエラーを理解することはできません。

編集: fwrites と freads を通常の書き込みと読み取りに戻しましたが、それでも破損した画像が送信されます

4

3 に答える 3

10

いくつかの問題があります。

  • "rb"デフォルトのテキストモードではなく、バイナリモード(読み取り"wb"用、書き込み用)でファイルを開く必要があります。Windows (および行末変換を行うその他のシステム) では、書き込み時に stdio ライブラリが LF (バイト 0x0A) を CRLF ペア (2 バイト 0x0D 0x0A) に変換し、読み取り時に逆変換を行います。JPEG ファイルのような非テキスト データの場合、これによりデータが破損します。
  • 各送信後に「ハンドシェイク」バイトを送信する必要はありません。TCP/IP は、確認/再送信/フロー制御などを既に処理しています。send()/write()が正の値を返す限り、多くのバイトが他のピアによって受信されたと想定できます。
  • send()/write()は、要求したすべてのデータを送信しない場合があります。部分的な送信を行う場合があります。その場合は、残りのバッファをループで送信し続ける必要があります。
  • sizeof(char)は C 言語標準によって 1 であることが保証されていsizeof(char)ます。代わりに、それがなくてもコードがより明確になる場合を言う必要はほとんどありません。
  • クライアント コードでは、ioctlブロックせずに読み取ることができるデータの量を判断するためにこれを使用する必要はありません。これは、再びループしているためです。利用可能なデータがない間、コードは 100% CPU でスピンします。read()通話をブロックするだけです。このコードをラップトップで実行している場合、バッテリーは感謝します。
  • 同様に、クライアントはほぼ間違いなく部分的な読み取りを取得します。1 回の呼び出しでファイル全体を受け取ることはありません。取得したデータを書き出してから、ループして再度受信する必要があります。
  • 開始時にソケットを介してイメージ サイズを送信すると、2 つのシステムのエンディアンが同じでない場合、クライアントで異なる値を取得する可能性があります。コードを防弾にするためには、送信時にデータをネットワーク順序 (ビッグエンディアン) に変換し、受信後にホスト (ネイティブ) 順序に戻す必要があります。ntohl(3)およびhtonl(3)関数を使用して、4 バイト値のこれらの変換を行うことができます。
于 2013-03-16T04:30:59.077 に答える
9

今はうまく動作します。

一番、

マリオ。

クライアント:

#include<stdio.h>
#include<string.h>
#include<sys/socket.h>
#include<arpa/inet.h>   
#include<sys/ioctl.h>
#include<unistd.h>  
#include<iostream>
#include<fstream>
#include<errno.h>
using namespace std;

//This function is to be used once we have confirmed that an image is to be sent
//It should read and output an image file

int receive_image(int socket)
{ // Start function 

int buffersize = 0, recv_size = 0,size = 0, read_size, write_size, packet_index =1,stat;

char imagearray[10241],verify = '1';
FILE *image;

//Find the size of the image
do{
stat = read(socket, &size, sizeof(int));
}while(stat<0);

printf("Packet received.\n");
printf("Packet size: %i\n",stat);
printf("Image size: %i\n",size);
printf(" \n");

char buffer[] = "Got it";

//Send our verification signal
do{
stat = write(socket, &buffer, sizeof(int));
}while(stat<0);

printf("Reply sent\n");
printf(" \n");

image = fopen("capture2.jpeg", "w");

if( image == NULL) {
printf("Error has occurred. Image file could not be opened\n");
return -1; }

//Loop while we have not received the entire file yet


int need_exit = 0;
struct timeval timeout = {10,0};

fd_set fds;
int buffer_fd, buffer_out;

while(recv_size < size) {
//while(packet_index < 2){

    FD_ZERO(&fds);
    FD_SET(socket,&fds);

    buffer_fd = select(FD_SETSIZE,&fds,NULL,NULL,&timeout);

    if (buffer_fd < 0)
       printf("error: bad file descriptor set.\n");

    if (buffer_fd == 0)
       printf("error: buffer read timeout expired.\n");

    if (buffer_fd > 0)
    {
        do{
               read_size = read(socket,imagearray, 10241);
            }while(read_size <0);

            printf("Packet number received: %i\n",packet_index);
        printf("Packet size: %i\n",read_size);


        //Write the currently read data into our image file
         write_size = fwrite(imagearray,1,read_size, image);
         printf("Written image size: %i\n",write_size); 

             if(read_size !=write_size) {
                 printf("error in read write\n");    }


             //Increment the total number of bytes read
             recv_size += read_size;
             packet_index++;
             printf("Total received image size: %i\n",recv_size);
             printf(" \n");
             printf(" \n");
    }

}


  fclose(image);
  printf("Image successfully Received!\n");
  return 1;
  }

  int main(int argc , char *argv[])
  {

  int socket_desc;
  struct sockaddr_in server;
  char *parray;


  //Create socket
  socket_desc = socket(AF_INET , SOCK_STREAM , 0);

  if (socket_desc == -1) {
  printf("Could not create socket");
  }

  memset(&server,0,sizeof(server));
  server.sin_addr.s_addr = inet_addr("10.0.0.30");
  server.sin_family = AF_INET;
  server.sin_port = htons( 8889 );

  //Connect to remote server
  if (connect(socket_desc , (struct sockaddr *)&server , sizeof(server)) < 0) {
  cout<<strerror(errno);
  close(socket_desc);
  puts("Connect Error");
  return 1;
  }

  puts("Connected\n");

  receive_image(socket_desc);

  close(socket_desc);

  return 0;
  }

サーバ:

   #include<stdio.h>
   #include<string.h>
   #include<sys/socket.h>
   #include<arpa/inet.h>   
   #include<unistd.h>  
   #include<iostream>
   #include<fstream>
   #include<errno.h>

   using namespace std;

   int send_image(int socket){

   FILE *picture;
   int size, read_size, stat, packet_index;
   char send_buffer[10240], read_buffer[256];
   packet_index = 1;

   picture = fopen("capture.jpeg", "r");
   printf("Getting Picture Size\n");   

   if(picture == NULL) {
        printf("Error Opening Image File"); } 

   fseek(picture, 0, SEEK_END);
   size = ftell(picture);
   fseek(picture, 0, SEEK_SET);
   printf("Total Picture size: %i\n",size);

   //Send Picture Size
   printf("Sending Picture Size\n");
   write(socket, (void *)&size, sizeof(int));

   //Send Picture as Byte Array
   printf("Sending Picture as Byte Array\n");

   do { //Read while we get errors that are due to signals.
      stat=read(socket, &read_buffer , 255);
      printf("Bytes read: %i\n",stat);
   } while (stat < 0);

   printf("Received data in socket\n");
   printf("Socket data: %c\n", read_buffer);

   while(!feof(picture)) {
   //while(packet_index = 1){
      //Read from the file into our send buffer
      read_size = fread(send_buffer, 1, sizeof(send_buffer)-1, picture);

      //Send data through our socket 
      do{
        stat = write(socket, send_buffer, read_size);  
      }while (stat < 0);

      printf("Packet Number: %i\n",packet_index);
      printf("Packet Size Sent: %i\n",read_size);     
      printf(" \n");
      printf(" \n");


      packet_index++;  

      //Zero out our send buffer
      bzero(send_buffer, sizeof(send_buffer));
     }
    }

    int main(int argc , char *argv[])
    {
      int socket_desc , new_socket , c, read_size,buffer = 0;
      struct sockaddr_in server , client;
      char *readin;

      //Create socket
      socket_desc = socket(AF_INET , SOCK_STREAM , 0);
      if (socket_desc == -1)
      {
         printf("Could not create socket");
      }

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

      //Bind
     if( bind(socket_desc,(struct sockaddr *)&server , sizeof(server)) < 0)
     {
       puts("bind failed");
       return 1;
     }

     puts("bind done");

     //Listen
     listen(socket_desc , 3);

      //Accept and incoming connection
      puts("Waiting for incoming connections...");
      c = sizeof(struct sockaddr_in);

     if((new_socket = accept(socket_desc, (struct sockaddr *)&client,(socklen_t*)&c))){
puts("Connection accepted");
         }

    fflush(stdout);

    if (new_socket<0)
    {
      perror("Accept Failed");
      return 1;
    }

    send_image(new_socket);

    close(socket_desc);
    fflush(stdout);
    return 0;
    }
于 2014-03-15T03:04:49.937 に答える