Внедрение протокола синхронизации с клиент-сервером UDP, позволяющего изменить порт - PullRequest
0 голосов
/ 03 ноября 2019

У меня есть UDP-клиент и сервер, с которыми я работаю. Основная идея заключается в том, что я хочу иметь сокет специально для целей синхронизации, я хочу установить «трехстороннее рукопожатие» до того, как между двумя кодами произойдет обмен какими-либо фактическими данными.

То, что у меня естьэто создать 2 сокета на стороне сервера, один для синхронизации и один для данных. У вас должен быть один сокет на стороне клиента и использовать сообщения синхронизации для изменения порта клиентского сокета для связи с сокетом данных на стороне сервера. Как только все это будет сделано, технически и клиент, и сервер должны по-прежнему иметь возможность обмениваться данными так, как им предназначено. В моем случае на данный момент это просто эхо-сервер.

Вот два кода: client.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#define BUFFER_SIZE 1024

int main(int argc, char* argv[])
{
    int port_sync, port_data;
    char addr[15];
    if (argc < 3)
    {
        printf("Too few arguments given.\n");
        printf("Format: ./client adresseIP port\n");
        exit(1);
    }
    else if (argc > 3)
    {
        printf("Too many arguments given.\n");
        printf("Format: ./client adresseIP port\n");
        exit(1);
    }
    else
    {
        strcpy(addr, argv[1]);
        port_sync = atoi(argv[2]);
    }

    // SYNCHRONIZATION SOCKET

    int socket_sync_fd; 
    socklen_t socket_length;
    struct sockaddr_in server_sync_addr, client_addr;
    memset((char*)&server_sync_addr, 0, sizeof(server_sync_addr));

    if ((socket_sync_fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
    {
        perror("[-] Connection error");
        exit(1);
    }
    printf("[+] Client synchronization socket created\n");

    int reuse_sync = 1;
    setsockopt(socket_sync_fd, SOL_SOCKET, SO_REUSEADDR, &reuse_sync, sizeof(reuse_sync));

    server_sync_addr.sin_family = AF_INET;
    server_sync_addr.sin_port = htons(port_sync);
    inet_aton(addr, &server_sync_addr.sin_addr);

    // SYNCHRONIZATION

    char syn[BUFFER_SIZE];
    strcpy(syn, "SYN");
    sendto(socket_sync_fd, syn, strlen(syn), 0, (struct sockaddr *) &server_sync_addr, sizeof(server_sync_addr));
    memset(syn, 0, BUFFER_SIZE);

    recvfrom(socket_sync_fd, syn, BUFFER_SIZE, 0, (struct sockaddr *) &server_sync_addr, &socket_length);
    char delim[] = "-";
    char port[20];
    char *ptr = strtok(syn, delim); // ptr = "SYN"
    ptr = strtok(NULL, delim);      // ptr = "ACK"
    ptr = strtok(NULL, delim);      // ptr = port_data
    strcpy(port, ptr);
    port_data = atoi(port);
    printf("new port: %d\n", port_data);
    memset(syn, 0, BUFFER_SIZE);

    strcpy(syn, "ACK");
    sendto(socket_sync_fd, syn, strlen(syn), 0, (struct sockaddr *) &server_sync_addr, sizeof(server_sync_addr));
    memset(syn, 0, BUFFER_SIZE);

    printf("[+] Synchronization successful\n");

    server_sync_addr.sin_port = htons(port_data);

    int recvfrom_return;
    char buffer[BUFFER_SIZE];

    while (1)
    {
        printf("UDP Client: ");
        fgets(buffer, BUFFER_SIZE, stdin);
        buffer[strcspn(buffer, "\n")] = 0;
        sendto(socket_sync_fd, buffer, sizeof(buffer), 0, (struct sockaddr *) &server_sync_addr, sizeof(server_sync_addr));

        if (strcmp(buffer, ":exit") == 0)
        {
            close(socket_sync_fd);
            printf("[-] Disconnected from server\n");
            exit(1);
        }

        if ((recvfrom_return = recvfrom(socket_sync_fd, buffer, sizeof(buffer), 0, (struct sockaddr *) &client_addr, &socket_length)) < 0)
        {
            perror("[-] Data reception error");
        }
        else
        {
            buffer[recvfrom_return] = 0;
            printf("Server: %s\n", buffer);
        }
    }
    return 0;
}

server.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <sys/time.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#define BUFFER_SIZE 1024

int main(int argc, char* argv[])
{
    int port_sync, port_data;

    if (argc < 3)
    {
        printf("Too few arguments given.\n");
        printf("Format: ./server port_sync port_data\n");
        exit(1);
    }
    else if (argc > 3)
    {
        printf("Too many arguments given.\n");
        printf("Format: ./server port_sync port_data\n");
        exit(1);
    }
    else
    {
        port_sync = atoi(argv[1]);
        port_data = atoi(argv[2]);
    }

    // SYNCHRONIZATION SOCKET

    fd_set socket_fd_set;
    FD_ZERO(&socket_fd_set);

    int socket_sync_fd, socket_data_fd; 
    socklen_t socket_length;
    struct sockaddr_in server_sync_addr, server_data_addr, client_addr;
    memset((char*)&server_sync_addr, 0, sizeof(server_sync_addr));

    if ((socket_sync_fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
    {
        perror("[-] Connection error");
        exit(1);
    }
    printf("[+] Synchronization socket created.\n");

    server_sync_addr.sin_family = AF_INET;
    server_sync_addr.sin_port = htons(port_sync);
    server_sync_addr.sin_addr.s_addr = INADDR_ANY;

    if (bind(socket_sync_fd, (struct sockaddr*) &server_sync_addr, sizeof(server_sync_addr)) < 0)
    {
        perror("[-] Bind error");
        exit(1);
    }
    printf("[+] Bind synchronization socket to port %d.\n", port_sync);

    int reuse_sync = 1;
    setsockopt(socket_sync_fd, SOL_SOCKET, SO_REUSEADDR, &reuse_sync, sizeof(reuse_sync));

    int recvfrom_return;
    char buffer[1024];

    while (1)
    {
        FD_SET(socket_sync_fd, &socket_fd_set);
        FD_SET(socket_data_fd, &socket_fd_set);
        int select_return = select(10, &socket_fd_set, NULL, NULL, NULL);

        if(select_return < 0)
        {
            perror("[-] Select error");
            exit(1);
        }

        if(FD_ISSET(socket_sync_fd, &socket_fd_set))
        {
            // SYNCHRONIZATION

            char syn[BUFFER_SIZE];
            char temp[25];
            recvfrom(socket_sync_fd, syn, BUFFER_SIZE, 0, (struct sockaddr *) &client_addr, &socket_length);
            memset(syn, 0, BUFFER_SIZE);

            snprintf(temp, sizeof(temp), "SYN-ACK-%d", port_data);
            strcpy(syn, temp);
            sendto(socket_sync_fd, syn, BUFFER_SIZE, 0, (struct sockaddr *) &client_addr, socket_length);
            memset(syn, 0, BUFFER_SIZE);

            recvfrom(socket_sync_fd, syn, BUFFER_SIZE, 0, (struct sockaddr *) &client_addr, &socket_length);
            memset(syn, 0, BUFFER_SIZE);

            printf("[+] Synchronization successful\n");
        }

        if(FD_ISSET(socket_data_fd, &socket_fd_set)){

            if ((socket_data_fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
            {
                perror("[-] Connection error");
                exit(1);
            }
            printf("[+] Data socket created.\n");

            server_data_addr.sin_family = AF_INET;
            server_data_addr.sin_port = htons(port_data);
            server_data_addr.sin_addr.s_addr = INADDR_ANY;

            if (bind(socket_data_fd, (struct sockaddr*) &server_data_addr, sizeof(server_data_addr)) < 0)
            {
                perror("[-] Bind error");
                exit(1);
            }
            printf("[+] Bind synchronization socket to port %d.\n", port_data);

            int reuse_data = 1;
            setsockopt(socket_data_fd, SOL_SOCKET, SO_REUSEADDR, &reuse_data, sizeof(reuse_data));

            recvfrom_return = recvfrom(socket_data_fd, buffer, sizeof(buffer), 0, (struct sockaddr *) &client_addr, &socket_length); 
            if (strcmp(buffer, ":exit") == 0)
            {
                printf("[-] Disconnected from %s:%d\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
                close(socket_data_fd);
                break;
            }
            else
            {
                printf("UDP Client: %s\n", buffer);
                sendto(socket_data_fd, buffer, recvfrom_return, 0, (struct sockaddr *) &client_addr, socket_length);
                memset(buffer, 0, sizeof(buffer));
                bzero(buffer, sizeof(buffer));
            }
        }
    }
    close(socket_sync_fd);
}

Myпроблема в том, что для этого я знаю, что мне нужно использовать выбор, но я не смог правильно использовать выбор в моем коде, чтобы делать то, что я хочу, и я не знаю, что делать дальше.

Базовая эволюция кода должна быть следующей:

  • Установочные переменные сокета и sockaddr
  • Связать их на стороне сервера
  • Клиент отправляет "SYN"
  • Сервер отвечает «SYN-ACK-5555», где 5555 - номер порта для сокета данных
  • Клиент получает новый номер порта и отвечает с окончательным «ACK»
  • После того, как это будет сделано, связь между клиентом и сервером изменится с начального порта на новый, и основные функциональные возможности эхо-сервера будут следующими:

В идеале, функциональность трехстороннего рукопожатия и эхо-сигнала являются независимымии как только рукопожатие сделано, эхо-часть работает безвернемся к части рукопожатия.

Вот где выбор должен быть полезен, так как я могу разбить, какой код выполняется на основе, какой дескриптор файла активен, но мне не удалось выполнить эту работу.

Заранее спасибо.

...