Winsock C ++ - медленное соединение с Java

Я использую сервер (C ++ Winsock) и клиент (Java) на своем ПК.

Я отправляю большой байтовый массив со своего клиента на сервер, и хотя передача завершается без ошибок, скорость передачи у меня очень низкая. Например, для массива размером 200 000 байт передача занимает 3-5 секунд (около 50 КБ / с).

Это нормально? Я не эксперт, но разве я не должен достигать гораздо большей скорости (около 1 Мбит / с) через локальную сеть?

Вот мой упрощенный код:

Клиент (Java)

    import ...

    public class Client {
        public static void main(String[] args) throws IOException {

            OutputStream outToServer;
            DataOutputStream out = null; 
            String serverHostname = new String ("...");
            int port = ...;

            Socket client = null;
            try {
                client = new Socket(serverHostname, port);
                outToServer = client.getOutputStream();
                out = new DataOutputStream(outToServer);

                int size = 200000;
                byte[] b = new byte[size];
                new Random().nextBytes(b);
                for(int i = 0 ; i < size ; i++){
                    out.writeByte(b[i]);
                }           
                out.close();
            } catch (UnknownHostException e) ...//Exit
              catch (IOException e) ...//Exit

            client.close();
        }
    }

и сервер (C ++, Winsock)

    #undef UNICODE
    #define WIN32_LEAN_AND_MEAN
    #include <windows.h>
    #include <winsock2.h>
    #include <ws2tcpip.h>...
    // Need to link with Ws2_32.lib
    #pragma comment (lib, "Ws2_32.lib")
    // #pragma comment (lib, "Mswsock.lib")
    #define DEFAULT_BUFLEN 512
    #define DEFAULT_PORT "..."

    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) //Return

        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) ...//Return

        // Create a SOCKET for connecting to server
        ListenSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
        if (ListenSocket == INVALID_SOCKET) ...//Return

        // Setup the TCP listening socket
        iResult = bind(ListenSocket, result->ai_addr, (int)result->ai_addrlen);
        if (iResult == SOCKET_ERROR) ...//Return

        freeaddrinfo(result);

        iResult = listen(ListenSocket, SOMAXCONN);
        if (iResult == SOCKET_ERROR) ...//Return

        // Accept a client socket
        ClientSocket = accept(ListenSocket, NULL, NULL);
        if (ClientSocket == INVALID_SOCKET) ...//Return

        // No longer need server socket
        closesocket(ListenSocket);
        // Receive until the peer shuts down the connection
        int bytes = 0;
        do {
            iResult = recv(ClientSocket, recvbuf, recvbuflen, 0);
            if (iResult > 0) 
                bytes += iResult;
            else if (iResult == 0)
                //Connection Closing
            else  
                ...//Return

        } while (iResult > 0);

        printf("Received %d bytes\n", bytes);

        ...//Shutdown and Return
    }

person Theo    schedule 31.05.2016    source источник
comment
вы чемпион, это был буферизованный вывод :) Новая скорость 64Мб / с ... в 1000 раз быстрее! Большое спасибо, я уже несколько дней занимаюсь устранением неполадок. Можете ли вы опубликовать его в качестве ответа, чтобы я мог его принять?   -  person Theo    schedule 31.05.2016
comment
Готово, рад помочь.   -  person    schedule 31.05.2016


Ответы (1)


Либо оберните свой OutputStream в BufferedOutputStream, либо просто буферизуйте свой вывод вручную (например, сначала собрав байты в массив, а затем используя _ 3_. Отправка пакета с каждым байтом обязательно будет очень медленной - см. Размер пустого пакета UDP и TCP?; пустой пакет TCP составляет 64 байта, то есть 64 + 1 байта отправляются для 1 байта данных, что дает вам ~ 1/65 от возможной скорости передачи (YMMV, вы можете увидеть еще большее увеличение скорости передачи из-за избавления от дополнительных тяжелых накладных расходов на виртуальную машину -> связь ОС для каждой отдельной команды writeByte).

Эмпирическое правило для прямой сетевой передачи состоит в том, что если вы намереваетесь отправить намного меньше, чем обычный пакет Ethernet (т. Е. Заметно меньше 1 КБ, например, 100 байт) повторно в течение короткого периода времени, это хороший идея сначала буферизовать его и отправить вместе.

person Community    schedule 31.05.2016