通过Socket发送图像(JPEG)

Sending Image (JPEG) through Socket in C Linux

本文关键字:JPEG 图像 Socket 通过      更新时间:2023-10-16

我正在编写一个小的C程序,以便能够在两台计算机之间传输图像文件(从服务器到客户端都运行linux)使用TCP/IP套接字,但似乎有一个错误,因为我的图片出现在另一边损坏。

我的服务器的代码如下:

#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 Sizen");   
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 Sizen");
write(socket, (void *)&size, sizeof(int));
if(read_size = read(socket, &verify , sizeof(char)) < 0) {
   puts("nError Receiving Verification");
}

if(verify == '1'){
    printf("5n");
    //Send Picture as Byte Array
    printf("Sending Picture as Byte Arrayn");
    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 signaln %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 0n");
    return -1;
}
image = fopen("2.jpg", "w");
if( image == NULL) {
    printf("Error has occurred. Image file could not be openedn");
    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("Connectedn");
receive_image(socket_desc);
close(socket_desc);
return 0;
}
谁能帮我一下这个?我怎么也弄不清这个错误。

编辑:我已经改变了fwrites和freads回到常规的写和读,它仍然发送一个损坏的图像

你有很多问题:

  • 您需要以二进制模式打开文件("rb"用于读取,"wb"用于写入),而不是默认的文本模式。在Windows(以及任何其他进行行结束转换的系统)上,stdio库在写入时将lf(字节0x0A)转换为CRLF对(两个字节0x0D 0x0A),并在读取时进行反向转换。对于非文本数据,如JPEG文件,这会破坏数据。
  • 没有必要在每次发送之后发送你的"握手"字节。TCP/IP已经处理了确认/重发/流量控制等。您可以假设只要send()/write()返回一个正值,那么另一个对等体收到了许多字节。
  • send()/write()可能不会发送你要求它发送的所有数据,它们可能会部分发送。如果发生这种情况,您需要继续尝试在循环中发送剩余的缓冲区。
  • sizeof(char)被C语言标准保证为1,很少有必要说sizeof(char),当你的代码没有它会更清晰
  • 在客户端代码中,没有必要使用ioctl来确定在没有阻塞的情况下可以读取多少数据,因为您只是再次循环—当没有数据可用时,您的代码将在100% CPU下旋转。让read()调用阻塞。如果你在笔记本电脑上运行这个代码,你的电池会感谢你的。
  • 同样,客户端几乎肯定会获得部分读取,您不会在一次调用中接收整个文件。你需要写出你得到的数据,然后循环并再次接收。
  • 当您在开始时通过套接字发送图像大小时,如果两个系统的端序不同,您可能会在客户端获得不同的值。为了使您的代码防弹,您需要在发送数据时将其转换为网络顺序(大端),然后在接收数据后将其转换回主机(本机)顺序。可以使用ntohl(3)htonl(3)函数对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: %in",stat);
printf("Image size: %in",size);
printf(" n");
char buffer[] = "Got it";
//Send our verification signal
do{
stat = write(socket, &buffer, sizeof(int));
}while(stat<0);
printf("Reply sentn");
printf(" n");
image = fopen("capture2.jpeg", "w");
if( image == NULL) {
printf("Error has occurred. Image file could not be openedn");
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: %in",packet_index);
        printf("Packet size: %in",read_size);

        //Write the currently read data into our image file
         write_size = fwrite(imagearray,1,read_size, image);
         printf("Written image size: %in",write_size); 
             if(read_size !=write_size) {
                 printf("error in read writen");    }

             //Increment the total number of bytes read
             recv_size += read_size;
             packet_index++;
             printf("Total received image size: %in",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("Connectedn");
  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 Sizen");   
   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: %in",size);
   //Send Picture Size
   printf("Sending Picture Sizen");
   write(socket, (void *)&size, sizeof(int));
   //Send Picture as Byte Array
   printf("Sending Picture as Byte Arrayn");
   do { //Read while we get errors that are due to signals.
      stat=read(socket, &read_buffer , 255);
      printf("Bytes read: %in",stat);
   } while (stat < 0);
   printf("Received data in socketn");
   printf("Socket data: %cn", 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: %in",packet_index);
      printf("Packet Size Sent: %in",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;
    }

我修改了@mmirand6 answer,使服务器在客户端发送图像时接收图像(即,上面的示例反之亦然)。同样,这个例子使用了localhost。另一个区别是,服务器永远不会退出,并一直等待新的连接。

server.cpp

#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 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: %in",stat);
printf("Image size: %in",size);
printf(" n");*/
char buffer[] = "Got it";
//Send our verification signal
do{
stat = write(socket, &buffer, sizeof(int));
}while(stat<0);
printf("Reply sentn");
printf(" n");
image = fopen("res.ppm", "w");
if( image == NULL) {
printf("Error has occurred. Image file could not be openedn");
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: %in",packet_index);
            printf("Packet size: %in",read_size);*/

        //Write the currently read data into our image file
         write_size = fwrite(imagearray,1,read_size, image);
         //printf("Written image size: %in",write_size);
             if(read_size !=write_size) {
                 printf("error in read writen");    }

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

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

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); // int listen(int s, int backlog); | `backlog` (3)
    //limits the number of outstanding connections in the socket's listen
    //queue to the value specified by the backlog argument.
    while(true)
    {
      //Accept and incoming connection
      puts("Waiting for incoming connections...");
      c = sizeof(struct sockaddr_in);
      // waits for a connection. returns -1 on failure, a positive val on success
      if((new_socket = accept(socket_desc, (struct sockaddr *)&client,(socklen_t*)&c)))
      {
          puts("Connection accepted");
          cout << "new_socket = " << new_socket << "n";
      }
      fflush(stdout);
      if (new_socket<0)
      {
          perror("Accept Failed, trying again");
          continue;
      }
      // receive image
      receive_image(new_socket);
    }
    close(socket_desc);
    fflush(stdout);
    return 0;
}

client.cpp

#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 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("test.ppm", "r");
    printf("Getting Picture Sizen");
    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: %in",size);
    //Send Picture Size
    printf("Sending Picture Sizen");
    write(socket, (void *)&size, sizeof(int));
    //Send Picture as Byte Array
    printf("Sending Picture as Byte Arrayn");
    do { //Read while we get errors that are due to signals.
       stat=read(socket, &read_buffer , 255);
       printf("Bytes read: %in",stat);
    } while (stat < 0);
    printf("Received data in socketn");
    printf("Socket data: %cn", 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: %in",packet_index);
       printf("Packet Size Sent: %in",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;
    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("127.0.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("Connectedn");
    send_image(socket_desc);
    //close(socket_desc);
    return 0;
}

$gcc client.cpp -lstdc++ -o client编译