通过TCP / IP连接发送二进制文件

我将在这里重述整个问题,以便它是可以回答的。

我能够在不使用套接字的同一台机器上完美地复制二进制文件,只是制作一个简单的复制function。 尝试实现此代码以复制到TCP / IP连接但无法使其工作。

FILE *filehandle = fopen("imagefile.jpg", "rb"); FILE *dest =fopen("imagecopy.jpg", "wb"); // copied image file fseek(filehandle, 0, SEEK_END); unsigned long filesize = ftell(filehandle); char *buffer = (char*)malloc(sizeof(char)*filesize); rewind(filehandle); int bytesread = fread(buffer, sizeof(char), filesize, filehandle); for( int i=0; i<filesize; i++ ) { fputc(buffer[i], filehandle); // copies all the contents to dest } 

上面的代码非常适合在计算机中复制图像文件,但是当实现在服务器上复制时,很难实现。

我试图将一个图像文件从服务器发送到客户端,这两个文件都是用C手动完成的。服务器发送的文件长度只有在服务器发送文件时才知道,因此缓冲区是动态的在服务器中生成,如下所示:

服务器

 fseek(filehandle, 0, SEEK_END); long filesize = ftell(filehandle); // file could be 11000bytes char *buffer = (char*)malloc(sizeof(char)*filesize); // char buffer with 11000 bytes to store the data from the file. // then I call the send() function rewind(filehandle); // go back to beginning send(clientsocket, buffer, filesize, 0); // this is being sent perfectly, no errors because in the actual code, I am checking for errors 

客户

 // here is where I don't understand how to dynamically allocate the 11000 bytes to store the data in a client buffer // the filesize is not necessarily going to be 11000 so need to dynamically allocate // I did the following: #define BUFSIZE 10 FILE *filehandle = fopen("imagefile.jpg", "wb"); // image file created by client char *buffer = (char*)malloc(sizeof(char)*BUFSIZE); int bytesread = recv(buffer, 1, strlen(buffer), 0); if( bytesread > 0 ) { printf("Bytes read: %d\n", bytesread); // bytes read is 5 printf("Buffer: %s\n", buffer); // but buffer shows all the binary text like it normally would // when I try to store buffer in a file, it doesn't put full buffer because only 5 characters are written for( int i=0; i<bytesread; i++ ) { fputc(buffer[i], filehandle); // this doesn't create full image } } 

如何动态分配服务器发送的11000字节?

您需要循环发送和接收。 send()recv()都不保证发送/读取您请求的字节数。

您还应该在文件数据之前发送文件大小,以便接收方知道预期的字节数和停止读取的时间。

尝试更像这样的东西:

服务器

 bool senddata(SOCKET sock, void *buf, int buflen) { unsigned char *pbuf = (unsigned char *) buf; while (buflen > 0) { int num = send(sock, pbuf, buflen, 0); if (num == SOCKET_ERROR) { if (WSAGetLastError() == WSAEWOULDBLOCK) { // optional: use select() to check for timeout to fail the send continue; } return false; } pbuf += num; buflen -= num; } return true; } bool sendlong(SOCKET sock, long value) { value = htonl(value); return senddata(sock, &value, sizeof(value)); } bool sendfile(SOCKET sock, FILE *f) { fseek(f, 0, SEEK_END); long filesize = ftell(f); rewind(f); if (filesize == EOF) return false; if (!sendlong(sock, filesize)) return false; if (filesize > 0) { char buffer[1024]; do { size_t num = min(filesize, sizeof(buffer)); num = fread(buffer, 1, num, f); if (num < 1) return false; if (!senddata(sock, buffer, num, 0)) return false; filesize -= num; } while (filesize > 0); } return true; } 

 FILE *filehandle = fopen("imagefile.jpg", "rb"); if (filehandle != NULL) { sendfile(clientsocket, filehandle); fclose(filehandle); } 

客户

 bool readdata(SOCKET sock, void *buf, int buflen) { unsigned char *pbuf = (unsigned char *) buf; while (buflen > 0) { int num = recv(sock, pbuf, buflen, 0); if (num == SOCKET_ERROR) { if (WSAGetLastError() == WSAEWOULDBLOCK) { // optional: use select() to check for timeout to fail the read continue; } return false; } else if (num == 0) return false; pbuf += num; buflen -= num; } return true; } bool readlong(SOCKET sock, long *value) { if (!readdata(sock, value, sizeof(value))) return false; *value = ntohl(*value); return true; } bool readfile(SOCKET sock, FILE *f) { long filesize; if (!readlong(sock, &filesize)) return false; if (filesize > 0) { char buffer[1024]; do { int num = min(filesize, sizeof(buffer)); if (!readdata(sock, buffer, num)) return false; int offset = 0; do { size_t written = fwrite(&buffer[offset], 1, num-offset, f); if (written < 1) return false; offset += written; } while (offset < num); filesize -= num; } while (filesize > 0); } return true; } 

 FILE *filehandle = fopen("imagefile.jpg", "wb"); if (filehandle != NULL) { bool ok = readfile(clientsocket, filehandle); fclose(filehandle); if (ok) { // use file as needed... } else remove("imagefile.jpg"); } 

我们可以避免包含图像大小的标题,但我们只是读到发送数据的末尾。 关于缓冲区大小,我们可以使用固定数字,如10 * 1024,当我们从服务器收到一些数据时,我们只是根据实际接收的数据长度将其保存到文件中。

 // please open a file ... FILE * fp; // ... const int LENGTH = 10 * 1024; int len = 0; char * buffer = (char *)malloc(LENGTH); while ((len = recv(socket, buffer, LENGTH, 0)) > 0) { fwrite(buffer, 1, len, fp); } free(buffer); // close the file 

@TC:我想我们不能根据服务器发送的大小来分配缓冲区,以防图像太大而无法保存在客户端的内存中。 不提服务器是假的,并打算进行任何攻击。