I practice in socket programming, I wrote a code (server: python, client: C/C++) to transfer data though socket. With small file, it works perfectly. Then I try with bigger file, it only transfers part of that file. Here is my code:
Server
def recv_file_from_client(conn):
f = open("torecv","wb")
while(True):
l = conn.recv(1024)
if "Done" in l:
break
f.write(l)
f.close()
print "Done recv"
Client
BOOL SendFile(TCHAR* file) {
FILE* filewrite = fopen("test.txt", "a");
FILE* fp = _wfopen(file, L"rb");
unsigned char buffer[1024] = { NULL };
int readedChar;
int total = 0;
char log[128] = { NULL };
while ((readedChar = fread(buffer, 1, 1024, fp)) > 0) {
if (send(s, (const char*)buffer, sizeof(buffer), 0)) {
total += readedChar;
sprintf(log, "%d\n", total);
fputs(log,filewrite);
}
memset(buffer, 0, 1024);
}
send(s, "Done", 1024, 0);
fclose(fp);
return TRUE;
}

Your sending code has many logic errors:
lack of adequate error handling.
passing the wrong buffer size to send() (hint, it won't be 1024 for the last buffer if the file size is not an even multiple of 1024).
assuming send() sends the entire buffer in one go (hint, it rarely does). You need to call send() in a loop until the entire buffer has been sent.
misinterpreting the return value of send() (hint, it doesn't return a boolean). It returns the actual number of bytes sent (well, the number of bytes accepted into the socket's internal buffer for transmission in the background).
adding the wrong value to total after each send(), since you are assuming send() the entire buffer in one go.
sending a delimiter string at the end of the file, without regard to whether such delimiter may have appeared in the file being sent. It would be safer to instead send the file's size before sending the file's bytes.
specifying the wrong buffer size when sending the delimiter string (hint, "Done" is not 1024 bytes in size).
leaking the filewrite handle. You are not calling fclose() for it.
With that said, try something more like this instead:
BOOL SendRaw(const void *buffer, int size) {
const char *ptr = (const char*)buffer;
int numSent;
while (size > 0) {
numSent = send(s, ptr, size, 0);
if (numSent == -1)
return FALSE;
ptr += numSent;
size -= numSent;
}
return TRUE;
}
BOOL SendFile(const wchar_t* file) {
FILE* filewrite = fopen("test.txt", "a");
if (!filewrite)
return FALSE;
FILE* fp = _wfopen(file, L"rb");
if (!fp) {
fclose(filewrite);
return FALSE;
}
if (fseek(fp, 0, SEEK_END) != 0) {
fclose(fp);
fclose(filewrite);
return FALSE;
}
long size = ftell(fp);
if (size == -1L) {
fclose(fp);
fclose(filewrite);
return FALSE;
}
rewind(fp);
uint32_t tmp = htonl(size);
if (!SendRaw(&tmp, sizeof(tmp))) {
fclose(fp);
fclose(filewrite);
return FALSE;
}
unsigned char buffer[1024];
int numBytes, numSent, total = 0;
while (size > 0) {
numBytes = fread(buffer, 1, min(sizeof(buffer), size), fp);
if (numBytes < 1) {
fclose(fp);
fclose(filewrite);
return FALSE;
}
if (!SendRaw(buffer, numBytes)) {
fclose(fp);
fclose(filewrite);
return FALSE;
}
size -= numBytes;
total += numBytes;
fprintf(filewrite, "%d\n", total);
}
fclose(fp);
fclose(filewrite);
return TRUE;
}
import struct
def recv_file_from_client(conn):
f = open("torecv","wb")
data = conn.recv(4)
if not data:
print "Error recv"
return
size = struct.unpack("!I", data)[0]
while(size > 0):
data = conn.recv(min(1024, size))
if not data:
print "Error recv"
return
f.write(data)
size -= len(data)
f.close()
print "Done recv"
Done is no more than an arbitrary sequence of 4 bytes. If it is present in the tranfered file, it will stop the transfer. For binary files, the common way is to first send the size and then the file, or to send blocks with a well known structure (for example starting with the block size) and an empty block indicating the end of the file.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With