Как мне сохранить IP-адреса клиента в массиве на C (программирование сокетов)

#c #arrays #list #sockets #server

#c #массивы #Список #сокеты #сервер

Вопрос:

У меня есть простая программа клиент / сервер в сокете на C. Я использую inet_ntoa , которая возвращает IP-адреса клиентов, подключенных к серверам. Я запускаю цикл 2 раза, чтобы подключить 2 клиента и сохранить int в массиве char .

Проблема в том, что когда я печатаю массив, он всегда выдает последний IP-адрес, добавленный в массив. Например:

 x.x.x.x connected 
y.y.y.y connected 
  

Массив печатается y.y.y.y два раза

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

#define MAX 80
#define PORT 8080
#define SA struct sockaddr

// Driver function 
int main() {

  int sockfd, connfd, len;
  struct sockaddr_in servaddr, cli;
  struct sockaddr_in addr_remote;
  char * ips[2];
  // socket create and verification 
  sockfd = socket(AF_INET, SOCK_STREAM, 0);
  if (sockfd == -1) {
    printf("socket creation failed...n");
    exit(0);
  } 
  else
    printf("Socket successfully created..n");
  bzero( amp; servaddr, sizeof(servaddr));

  // assign IP, PORT 
  servaddr.sin_family = AF_INET;
  servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
  servaddr.sin_port = htons(PORT);

  // Binding newly created socket to given IP and verification 
  if ((bind(sockfd, (SA * ) amp; servaddr, sizeof(servaddr))) != 0) {
    printf("socket bind failed...n");
    exit(0);
  } 
  else
    printf("Socket successfully binded..n");

  // Now server is ready to listen and verification 
  int i = 0;
  for (i = 0; i < 2; i  ) {
    if ((listen(sockfd, 5)) != 0) {
      printf("Listen failed...n");
      exit(0);
    } 
    else
      printf("Server listening..n");
    len = sizeof(cli);

    // Accept the data packet from client and verification 
    connfd = accept(sockfd, (SA * ) amp; addr_remote, amp; len);
    if (connfd < 0) {
      printf("server acccept failed...n");
      exit(0);
    }
    else
      printf("server acccept the client...n");

    // Function for chatting between client and server 
    // func(connfd); 
    //printf( " Welcome %s " , inet_ntoa(addr_remote.sin_addr));
    ips[i] = inet_ntoa(addr_remote.sin_addr);

  }
  for (i = 0; i < 2; i  ) {

    printf("%s", ips[i]);

  }
  // After chatting close the socket 
  close(sockfd);
}
  

Комментарии:

1. Смотрите документацию по адресу linux.die.net/man/3/inet_ntoa — там написано «Функция inet_ntoa() … Строка возвращается в статически выделенный буфер, который последующие вызовы будут перезаписывать «.

2. не могли бы вы объяснить подробнее, пожалуйста?

3. можете ли вы порекомендовать мне решение?

4. При печати просто используйте это: ‘uint32_t ip; printf(«%hhu.%hhu.%hhu.%hhu.%hhu», ip>> 24, ip>> 16, ip >> 8, ip);

Ответ №1:

Вы должны выделить свой собственный массив символов для IP и скопировать его из статического буфера, возвращаемого inet_ntoa() . Простой пример:

 char ips[2][20];
...
strcpy(ips[i], inet_ntoa(...))
  

РЕДАКТИРОВАТЬ: дело в том, что inet_ntoa() функция сохраняет свой результат во внутреннем, статически выделенном буфере и возвращает только указатель на него, который является постоянным. Таким образом, ваш ip[0] и ip[1] оба содержат один и тот же указатель, который указывает на последний IP, полученный из inet_ntoa() .

Комментарии:

1. Почему 20 ? 15 1 отлично подойдет для адреса IPV4.

2. @alk: Да, вы правы, мне было лень считать 🙂 Это всего лишь пример.