How to create a fast data transfer between two tcp sockets

51 Views Asked by At

Can someone please help on what I can do to make this simple TCP socket transfer code fast?

I have tried changing the buffer size and non blocking / blocking sockets. Nothing helps. It is much slower than a ssh tunnel. I only have 2 TCP sockets to deal with so I assume select() is not the issue. TRANSFER_BUFF_SIZE of 1000 seems to work the best. Have no idea why.

Thanks in advance

/* Sends data to the specified non blocking tcp socket. data_size is in bytes.
* Returns true if successful */
bool send_non_block_tcp_socket_data (int socket_id, void *data, int data_size)
{
  int i, n;
  fd_set write_fds, err_fds;
  timeval tv_delay;
  char *ptr;

  if (socket_id == -1) return false;
  ptr = (char*) data;

  tv_delay.tv_sec = 10;
  tv_delay.tv_usec = 0;

  i = 0;
  while (i < n)
  {
    FD_ZERO (&write_fds);             //clear set
    FD_SET (socket_id, &write_fds);   //add socket_id to set

    FD_ZERO (&err_fds);             //clear set
    FD_SET (socket_id, &err_fds);   //add socket_id to set

    while (select (socket_id + 1, NULL, &write_fds, &err_fds, &tv_delay) == 0)
    {
      tv_delay.tv_sec = 10;
      tv_delay.tv_usec = 0;
    }

    if (FD_ISSET (socket_id, &err_fds) != 0) return false;
    if (FD_ISSET (socket_id, &write_fds) != 0)
    {
      n = send (socket_id, &ptr[i], data_size - i, 0);
      if (n == -1) return false;
      i += n;
    }
  }
  return true;
}

/* Sets the tcp socket as non blocking */
bool set_tcp_socket_non_blocking (int socket_id)
{
  unsigned int op;

  op = fcntl (socket_id, F_GETFL);
  //sbit (&op, O_NONBLOCK);
  op = O_NONBLOCK;
  fcntl (socket_id, F_SETFL, op);
  return true;
}

/* Reads tty output into the specified buffer.
* Returns number of bytes read or -1 on error*/
int get_non_block_tcp_socket_data (int socket_id, char *buffer, int buffer_size)
{
  int n;

  if (socket_id == -1) return -1;
  if ((n = recv (socket_id, buffer, buffer_size, 0)) > 0) return n;
  if (errno == EAGAIN) return 0;  //no error, just no data
  return -1;
}

/* Waits for the specified tcp sockets to have data to be read.
* Returns socket that has data ready or -1 on error */
int wait_read_tcp_sockets (int socket_id, int socket_id2)
{
  int n, id;
  fd_set read_fds, err_fds;
  fd_set sid_set;
  timeval tv_delay;

  if (socket_id == -1) return -1;
  if (socket_id2 == -1) return -1;

  id = socket_id;
  if (id < socket_id2) id = socket_id2;
  while (true)
  {
    FD_ZERO (&read_fds);
    FD_SET (socket_id, &read_fds);
    FD_SET (socket_id2, &read_fds);

    FD_ZERO (&err_fds);
    FD_SET (socket_id, &err_fds);
    FD_SET (socket_id2, &err_fds);

    tv_delay.tv_sec = 10;
    tv_delay.tv_usec = 0;

    n = select (id + 1, &read_fds, NULL, &err_fds, &tv_delay);
    if (n != 0) break;
  }
  if (n > 0)
  {                       
    if (FD_ISSET (socket_id, &err_fds) != 0) return -1;
    if (FD_ISSET (socket_id2, &err_fds) != 0) return -1;

    if (FD_ISSET (socket_id, &read_fds) != 0) return socket_id;
    if (FD_ISSET (socket_id2, &read_fds) != 0) return socket_id2;
  }
  if (n < 0)
  {
    fprintf (stderr, "wait_read_tcp_sockets() select error\n");
  }
  return -1;
}

/* Transfers data between two TCP sockets
*
* Return true if successful */
bool transfer_data_tcp_sockets (int socket_id, int socket_id2)
{
  int n, si, read_sid, write_sid;
  char buffer[TRANSFER_BUFF_SIZE+4];
  bool read;

  set_tcp_socket_non_blocking (socket_id);
  set_tcp_socket_non_blocking (socket_id2);

  while (true)           
  {
    read = false;
    n = get_non_block_tcp_socket_data (socket_id2, buffer, TRANSFER_BUFF_SIZE);
    if (n < 0) return false;

    if (n > 0)
    {
      read = true;
      if (send_non_block_tcp_socket_data (socket_id, buffer, n) == -1) return false;
    }

    //--------

    n = get_non_block_tcp_socket_data (socket_id, buffer, TRANSFER_BUFF_SIZE);
    if (n < 0) return false;

    if (n > 0)
    {
      read = true;
      if (send_non_block_tcp_socket_data (socket_id2, buffer, n) == -1) return false;
    }

    if (!read)
    {
      while (true)
      {
        read_sid = wait_read_tcp_sockets (socket_id, socket_id2);
        if (read_sid == -1)
        {
          fprintf (stderr, "wait_read_tcp_sockets() error\n");
          return false;
        }
        else if (read_sid == socket_id) write_sid = socket_id2;
        else if (read_sid == socket_id2) write_sid = socket_id;
        else
        {
          fprintf (stderr, "wait_read_tcp_sockets() returned invalid socket %d\n",
                  read_sid);
          continue;
        }

        while (true)
        {
          n = get_non_block_tcp_socket_data (read_sid, buffer, TRANSFER_BUFF_SIZE);
          if (n < 0) return false;
          if (n > 0)
          {
            read = true;
            if (send_non_block_tcp_socket_data (write_sid, buffer, n) == -1) return false;
          }
          break;
        }
      }
    }
  }
  return true;
}

0

There are 0 best solutions below