Как подключиться к серверу, определив обе стороны портов, на C - PullRequest
0 голосов
/ 20 февраля 2011

Привет, люди!

Я пытаюсь сделать простую программу. Это отправить некоторую информацию на сервер к порту 80, но вопрос в том, что мне нужно указать порт отправителя (локальный), который я тоже должен использовать.

Использование языка c на машине с Ubuntu.

Ejample:

Мой ПК: (Порт 2000) -----------> Сервер: (Порт 80)

Я создал программу, но не работает, кто-нибудь может мне помочь, пожалуйста?

4 #include <stdio.h>
5 #include <string.h>
6 #include <sys/types.h>
7 #include <sys/socket.h>
8 #include <netdb.h>
9 #include <arpa/inet.h>
10
11 int main(int argc, char *argv[]) {
12
13   struct addrinfo server_hints;
14   struct addrinfo *server_res;
15   int    server_sockfd;
16   int    server_addrinfo;
17   int    server_bind;
18
19   struct addrinfo client_hints;
20   struct addrinfo *client_res;
21   int    client_sockfd;
22   int    client_addrinfo;
23   int    client_bind;
24
25   int    conn_info;
26
27   // Completamos la estrucctura de dirección del servidor con getaddrinfo():
28
29   memset(&server_hints, 0, sizeof (server_hints));
30   server_hints.ai_family   = AF_UNSPEC;     // Usa IPv4 or IPv6
31   server_hints.ai_socktype = SOCK_STREAM;   // TCP
32   server_hints.ai_flags    = AI_PASSIVE;    // Rellena la ip del server
33
34   server_addrinfo = getaddrinfo(NULL, "2000", &server_hints, &server_res);
35
36   if (server_addrinfo != 0){
37     fprintf(stderr, "Getaddrinfo server: %s\n", gai_strerror(server_addrinfo));
38     return 1;
39   }
40
41
42   // Crea la conexión del socket:
43
44   server_sockfd = socket(server_res->ai_family, server_res->ai_socktype, server_res->ai_protocol);
45
46   if (server_sockfd == -1){
47     fprintf(stderr, "Socket: %s\n", gai_strerror(server_sockfd));
48     return 1;
49   }
50
51
52   // Para eliminar esas veces que te pone que "Address already in use."
53
54   int yes=1;
55
56   if (setsockopt(server_sockfd,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(int)) == -1) {
57     perror("setsockopt");
58     return 1;
59   }
60
61
62   // Lo lincamos con el puerto que le pasamos en getaddrinfo():
63
64   server_bind = bind(server_sockfd, server_res->ai_addr, server_res->ai_addrlen);
65
66
67   if (server_bind == -1){
68     fprintf(stderr, "Socket: %s\n", gai_strerror(server_sockfd));
69     return 1;
70   }
71
72
73   // Completamos la estrucctura de dirección del cliente con getaddrinfo():
74   memset(&client_hints, 0, sizeof(client_hints));
75   client_hints.ai_family   = AF_UNSPEC;
76   client_hints.ai_socktype = SOCK_STREAM;
77
78   client_addrinfo = getaddrinfo("82.197.1.1", "80", &client_hints, &client_res);
79
80   if (client_addrinfo != 0){
81     fprintf(stderr, "Getaddrinfo server: %s\n", gai_strerror(client_addrinfo));
82     return 1;
83   }
84
85
86   conn_info = connect(server_sockfd, client_res->ai_addr, client_res->ai_addrlen);
87
88   if (conn_info == -1){
89     fprintf(stderr, "Connect: %s\n", gai_strerror(conn_info));
90     return 1;
91   }
92
93
94   char *men = "GET /index.php?uuu=hi&ppp=bye HTTP/1.0\r\nHost: %s\r\nUser-Agent: Mozilla/5.0\r\n\r\n"    ;
95
96   send(server_sockfd, men, strlen(men), 0);
97
98   // Limpiamos la conexiónes:
99
100   close(server_sockfd);
101   freeaddrinfo(server_res);
102   freeaddrinfo(client_res);

Спасибо за вашу помощь! : -)

Ответы [ 2 ]

1 голос
/ 21 мая 2011

Вам необходимо bind по адресу перед подключением. Если вы этого не сделаете, операционная система выберет подходящий source_address:source_port. Вот как ты мог это сделать.

Создать сокет

s = socket(AF_INET, SOCK_STREAM, 0);
if (-1 == s) {
    perror("socket");
    exit(1);
}

Инициализация структуры сервера sockaddr_in

memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(80);

if (1 != inet_pton(AF_INET, "192.168.1.1", &server_addr.sin_addr)) {
    perror("inet_pton");
    exit(1);
}

Инициализация структуры клиента sockaddr_in и привязка к ней

memset(&client_addr, 0, sizeof(client_addr));
client_addr.sin_family = AF_INET;
client_addr.sin_port = htons(22222);

if (bind(s, (struct sockaddr *) &client_addr, sizeof(client_addr)) < 0) {
    perror("bind");
    exit(1);
}

Подключите как обычно

if (connect(s, (struct sockaddr *) &server_addr, sizeof(server_addr)) < 0) {
    perror("connect");
    exit(1);
}

Другой возможностью было бы использование getaddrinfo для получения sockaddr для привязки.

memset(&hints, 0, sizeof(hints));
hints.ai_socktype = SOCK_STREAM;
hints.ai_family = AF_UNSPEC;        /* Both v4 and v6.*/
hints.ai_flags = AI_PASSIVE;

rc = getaddrinfo(addr, port, &hints, &result);
if (rc)
    return -1;

for (rp = result; rp != NULL; rp = rp->ai_next) {
    rc = bind(s, rp->ai_addr, rp->ai_addrlen);
    if (!rc)
        break;
    /* Otherwise move on. */
}

Используйте tcpdump(1), чтобы убедиться, что он устанавливает порт источника для ваших сегментов.

0 голосов
/ 20 февраля 2011

При использовании TCP-соединений вы можете использовать connect и write для записи в сокет (обычно используется только отправка для UDP-соединений).Вы можете использовать read на сокете, чтобы прочитать ответ.При использовании запись в сокет, возвращаемый accept на сервере, автоматически отправит сообщение обратно (при условии, что соединение все еще открыто), поэтому вам не нужно сообщать серверу отправителяхост и порт.

...