Date Tags tcp

Как выяснилось стэк TCP/IP Linux-3.3.8 идентифицирует соединение не только по локальному адресу, но и по удалённому. Следовательно можно использовать несколько сокетов, забинденных на один локальный арес, но соединенных с разными удалёнными адресами. Проверим данную гипотезу. Для этого получим 5 HTML страниц с www.afrinic.net www.lacnic.net www.arin.net www.ripe.net и www.apnic.net по протоколу HTTP с сокетов, забинденных на один адрес.

#include <nx_socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <pthread.h>

struct sockaddr_in local_addr;
const char buf[] = "GET / HTTP/1.1\r\nHost: \r\n\r\n";

struct args_s
{
  SOCKET sock;
  const char * addr;
};

void* test(void * args)
{
  SOCKET sock = ((struct args_s*)args)->sock;
  const char * addr = ((struct args_s*)args)->addr;
  struct pollfd fd[1];
  struct sockaddr_in rpeer;
  FILE * file;
  int rs;
  memset(&rpeer, 0, sizeof(rpeer));
  rpeer.sin_addr.s_addr = inet_addr(addr);
  rpeer.sin_port = htons(80);
  rpeer.sin_family = AF_INET;
  if(!IS_VALID_SOCK(sock) )
  {
          perror("Error calling socket");
          return;
  }
  if(SetNonBlock(sock) < 0)
  {
          perror("Error setting nonblock");
          return;
  }
  if(SetReusable(sock) < 0)
  {
          perror("Error setting reusable");
          return;
  }
  if(bind(sock, (struct sockaddr*)&local_addr, sizeof(local_addr)) < 0 )
  {
          perror("Error binding.");
          return;
  }
  if( connect(sock, (struct sockaddr*)&rpeer, sizeof(rpeer)) < 0 )
  {
          if(errno != EINPROGRESS)
          {
                  perror("Error connecting.");
                  return;
          }
  }

  // ждем, когда можно будет посылать
  fd[0].fd = sock;
  fd[0].events = POLLOUT;
  rs = poll(fd, 1, 5000);
  if(rs < 0)
  {
          perror("Error sending.");
          return;
  }
  if(rs == 0)
  {
          perror("Sending timeout.");
          return;
  }
  if( send(sock, buf, sizeof(buf), 0) != sizeof(buf) )
  {
          perror("Error calling send.");
          shutdown(sock, SHUT_RDWR);
          close(sock);
          return;
  }

  file = fopen(addr, "w");
  if(!file)
  {
          perror("Error file opening.");
          shutdown(sock, SHUT_RDWR);
          close(sock);
          return;
  }

  // ждем, когда можно будет получать
  while(1)
  {
          char buf[10000];
          memset(buf, 0, sizeof(buf));
          int rs = 0;
          memset(fd, 0, sizeof(fd));
          fd[0].fd = sock;
          fd[0].events = POLLIN | POLLPRI;
          if(rs = poll(fd, 1, 15000))
          {
                  if(rs < 0)
                  {
                          perror("Error calling poll");
                          exit(1);
                  }
                  else if(rs == 0)
                  {
                          shutdown(sock, SHUT_RDWR);
                          close(sock);
                          close(file);
                          return;
                  }
                  if((rs = recv(sock, buf, sizeof(buf), 0)) < 0)
                  {
                          perror("Error data receiving");
                          shutdown(sock, SHUT_RDWR);
                          close(sock);
                          close(file);
                          return;
                  }
                  if(rs == 0)
                  {
                          shutdown(sock, SHUT_RDWR);
                          close(sock);
                          close(file);
                          return;
                  }
                  fprintf(file, "%s", buf);
          }
  }
}

int main(int argc, char * argv[])
{
  pthread_t t1, t2, t3, t4, t5;
  struct args_s sa1, sa2, sa3, sa4, sa5;
  int rs1, rs2, rs3, rs4, rs5;
  char a1[] = "196.216.2.136\0";
  char a2[] = "200.3.14.147\0";
  char a3[] = "192.149.252.76\0";
  char a4[] = "193.0.6.139\0";
  char a5[] = "202.12.29.211\0";
  sa1.addr = a1;
  sa2.addr = a2;
  sa3.addr = a3;
  sa4.addr = a4;
  sa5.addr = a5;
  SOCKET s1, s2, s3, s4, s5;
  if(argc < 3)
  {
          printf("Usage: %s <local_ip> <local_port>", argv[0]);
          return 0;
  }
  memset(&local_addr, 0, sizeof(local_addr));
  local_addr.sin_family = AF_INET;
  local_addr.sin_addr.s_addr = inet_addr("");
  local_addr.sin_port = 22765;
  sa1.sock = socket(local_addr.sin_family, SOCK_STREAM, 0);
  sa2.sock = socket(local_addr.sin_family, SOCK_STREAM, 0);
  sa3.sock = socket(local_addr.sin_family, SOCK_STREAM, 0);
  sa4.sock = socket(local_addr.sin_family, SOCK_STREAM, 0);
  sa5.sock = socket(local_addr.sin_family, SOCK_STREAM, 0);

  pthread_create(&t1, NULL, test, &sa1);
  pthread_create(&t2, NULL, test, &sa2);
  pthread_create(&t3, NULL, test, &sa3);
  pthread_create(&t4, NULL, test, &sa4);
  pthread_create(&t5, NULL, test, &sa5);

  pthread_join(t1, NULL);
  pthread_join(t2, NULL);
  pthread_join(t3, NULL);
  pthread_join(t4, NULL);
  pthread_join(t5, NULL);

  return 0;
}

Указанный выше код прекрасно работает на Gentoo с ядром Linux-3.3.8

TODO:Проверить на винде

Comments

comments powered by Disqus