0

I have bought a VPS as a remote server and deployed shadowsocks as a proxy on this remote server.

Case 1:

When I use uTorrent to download files through shadowsocks, the speed could reach 10 MB/sec (which is 80 Mbits/sec). The diagram is:

 ---------------------------                    --------------------------      ---------
|    Local computer         |                  |   Remote server          |    |         |
|              ------------ |   80 Mbits/sec   |  -----------             |    |         |
| uTorrent<-->| shadowsocks||<---------------->| |shadowsocks|<--------------->|Internet |
|             |    client  ||                  | |  server   |            |    |         |
|              ------------ |                  |  -----------             |    |         |
 ---------------------------                    --------------------------      ---------

Case 2:

Now, I wrote a client/server program by C++. But the network speed is extremely low, and here is my test results:

Client: download speed

t_lRecvTotalBytes = 1024000 Bytes

t_lRecvTotalTime = 2942410 microseconds.

network speed: 2.7 MBit/s


Server: upload speed

t_lRecvTotalBytes = 1024000 Bytes

t_lRecvTotalTime = 1741625 microseconds.

network speed: 4.5 MBit/s

The diagram is:

 ---------------------------                    -------------------------- 
|    Local computer         |                  |   Remote server          |
|     ---------------       |2.7~4.5 Mbits/sec |  --------------          |
|    | My C++ client |<------------------------->| My C++ server|         |
|     ---------------       |                  |  --------------          |
|                           |                  |                          |
 ---------------------------                    --------------------------

Case 3:

iperf3 is used to test the bandwith between local computer and Remote server. And the result is:

[ ID] Interval Transfer Bitrate

[ 5] 0.00-10.00 sec 7.25 MBytes 6.08 Mbits/sec

[ 5] 10.00-20.00 sec 11.6 MBytes 9.73 Mbits/sec

[ 5] 20.00-30.00 sec 12.2 MBytes 10.3 Mbits/sec

[ 5] 30.00-40.00 sec 11.4 MBytes 9.53 Mbits/sec

[ 5] 40.00-50.00 sec 12.0 MBytes 10.0 Mbits/sec

[ 5] 50.00-60.00 sec 8.28 MBytes 6.94 Mbits/sec


[ ID] Interval Transfer Bitrate Retr

[ 5] 0.00-60.00 sec 62.9 MBytes 8.79 Mbits/sec 222 sender

[ 5] 0.00-60.00 sec 62.7 MBytes 8.77 Mbits/sec receiver

The diagram is:

 ---------------------------                    -------------------------- 
|    Local computer         |                  |   Remote server          |
|     ---------------       |   8.8 Mbits/sec  |  --------------          |
|    | iperf3 client |<------------------------->| iperf3 server|         |
|     ---------------       |                  |  --------------          |
|                           |                  |                          |
 ---------------------------                    --------------------------


MY CLIENT/SERVER CODE

server.cpp

#include <iostream>
#include <arpa/inet.h>
#include <string>
#include <chrono>
#include <unistd.h>
#include <stdlib.h>
#include <iomanip>
#include <signal.h>
#include <fcntl.h>

#define PORT        (7549)
#define CYCLE_TIME  (100)

int g_iSockFd;

void sigQuitHandler(int signal) {
    std::cout << "received SIGQUIT, doing graceful shutting down ..."
        << std::endl;
    close(g_iSockFd);
    exit(1);
}


void sigIntrHandler(int signal) {
    std::cout << "received SIGINT, doing graceful shutting down ..."
        << std::endl;
    close(g_iSockFd);
    exit(1);
}

/*
 * FUNCTION  :  enable or disable blocking of a file descriptor (socket)
 *   @PARAM  :  fd              file descriptor to be processed
 *   @PARAM  :  blocking        a bool flag to indicate blocking or non-blocking
 *                              true  ----> blocking
 *                              false ----> non-blocking
 *   @RETURN :  true on success
 *              false if there was an error
 */
bool SetSocketBlockingEnabled(int fd, bool blocking) {
    if (fd < 0) {
        return false;
    }
   int flags = fcntl(fd, F_GETFL, 0);
   if (flags == -1) {
       return false;
   }
   flags = blocking ? (flags & ~O_NONBLOCK) : (flags | O_NONBLOCK);
   return (fcntl(fd, F_SETFL, flags) == 0) ? true : false;
}


