Reputation: 31
I'm new here (my first question) and a bit of a newbe, I've never had programming classes so... sorry for some chaotic code.
I made this program that sends (client) and receives (server) files through sockets, the client reads and sends 1024 bytes of a file per loop and the server receives it and writes it on the file. It works fine but the problem is that it is very slow. It takes as much time sending a file from my computer to my computer as sending to another computer, but still takes more time than expected, when i try to transfer, for example, through skype it's a lot faster. Any clue? (Below there is the code I'm using).
Server:
// servrecvfile.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#undef UNICODE
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdlib.h>
#include <stdio.h>
// Need to link with Ws2_32.lib
#pragma comment (lib, "Ws2_32.lib")
// #pragma comment (lib, "Mswsock.lib")
#define DEFAULT_BUFLEN 65536
#define DEFAULT_PORT "8883"
typedef struct thread_args{
SOCKET ClientSocket;
int index;
} *MYDATA, PM;
MYDATA pDataArray[100];
DWORD WINAPI abc(void*);
int p=0;
int abz(){
return p;
}
void broadcast(MYDATA *fp, char *b, int index){
for(int i=0; i<=abz(); i++){
if(index != i)
send( fp[i]->ClientSocket, b, (int)strlen(b), 0 );
}
}
DWORD WINAPI abc(void* pVoid)
{
struct thread_args *fp;
fp = (struct thread_args *) pVoid;
long iResult;
int filesize;
unsigned char recvbuf[ DEFAULT_BUFLEN];
memset(recvbuf, 0, sizeof(recvbuf));
recv(fp->ClientSocket, (char*)recvbuf, DEFAULT_BUFLEN, 0);
FILE *abc = fopen(strtok ((char*)recvbuf,":"), "wb");
filesize = atoi(strtok (NULL,":"));
memset(recvbuf, 0, sizeof(recvbuf));
int perc=0;
int perc2=0;
int counter=0;
char a = '%';
do {
iResult = recv(fp->ClientSocket, (char*)recvbuf, DEFAULT_BUFLEN, 0);
if (iResult > 0) {
counter += fwrite (recvbuf , sizeof(char) , iResult , abc );
memset(recvbuf, 0, sizeof(recvbuf));
perc2 = ((counter*1.000)/filesize*1.000)*100;
if(perc2 != perc){
printf("%d%c\n", perc2, a);
perc = perc2;
}
}
else if (iResult == 0)
printf("Connection closing...\n");
else {
printf("recv failed with error: %d\n", WSAGetLastError());
closesocket(fp->ClientSocket);
fclose(abc);
WSACleanup();
ExitThread(1);
}
} while (iResult > 0);
fclose(abc);
ExitThread(-1);
}
int __cdecl main(void)
{
WSADATA wsaData;
int iResult;
SOCKET ListenSocket = INVALID_SOCKET;
SOCKET ClientSocket = INVALID_SOCKET;
struct addrinfo *result = NULL;
struct addrinfo hints;
int iSendResult;
char recvbuf[DEFAULT_BUFLEN];
int recvbuflen = DEFAULT_BUFLEN;
// Initialize Winsock
iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
if (iResult != 0) {
printf("WSAStartup failed with error: %d\n", iResult);
return 1;
}
ZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
hints.ai_flags = AI_PASSIVE;
// Resolve the server address and port
iResult = getaddrinfo(NULL, DEFAULT_PORT, &hints, &result);
if ( iResult != 0 ) {
printf("getaddrinfo failed with error: %d\n", iResult);
WSACleanup();
return 1;
}
// Create a SOCKET for connecting to server
ListenSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
if (ListenSocket == INVALID_SOCKET) {
printf("socket failed with error: %ld\n", WSAGetLastError());
freeaddrinfo(result);
WSACleanup();
return 1;
}
// Setup the TCP listening socket
iResult = bind( ListenSocket, result->ai_addr, (int)result->ai_addrlen);
if (iResult == SOCKET_ERROR) {
printf("bind failed with error: %d\n", WSAGetLastError());
freeaddrinfo(result);
closesocket(ListenSocket);
WSACleanup();
return 1;
}
freeaddrinfo(result);
iResult = listen(ListenSocket, SOMAXCONN);
if (iResult == SOCKET_ERROR) {
printf("listen failed with error: %d\n", WSAGetLastError());
closesocket(ListenSocket);
WSACleanup();
return 1;
}
int i=0;
while(1){
// Accept a client socket
ClientSocket = accept(ListenSocket, NULL, NULL);
if (ClientSocket == INVALID_SOCKET) {
printf("accept failed with error: %d\n", WSAGetLastError());
closesocket(ListenSocket);
WSACleanup();
return 1;
}
pDataArray[i] = (MYDATA) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
sizeof(PM));
pDataArray[i]->ClientSocket = ClientSocket;
pDataArray[i]->index = i;
CreateThread(
NULL, // default security attributes
0, // use default stack size
abc, // thread function name
pDataArray[i], // argument to thread function
0, // use default creation flags
NULL); // returns the thread identifier
p = i;
i++;
}
// No longer need server socket
closesocket(ListenSocket);
// Receive until the peer shuts down the connection
//char a[DEFAULT_BUFLEN];
// shutdown the connection since we're done
iResult = shutdown(ClientSocket, SD_SEND);
if (iResult == SOCKET_ERROR) {
printf("shutdown failed with error: %d\n", WSAGetLastError());
closesocket(ClientSocket);
WSACleanup();
return 1;
}
// cleanup
closesocket(ClientSocket);
WSACleanup();
return 0;
}
Client:
// sendfile.cpp : Defines the entry point for the console application.
//
#include "StdAfx.h"
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
// Need to link with Ws2_32.lib, Mswsock.lib, and Advapi32.lib
#pragma comment (lib, "Ws2_32.lib")
#pragma comment (lib, "Mswsock.lib")
#pragma comment (lib, "AdvApi32.lib")
#define DEFAULT_BUFLEN 65536
#define DEFAULT_PORT "8882"
int __cdecl main(int argc, char **argv)
{
WSADATA wsaData;
SOCKET ConnectSocket = INVALID_SOCKET;
struct addrinfo *result = NULL,
*ptr = NULL,
hints;
char *sendbuf = "this is a test";
char recvbuf[DEFAULT_BUFLEN];
int iResult;
int recvbuflen = DEFAULT_BUFLEN;
char linha[DEFAULT_BUFLEN];
char IP[20], porta[10];
FILE *fp1;
fp1 = fopen("config.txt", "r");
if(fp1 == NULL)
{
printf("Unable to find config.txt.\n");
exit(-1);
}
while( fgets(linha,DEFAULT_BUFLEN, fp1) !=NULL){
if(strstr(linha, "port="))
sscanf(linha, "port=%s", porta);
if(strstr(linha, "ip="))
sscanf(linha, "ip=%s", IP);
}
fclose(fp1);
char filenam[DEFAULT_BUFLEN];
printf("Insert file name: ");
scanf ("%s", filenam);
FILE *trans = fopen(filenam, "rb");
if(trans == NULL)
{
printf("File not found\n");
exit(-1);
}
// Initialize Winsock
iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
if (iResult != 0) {
printf("WSAStartup failed with error: %d\n", iResult);
return 1;
}
ZeroMemory( &hints, sizeof(hints) );
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
// Resolve the server address and port
iResult = getaddrinfo(IP, porta, &hints, &result);
if ( iResult != 0 ) {
printf("getaddrinfo failed with error: %d\n", iResult);
WSACleanup();
return 1;
}
// Attempt to connect to an address until one succeeds
for(ptr=result; ptr != NULL ;ptr=ptr->ai_next) {
// Create a SOCKET for connecting to server
ConnectSocket = socket(ptr->ai_family, ptr->ai_socktype,
ptr->ai_protocol);
if (ConnectSocket == INVALID_SOCKET) {
printf("socket failed with error: %ld\n", WSAGetLastError());
WSACleanup();
return 1;
}
// Connect to server.
iResult = connect( ConnectSocket, ptr->ai_addr, (int)ptr->ai_addrlen);
if (iResult == SOCKET_ERROR) {
closesocket(ConnectSocket);
ConnectSocket = INVALID_SOCKET;
continue;
}
break;
}
freeaddrinfo(result);
if (ConnectSocket == INVALID_SOCKET) {
printf("Unable to connect to server!\n");
WSACleanup();
return 1;
}
long lSize;
// obtain file size:
fseek (trans , 0 , SEEK_END);
lSize = ftell (trans);
rewind (trans);
char a = '%';
// allocate memory to contain the whole file:
memset(recvbuf, 0, sizeof(recvbuf));
unsigned char *linha2 = (unsigned char*) malloc (sizeof(unsigned char)* DEFAULT_BUFLEN);
//send(ConnectSocket, filenam, (int)strlen(filenam), 0 );
sprintf(filenam, "%s:%d", filenam, lSize);
printf("%d %d\n", send(ConnectSocket, filenam, (int)strlen(filenam), 0 ), lSize);
long counter=0;
long read;
int perc=0;
int perc2=0;
while(counter < lSize){
read = fread_s(linha2, DEFAULT_BUFLEN, sizeof(char), DEFAULT_BUFLEN, trans);
counter += send(ConnectSocket, (char*)linha2, read, 0);
perc2 = ((counter*1.000)/lSize*1.000)*100;
if(perc2 != perc){
printf("%d%c\n", perc2, a);
perc = perc2;
}
}
fclose(trans);
/*
do {
//memset(a, 0, sizeof(a));
iResult = recv(ConnectSocket, recvbuf, recvbuflen, 0);
if ( iResult > 0 )
{
printf("%s", recvbuf);
memset(recvbuf, 0, sizeof(recvbuf));
}
else if ( iResult == 0 )
printf("Connection closed\n");
else
printf("recv failed with error: %d\n", WSAGetLastError());
} while( iResult > 0 ); */
// cleanup
closesocket(ConnectSocket);
WSACleanup();
return 0;
}
I'm using visual studio 2010 on windows 7.
Appreciate any help and also let me know if there is anything wrong with the structure of this question.
Upvotes: 3
Views: 3145
Reputation: 21644
First run Wireshark and get a trace of the network communications. I expect you're suffering from the default TCP Window Size causing unnecessary flow control.
Take a look at these answers which may help:
Upvotes: 0
Reputation:
Skype is likely compressing the file, which would significantly speed up a network transfer. You can compress inline using zlib or implement your own from the many publicly available ones (Huffman encoding, etc.).
BTW, changing the buffer sizes won't change performance much. The underlying APIs (file, socket) have been optimized to automatically handle buffering independent of how you read from/write to them.
Upvotes: 1
Reputation: 283733
For efficiently sending file data through a socket, Windows provides the TransmitFile function.
Upvotes: 1