У меня есть 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»
- После того, как это будет сделано, связь между клиентом и сервером изменится с начального порта на новый, и основные функциональные возможности эхо-сервера будут следующими:
В идеале, функциональность трехстороннего рукопожатия и эхо-сигнала являются независимымии как только рукопожатие сделано, эхо-часть работает безвернемся к части рукопожатия.
Вот где выбор должен быть полезен, так как я могу разбить, какой код выполняется на основе, какой дескриптор файла активен, но мне не удалось выполнить эту работу.
Заранее спасибо.