2013-03-28 4 views
3

Я новичок здесь (мой первый вопрос) и немного нового, у меня никогда не было классов программирования, поэтому ... извините за какой-то хаотичный код.Отправка файлов через сокеты слишком медленно

Я сделал эту программу, которая отправляет (клиент) и получает (сервер) файлы через сокеты, клиент считывает и отправляет 1024 байта файла за цикл, а сервер его получает и записывает в файл. Он работает нормально, но проблема в том, что он очень медленный. Это занимает столько времени, что отправляет файл с моего компьютера на компьютер как отправку на другой компьютер, но все равно занимает больше времени, чем ожидалось, когда я пытаюсь передать, например, через skype, это намного быстрее. Любая подсказка? (Ниже приведен код, который я использую).

Сервер:

// 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; 
} 

Клиент:

// 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; 
} 

Я использую Visual Studio 2010 на окнах 7.

Цените любую помощь, а также дайте мне знать, если есть что-то неправильно со структурой этого вопроса.

+2

Первое - ваш размер буфера составляет всего 512 байт, что очень мало. Просто попробуйте изменить его на 65536 и посмотреть, какой эффект он имеет. Существует некоторый физический размер, который наиболее подходит, если это помогает ... –

+0

Просто попробовал и не имеет никакого эффекта. – user2220419

+0

Вы изменили свой 'send', чтобы читать и отправлять более 1024 байтов за раз, правильно? –

ответ

1

Для эффективной отправки файлов через сокет Windows предоставляет функцию TransmitFile.

+0

Я попробовал это на стороне клиента (серверная сторона остается той же) \t HANDLE hFile = CreateFile (argv [1], GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); \t // WaitForSingleObject (hFile, INFINITE); \t, если (hFile == INVALID_HANDLE_VALUE) \t \t { \t \t \t DisplayError (ТЕКСТ ("CreateFile")); \t \t \t _tprintf (ТЕКСТ («Сбой терминала: невозможно открыть файл»% s \ »для чтения. \ N"), argv [1]); \t \t \t возвращение; \t \t} \t TransmitFile (ConnectSocket, \t hFile, \t 0, \t 0, \t NULL, NULL, \t, \t TF_DISCONNECT); \t CloseHandle (hFile); Это примерно такая же скорость. – user2220419

+0

@ user2220419: Может быть, ваш диск является ограничением? Поворот дисков при отправке с этого компьютера сам по себе должен иметь доступ к двум файлам одновременно (тот, который читается, и тот, который записывается). Это означает, что диск проводит большую часть своего времени, двигаясь вперед и назад между ними. Я не думаю, что это ваша проблема, но если вы можете настроить Ramdisk и снова попробовать его использовать, это точно сообщит нам. –

+0

Я пробовал через TransmiteFile, и он прошел ту же скорость, я думаю, что это будет так быстро, как только может. Спасибо за помощь. – user2220419

1

Skype, вероятно, сжимает файл, что значительно ускорит передачу по сети. Вы можете сжать встроенную строку с помощью zlib или реализовать свои собственные из многих общедоступных (кодировка Хаффмана и т. Д.).

BTW, изменение размеров буфера не сильно изменит производительность. Основные API (файл, сокет) были оптимизированы для автоматической обработки буферизации независимо от того, как вы читаете/записываете их.

0

Сначала запустите Wireshark и получите следы сетевых сообщений. Я ожидаю, что вы страдаете от размера окна TCP по умолчанию, вызывая ненужное управление потоком.

Взгляните на эти ответы, которые могут помочь:

Смежные вопросы