I made a client server program by using C++.
I have a problem if I try to send large files. For example, a 50 byte file works fine while a 200 byte file fails.
Server Code:
// server.cpp : Defines the entry point for the console application.
#include "stdafx.h"
#include <WinSock2.h>
#include <Windows.h>
#include <stdio.h>
int _tmain(int argc, _TCHAR* argv[])
{
WORD wVersionRequested;
WSADATA wsaData;
int wsaerr;
wVersionRequested = MAKEWORD(2, 2);
wsaerr = WSAStartup(wVersionRequested, &wsaData);
if (wsaerr != 0) {
printf("The Winsock DLL not found \n ");
} else {
printf("The Winsock DLL found\n ");
}
if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) {
printf("not support Winsock version 2.2 ");
} else {
printf("support winsock version 2.2 \n ");
}
SOCKET m_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (m_socket == INVALID_SOCKET) {
printf("Error di socket(): %ld\n", WSAGetLastError());
WSACleanup();
} else{
printf("Socket() Berhasil ! \n");
}
sockaddr_in service;
service.sin_family = AF_INET;
service.sin_addr.s_addr = inet_addr("127.0.0.1");
service.sin_port = htons(55555);
int namelen = sizeof(service);
int m_bind = bind(m_socket, (sockaddr*)&service, namelen);
if (m_bind == SOCKET_ERROR){
printf("bind() failed ! %ld\n ", WSAGetLastError());
} else {
printf("bind() ok ! \n");
}
if (listen(m_socket, 1) == SOCKET_ERROR) {
printf("Listen() failed ! %d\n ", WSAGetLastError());
} else {
printf("Listen() ok ! \n");
}
SOCKET AcceptSocket;
printf("waiting for Client...\n \n");
int addresslen = sizeof(service);
while (AcceptSocket = accept(m_socket, (sockaddr*)&service, &addresslen)) {
printf("Server dan Client connected --> ");
char *ClientIP = inet_ntoa(service.sin_addr);
int ClientPort = ntohs(service.sin_port);
printf("IP: %s:%d\n ", ClientIP, ClientPort);
char *Filesize = new char[10];
int Size = 0;
int recv_size, recv_file;
char Buffer[MAXCHAR];
FILE *File;
recv_file = recv(AcceptSocket, Buffer, Size, 0);
recv_size = recv(AcceptSocket, Filesize, 10, 0);
while (Filesize) {
//Menerima File Size
Size = atoi((const char*)Filesize);
File = fopen("D:\\fileReceived.txt", "wb");
fwrite((const char*)Buffer, 1, Size, File);
fclose(File);
printf("File received \n");
ZeroMemory(Buffer, Size);
// printf("File size : %d\n",Size);
recv_file = recv(AcceptSocket, Buffer, Size, 0);
recv_size = recv(AcceptSocket, Filesize, 10, 0);
}
}
}
Client Code
// client.cpp : Defines the entry point for the console application.
#include "stdafx.h"
#include <winsock2.h>
#include <Windows.h>
#include <stdio.h>
using namespace std;
int Size = 0;
char *Buffer;
int _tmain(int argc, _TCHAR* argv[])
{
WORD wVersionRequested;
WSADATA wsaData;
int wsaerr;
wVersionRequested = MAKEWORD(2, 2);
wsaerr = WSAStartup(wVersionRequested, &wsaData);
if (wsaerr != 0) {
printf("The Winsock DLL not found \n ");
} else {
printf("The Winsock DLL found \n ");
}
if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) {
printf("not support Winsock version 2.2 ");
} else {
printf("support winsock version 2.2 \n ");
}
SOCKET Client_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (Client_socket == INVALID_SOCKET) {
printf("Error di socket(): %ld\n", WSAGetLastError());
WSACleanup();
} else{
printf("Socket() ok ! \n");
}
SOCKADDR_IN clientService;
clientService.sin_family = AF_INET;
clientService.sin_addr.s_addr = inet_addr("127.0.0.1");
clientService.sin_port = htons(55555);
if (connect(Client_socket, (SOCKADDR*)&clientService, sizeof(clientService)) == SOCKET_ERROR) {
printf("connect() fail ! \n");
} else {
printf(" connect() ok .... \n ");
while (1){
FILE *File;
File = fopen("D:\\logging21.txt", "rb");
if (!File){
printf("", WSAGetLastError());
}
printf("File open ok ! \n");
fseek(File, 0, SEEK_END);
Size = ftell(File);
fseek(File, 0, SEEK_SET);
char cisi[10];
sprintf(cisi, "%i", Size);
// fclose(File);
send(Client_socket, cisi, 10, 0); //file size sent
// Sleep(6000);
Buffer = (char*)malloc(Size + 1);
fread(Buffer, Size, 1, File);
fclose(File);
send(Client_socket, Buffer, Size, 0); // File Binary sent
free(Buffer);
printf("sending finished....\n");
Sleep(6000);
}
}
}
The server is riddled with errors, but this is the most relevant to the asked question: Why can I only send a few bytes?
At the very least, filesize must be read before trying to read the file.
Important fun fact about TCP: TCP is a stream, not a packet. Do not assume that because you wrote a number with send that the number is the only thing waiting to be read. For efficiency, TCP packs data together, so if you send "1234" and then a file 1234 bytes long, odds are pretty good both the file size and the file will arrive at the same time. So recv of 10 bytes will very likely read 1234, "1234"'s terminating null, and the first five bytes of the file. It's now up to you to separate the file length from the file data.
But if you send the length as a 32 bit integer, it will always be 4 bytes. Easy, yes? No. Because some computers and network protocols represent numbers backwards. I'm serious here. Google up endian.
Next: recv returns the number of bytes read. You may not get the number of bytes you asked for and have to keep asking until you get the while thing. recv also returns -1 if something goes wrong, so every time you recv, check that the return code is positive and that it's the number of bytes you need before doing anything with the data. Reading a 32 bit filesize, getting only 24 bits, and then trying to use those 24 bits to do meaningful work will really ruin your day.
And there's more! What if MAXCHARS is smaller than the size of the file? Well, that one is easy. You recv MAXCHARS or the number of bytes left in the file and write it out until the file is done.
So: