So, of course, the file is not complete, but the actual size (not size on disk) is exactly the same.
Here is the complete code of the server and client. In this example, I am copying the file from C:\temp\IMG_8526.jpg to E:\temp\newjpg.jpg.
SERVER:
#include <winsock2.h>
#include <windows.h>
#include <ws2tcpip.h>
#include <strsafe.h>
#include <process.h>
#include <mswsock.h>
#pragma comment(lib, "Ws2_32.lib")
#pragma comment(lib, "Mswsock.lib")
SOCKET SetUpListener(CONST CHAR *pcAddress, CONST INT nPort)
{
INT iBind = 0; ULONG nInterfaceAddr = 0;
inet_pton(AF_INET, pcAddress, &nInterfaceAddr);
if (nInterfaceAddr != INADDR_NONE)
{
SOCKET sd = socket(AF_INET, SOCK_STREAM, 0);
if (sd != INVALID_SOCKET)
{
sockaddr_in sinInterface;
sinInterface.sin_family = AF_INET;
sinInterface.sin_addr.s_addr = nInterfaceAddr;
sinInterface.sin_port = nPort;
iBind = bind(sd, (sockaddr*) &sinInterface, sizeof(sockaddr_in));
if (iBind != SOCKET_ERROR)
{
listen(sd, SOMAXCONN);
return sd;
}
}
}
return INVALID_SOCKET;
}
int readBytes(CONST SOCKET s, void *buffer, int buflen)
{
INT total = 0; UCHAR *pbuf = (UCHAR *) buffer;
while (buflen > 0)
{
INT iResult = recv(s, (CHAR *) pbuf, buflen, 0);
if (iResult < 0)
{
if (WSAGetLastError() == WSAEWOULDBLOCK)
continue;
return SOCKET_ERROR;
}
else if (iResult == 0)
return 0;
else
{
pbuf += iResult;
buflen -= iResult;
total += iResult;
}
}
return total;
}
BOOL ReceiveDoWorkThenReturnDataToClient(CONST SOCKET sd)
{
CHAR acReadBuffer[1024];
WCHAR sTempFileOut[MAX_PATH] = L"E:\\temp\\newjpg.jpg";
INT nReadBytes;
do
{
nReadBytes = recv(sd, acReadBuffer, 1024, 0);
if (nReadBytes > 0)
{
INT nSentBytes = 0;
while (nSentBytes < nReadBytes)
{
DeleteFile(sTempFileOut);
FILE* fp = NULL;
errno_t err = _wfopen_s(&fp, sTempFileOut, L"wb");
if (fp == NULL)
return 1;
ULONG FileSize;
int iResult = readBytes(sd, &FileSize, sizeof(FileSize));
if (iResult <= 0)
{
fclose(fp);
return 1;
}
FileSize = ntohl(FileSize);
CHAR mfcc[1024];
while (FileSize > 0)
{
int Received = readBytes(sd, mfcc, min(sizeof(mfcc), FileSize));
if (Received <= 0)
{
fclose(fp);
return 1;
}
if (fwrite(mfcc, 1, Received, fp) != Received)
{
fclose(fp);
return 1;
}
FileSize -= Received;
}
fflush(fp);
fclose(fp);
INT nTemp = send(sd, "1" + nSentBytes, (INT)strlen("1") - nSentBytes, 0);
if (nTemp > 0)
nSentBytes += nTemp;
else if (nTemp == SOCKET_ERROR)
break;
else
break;
}
}
else if (nReadBytes == SOCKET_ERROR)
return FALSE;
}
while (nReadBytes != 0);
return TRUE;
}
static BOOL ShutdownConnection(SOCKET sd)
{
CONST DWORD BUFFERSIZE = 4096;
if (shutdown(sd, SD_SEND) == SOCKET_ERROR)
return FALSE;
CHAR acReadBuffer[BUFFERSIZE];
while (1)
{
INT nNewBytes = recv(sd, acReadBuffer, BUFFERSIZE, 0);
if (nNewBytes == SOCKET_ERROR)
return FALSE;
else if (nNewBytes == 0)
break;
}
if (closesocket(sd) == SOCKET_ERROR)
return FALSE;
return TRUE;
}
static DWORD WINAPI ThreadHandler(void* sd_)
{
INT nRetval = 0;
SOCKET sd = (SOCKET) sd_;
if (!ReceiveDoWorkThenReturnDataToClient(sd))
nRetval = 3;
if (!ShutdownConnection(sd))
nRetval = 4;
return nRetval;
}
static unsigned WINAPI ListenAndAccept(void *)
{
sockaddr_in sinRemote;
INT nAddrSize = sizeof(sinRemote);
DWORD nThreadID;
SOCKET ListeningSocket = SetUpListener("localhost", htons(43210));
if (ListeningSocket == INVALID_SOCKET)
return 3;
while (1)
{
SOCKET sd = accept(ListeningSocket, (sockaddr*)&sinRemote, &nAddrSize);
if (sd != INVALID_SOCKET)
CreateThread(0, 0, &ThreadHandler, (void*)sd, 0, &nThreadID);
else
break;
}
return 0;
}
INT main()
{
WSADATA wsaData = { 0 };
if (WSAStartup(MAKEWORD(1, 1), &wsaData) != ERROR_SUCCESS) return 0;
UINT threadID = 0;
HANDLE hThread = (HANDLE)_beginthreadex(NULL, 0, &ListenAndAccept, NULL, 0, &threadID);
WaitForSingleObject(hThread, INFINITE);
CloseHandle(hThread);
while (1)
;
}
CLIENT (sends the jpg file to the server)
#include <winsock2.h>
#include <windows.h>
#include <mswsock.h>
#include <ws2tcpip.h>
#include <strsafe.h>
#include <windns.h>
#include <process.h>
#include <windns.h>
#pragma comment(lib, "Ws2_32.lib") // More than one instance overloaded function has C linkage
#pragma comment(lib, "dnsapi.lib") // needed for DnsFree API
int sendBytes(SOCKET s, void* buffer, int buflen)
{
INT total = 0;
unsigned char* pbuf = (unsigned char*)buffer;
while (buflen > 0)
{
int iResult = send(s, (char*)pbuf, buflen, 0);
if (iResult < 0)
{
if (WSAGetLastError() == WSAEWOULDBLOCK)
continue;
return SOCKET_ERROR;
}
else if (iResult == 0)
return 0;
else
{
pbuf += iResult;
buflen -= iResult;
total += iResult;
}
}
return total;
}
DWORD File_Transfer_Manip(SOCKET ConnectSocket, WCHAR *sFileToSend)
{
CHAR Buffer[1024];
DWORD dwWSA = 0;
FILE* fp = NULL;
errno_t err = _wfopen_s(&fp, sFileToSend, L"rb");
if (!fp)
return err;
fseek(fp, 0, SEEK_END);
ULONG FileSize = ftell(fp);
fseek(fp, 0, SEEK_SET);
ULONG tmpFileSize = htonl(FileSize);
int iResult = sendBytes(ConnectSocket, &tmpFileSize, sizeof(tmpFileSize));
if (iResult <= 0)
{
fclose(fp);
return 1;
}
while (FileSize > 0)
{
LONG Size = fread(Buffer, 1, min(sizeof(Buffer), FileSize), fp);
if (Size <= 0)
{
fclose(fp);
return 2;
}
if (sendBytes(ConnectSocket, Buffer, Size) != Size)
{
fclose(fp);
return 3;
}
FileSize -= Size;
}
fclose(fp);
return 0;
}
DWORD SendWinsockCommandToRemoteServer(CONST DWORD dwCharsAllocatedReturnString, WCHAR** sStringReturned)
{
SOCKET ConnectSocket = INVALID_SOCKET;
INT recvbuflen = 4096;
DWORD dwIPv4 = 0, dwErr = 0;
SecureZeroMemory(*sStringReturned, dwCharsAllocatedReturnString * sizeof(CHAR));
ConnectSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (ConnectSocket == INVALID_SOCKET)
return WSAGetLastError();
inet_pton(AF_INET, "127.0.0.1", &dwIPv4);
sockaddr_in clientService{};
clientService.sin_family = AF_INET;
clientService.sin_addr.s_addr = dwIPv4;
clientService.sin_port = htons(43210);
// If no error occurs, connect returns zero.
INT iResult = connect(ConnectSocket, (SOCKADDR*)&clientService, sizeof(clientService));
if ((iResult != 0) || (iResult == SOCKET_ERROR))
{
closesocket(ConnectSocket);
return 1;
}
DWORD dwResult = File_Transfer_Manip(ConnectSocket, L"c:\\temp\\IMG_8526.jpg");
iResult = shutdown(ConnectSocket, SD_SEND);
if (iResult == SOCKET_ERROR)
{
closesocket(ConnectSocket);
return 6;
}
closesocket(ConnectSocket);
return 0;
}
int main()
{
DWORD dwDataAllocatedSize = 1024;
DWORD dwErr = 0;
WCHAR* sData = new WCHAR[dwDataAllocatedSize]();
WCHAR* sRV = new WCHAR[dwDataAllocatedSize]();
WSADATA wsaData{};
INT iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
SendWinsockCommandToRemoteServer(dwDataAllocatedSize, &sRV);
delete[] sRV;
delete[] sData;
wprintf(L"Press any key to end."); getchar();
return 0;
}
Both are fully running examples. Any advice is appreciated on WHY the first part of the file isn't being copied? (looks like 4 characters when I bring it into Notepad++).
If I do copy the first four characters from the IMG_8526.jpg file into the newjpg.jpg file using Notepad++, then the image works.
in ReceiveDoWorkThenReturnDataToClient
, the value for iResult
the first time through is 4, so maybe that has to do with it?
This code was adapted from @RemyLebeau's reply at Winsock upload file to remote server