int main(int argc, char** argv) {
    // register signal handler function
    struct sigaction t_struQuitSigAction;
    struct sigaction t_struIntrSigAction;
    t_struQuitSigAction.sa_handler = sigQuitHandler;
    t_struQuitSigAction.sa_flags = 0;
    sigemptyset(&t_struQuitSigAction.sa_mask);
    sigaction(SIGQUIT, &t_struQuitSigAction, 0);
    t_struIntrSigAction.sa_handler = sigIntrHandler;
    t_struIntrSigAction.sa_flags = 0;
    sigemptyset(&t_struIntrSigAction.sa_mask);
    sigaction(SIGINT, &t_struIntrSigAction, 0);

    // init socket parameter
    char t_cRecvBuffer[102400];
    struct sockaddr_in t_struSockAddr;
    memset(&t_struSockAddr, 0, sizeof(t_struSockAddr));
    int t_iOpt = 1;
    // IPv4
    t_struSockAddr.sin_family = AF_INET;
    t_struSockAddr.sin_addr.s_addr = INADDR_ANY; // inet_addr("127.0.0.1");
    t_struSockAddr.sin_port = htons(PORT);
    // create socket
    int g_iSockFd = socket(AF_INET, SOCK_STREAM, 0);
    if (g_iSockFd == -1) {
        std::cout << "Error accurs when creating socket."
            << std::endl << "System exits abnormally." << std::endl;
        return -1;
    }
    int t_iError;
    if ((t_iError = setsockopt(g_iSockFd, SOL_SOCKET, SO_REUSEADDR,
                &t_iOpt, sizeof(t_iOpt))) < 0) {
        std::cout << "reuseaddr setsockopt fail. error = "
            << t_iError << std::endl;
        return -1;
    }
    if ((t_iError = setsockopt(g_iSockFd, SOL_SOCKET, SO_REUSEPORT,
                &t_iOpt, sizeof(t_iOpt))) < 0) {
        std::cout << "reuseport setsockopt fail. error = "
            << t_iError << std::endl;
        return -1;
    }
    SetSocketBlockingEnabled(g_iSockFd, true);
    if (bind(g_iSockFd, (struct sockaddr *)&t_struSockAddr,
                sizeof(t_struSockAddr)) < 0) {
        std::cout << "bind fail." << std::endl;
        return -1;
    }
    if (listen(g_iSockFd, 10) < 0) {
        std::cout << "listen fail." << std::endl;
        return -1;
    }
    int t_iNewSocket;
    while (1) {
        std::string t_strResponse(10240, 0);
        struct sockaddr_in t_struClientAddr;
        socklen_t t_ClientAddrLen = 0;
        memset(&t_struClientAddr, 0, sizeof(t_struClientAddr));
        if ((t_iNewSocket = accept(g_iSockFd,
                        (struct sockaddr*)&t_struClientAddr,
                        &t_ClientAddrLen)) < 0) {
            continue;
        }
        else {
            std::cout << "accept successfully." << std::endl;
        }

        // recv
        long t_lRecvTotalBytes = 0;
        long t_lRecvTotalTime = 0;
        double t_dSpeed = 0.0;
        std::chrono::high_resolution_clock::time_point t_StartTime;
        std::chrono::high_resolution_clock::time_point t_EndTime;
        bool t_bHasBegin = false;
        while (1) {
            int t_iRecvBytes = recv(t_iNewSocket, t_cRecvBuffer,
                    sizeof(t_cRecvBuffer), 0);
            if (t_iRecvBytes <= 0) {
                std::cout << "Error accurs when receiving. " << std::endl;
                break;
            }
            else {
                if (t_bHasBegin == false) {
                    t_bHasBegin = true;
                    t_StartTime = std::chrono::high_resolution_clock::now();
                }
                t_lRecvTotalBytes += t_iRecvBytes;
                std::string t_strRecv(t_cRecvBuffer, t_iRecvBytes);
                std::cout << "Receiving " << t_iRecvBytes << "/"
                    << t_lRecvTotalBytes
                    << " bytes. " << std::endl
                    << "Msg ends with: "
                    << int(t_strRecv[t_iRecvBytes - 1])
                    << std::endl;
                if (t_cRecvBuffer[t_iRecvBytes - 1] == 1) {
                    std::cout << "recv finished." << std::endl;
                    break;
                }
            }
        }
        t_EndTime = std::chrono::high_resolution_clock::now();
        t_lRecvTotalTime =
            std::chrono::duration_cast<std::chrono::microseconds>(
                t_EndTime - t_StartTime
            ).count();
        t_dSpeed = double(t_lRecvTotalBytes) / t_lRecvTotalTime
            * 1000000 * 8 / 1024 / 1024;
        std::cout << "t_lRecvTotalBytes = "
            << t_lRecvTotalBytes << " Bytes" << std::endl;
        std::cout << "t_lRecvTotalTime = "
            << t_lRecvTotalTime << " microseconds." << std::endl;
        std::cout << "network speed: "
            << std::setprecision(2)
            << t_dSpeed << " MBit/s" << std::endl;

        // response
        for (int i = 0; i < CYCLE_TIME; ++i) {
            if (i == CYCLE_TIME - 1) {
                t_strResponse[t_strResponse.size() - 1] = 1;
            }
            int t_iSendBytes = send(t_iNewSocket, t_strResponse.c_str(), \
                    t_strResponse.size(), 0);
            if (t_iSendBytes != t_strResponse.size()) {
                std::cout << "send error" << std::endl;
                return -1;
            }
            else {
                std::cout << "Send message successfully. "
                    << std::endl << "CNT = " << i << std::endl
                    << "size: " << t_iSendBytes << " Bytes." << std::endl;
            }
        }
        // close
        close(t_iNewSocket);
        std::cout << "t_lRecvTotalBytes = "
            << t_lRecvTotalBytes << " Bytes" << std::endl;
        std::cout << "t_lRecvTotalTime = "
            << t_lRecvTotalTime << " microseconds." << std::endl;
        std::cout << "network speed: "
            << std::setprecision(2)
            << t_dSpeed << " MBit/s" << std::endl;
    }
    return 0;
}


