2013-03-16 58 views
7

TCP/IPソケットを使って2台のコンピュータ間で画像ファイルを転送するために小さなCプログラムを書いています私の画像が破損した他の面に現れるので、エラーであるようです。C言語でソケットを使って画像を送信する(JPEG)

私のサーバーのためのコードは以下のようなある:

#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を変更し、読み、それはまだ壊れた画像に

+1

あなたがioctl'と '' FIONREAD'の必要性をしたん。まだデータがない場合はブロックするだけです。それは、あなたが他の何かをやっているようではありません。 – icktoofay

+0

個々のread_sizeが個々のwrite_sizeに対応していることを確認しましたか? –

+0

[C/C++(GCC/G ++)を使用したLinuxでソケットプログラミングでファイルを送受信する]の可能な複製(http://stackoverflow.com/questions/2014033/send-and-receive-a-file-in-ソケットプログラミング-in-linux-with-cc-gcc-g) –

答えて

6

を送信しますが、多くの問題持っていました:あなたは、ファイルを開く必要があり

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

'#include 'ならば、あなたは '' rb ''と '" rでファイルを開く必要はありません"いいです。 –

+0

あなたが言及したコードのクライアント部分については、部分的な読み込みが行われていますが、私のコードはそれを処理していませんか?使用可能なバイト数を読み込み、読み込み関数から返されたバイト数をファイルに書き込んだ後、ファイルサイズに等しいバイト数が書き込まれるまでループします。 – user1721182

+0

また、この画像転送プログラムは、Ubuntuを実行しているクライアントとサーバーでのみ使用されていますので、バイナリモードでファイルを開く必要はありませんか? – user1721182

4

今、うまく動作します。

ベスト、

マリオ。

クライアント:

#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; 
    } 
関連する問題