Как выяснилось стэк 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