client.cpp


#include <iostream>
#include <arpa/inet.h>
#include <string>
#include <chrono>
#include <unistd.h>
#include <stdlib.h>
#include <iomanip>
#include <signal.h>

#define CYCLE_TIME      (100)
#define PORT            (7549)

#define LOCAL_MODE      (0)
#define REMOTE_MODE     (1)

int g_iSockFd;

void sigQuitHandler(int signal) {
    std::cout << "received SIGQUIT, doing graceful shutting down ..."
        << std::endl;
    close(g_iSockFd);
    exit(1);
}


void sigIntrHandler(int signal) {
    std::cout << "received SIGINT, doing graceful shutting down ..."
        << std::endl;
    close(g_iSockFd);
    exit(1);
}

int main(int argc, char** argv) {
    int t_iWorkMode = LOCAL_MODE;
    if (argc == 2) {
        int t_iTempWorkMode = atoi(argv[1]);
        switch (t_iTempWorkMode) {
            case LOCAL_MODE:
                t_iWorkMode = LOCAL_MODE;
                break;
            case REMOTE_MODE:
                t_iWorkMode = REMOTE_MODE;
                break;
            default:
                std::cout << "mode should be 1 or 2. LOCAL_MODE is used."
                    << std::endl;
                t_iWorkMode = LOCAL_MODE;
        }
    }
    // register signal handler function
    struct sigaction t_struQuitSigAction;
    struct sigaction t_struIntrSigAction;
    t_struQuitSigAction.sa_handler = sigQuitHandler;
    t_struQuitSigAction.sa_flags = 0;
    sigemptyset(&t_struQuitSigAction.sa_mask);
    sigaction(SIGQUIT, &t_struQuitSigAction, 0);
    t_struIntrSigAction.sa_handler = sigIntrHandler;
    t_struIntrSigAction.sa_flags = 0;
    sigemptyset(&t_struIntrSigAction.sa_mask);
    sigaction(SIGINT, &t_struIntrSigAction, 0);

    struct in_addr t_in_addr;
    memset(&t_in_addr, 0, sizeof(t_in_addr));
    if (inet_aton("127.0.0.1", &t_in_addr) == 0) {
        std::cout << "inet_aton fail." << std::endl;
        return -1;
    }

    std::string t_strMsg;
    char t_cRecvBuffer[102400];
    // init socket parameter
    struct sockaddr_in t_struSockAddr;
    memset(&t_struSockAddr, 0, sizeof(t_struSockAddr));
    // IPv4
    t_struSockAddr.sin_family = AF_INET;
    // remote IP address
    if (t_iWorkMode == REMOTE_MODE) {
        t_struSockAddr.sin_addr.s_addr = inet_addr("remote server IP address");
    }
    else {
        t_struSockAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
    }
    // remote port
    t_struSockAddr.sin_port = htons(PORT);
    // create socket
    int g_iSockFd = socket(AF_INET, SOCK_STREAM, 0);
    if (g_iSockFd == -1) {
        std::cout << "Error accurs when creating socket."
            << std::endl << "System exits abnormally." << std::endl;
        return -1;
    }
    if (connect(g_iSockFd, (struct sockaddr *)&t_struSockAddr, \
                sizeof(struct sockaddr)) < 0) {
        std::cout << std::endl
            << "Error accurs when connecting to server."
            << std::endl << "System exits abnormally." << std::endl;
        return -1;
    }
    std::cout << "Connected to remote server." << std::endl;

    int t_iSendBytes = 0;
    // send request
    t_strMsg = std::string(10240, 0);
    for (int i = 0; i < CYCLE_TIME; ++i) {
        // 1 means the end of message
        if (i == CYCLE_TIME - 1) {
            t_strMsg[t_strMsg.size() - 1] = 1;
        }
        t_iSendBytes = send(g_iSockFd, t_strMsg.c_str(), \
                t_strMsg.size(), 0);
        if (t_iSendBytes != t_strMsg.size()) {
            std::cout << "Request message is not "
                << "sent completely. System exits abnormally. "
                << "t_iSendBytes = " << t_iSendBytes << " Bytes. " << std::endl;
            return -1;
        }
        else {
            std::cout << "CNT = " << i << std::endl
                << "Msg ends with "
                << int(t_strMsg[t_strMsg.size() - 1]) << std::endl
                << "Send request message. Bytes: " << t_iSendBytes
                << std::endl;
        }
    }
    std::cout << "Send finished." << std::endl;

    std::cout << "Begin to receive ..." << std::endl;
    long t_lRecvTotalBytes = 0;
    long t_lRecvTotalTime = 0;
    double t_dSpeed = 0.0;
    std::chrono::high_resolution_clock::time_point t_StartTime;
    std::chrono::high_resolution_clock::time_point t_EndTime;
    t_StartTime = std::chrono::high_resolution_clock::now();
    memset(t_cRecvBuffer, 0, sizeof(t_cRecvBuffer));
    while (1) {
        int t_iRecvBytes = recv(g_iSockFd, t_cRecvBuffer, sizeof(t_cRecvBuffer), 0);
        if (t_iRecvBytes == -1) {
            std::cout << "Error accurs when receiving. "
                << std::endl << "System exits abnormally.";
            return -1;
        }
        else if (t_iRecvBytes > 0) {
            t_lRecvTotalBytes += t_iRecvBytes;
            std::string t_strRecv(t_cRecvBuffer, t_iRecvBytes);
            // std::cout << t_strRecv;
            std::cout << "Receiving " << t_iRecvBytes << "/"
                << t_lRecvTotalBytes << " bytes." << std::endl;
            // 1 means the end of message.
            if (t_cRecvBuffer[t_iRecvBytes - 1] == 1) {
                std::cout << "recv finished." << std::endl;
                break;
            }
        }
    }
    t_EndTime = std::chrono::high_resolution_clock::now();
    t_lRecvTotalTime =
        std::chrono::duration_cast<std::chrono::microseconds>(
            t_EndTime - t_StartTime
        ).count();
    t_dSpeed = double(t_lRecvTotalBytes) / t_lRecvTotalTime
        * 1000000 * 8 / 1024 / 1024;
    std::cout << "t_lRecvTotalBytes = "
        << t_lRecvTotalBytes << " Bytes" << std::endl;
    std::cout << "t_lRecvTotalTime = "
        << t_lRecvTotalTime << " microseconds." << std::endl;
    std::cout << "network speed: "
        << std::setprecision(2)
        << t_dSpeed << " MBit/s" << std::endl;
    // close
    close(g_iSockFd);
    return 0;
}

GOAL

The goal is that the network speed between my client and server program could reach about 80 Mbits/sec. But I cannot figure out a way to solve the problem. And the network speed tested by utorrent and iperf make me confused.

I will appreciate it if anyone can help me. Thank you!