Установка TCP-сокета между клиентом PHP и сервером C на Ubuntu

Я пишу простой клиент PHP и серверные программы C на Ubuntu 16.04. На стороне клиента я сделал простой графический интерфейс пользователя в HTML, в котором есть только одно выпадающее окно и кнопка отправки. При нажатии на кнопку выполняется PHP клиентский код (хотя и Apache server), но клиент не подключается к серверу, который изначально запускается в терминале.

Я хочу передать значение раскрывающегося окна на сервер C, независимо от того, что пользователь выбирает из раскрывающегося списка. Пожалуйста, помогите мне выяснить, что не так с моим кодом.

Сервер.с

//All Libraries are present including pthread

#define BUFFER_SIZE 1024

//the thread function

void *connection_handler(void *);

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

  int socket_desc , client_sock , c , *new_sock;

  struct sockaddr_in server , client;

  socket_desc = socket(AF_INET , SOCK_STREAM , 0);

  if (socket_desc == -1)
  {

    printf("Could not create socket");

  }

  puts("Socket created");

  server.sin_family = AF_INET;

  server.sin_addr.s_addr = INADDR_ANY;

  server.sin_port = htons( 8888 );
  //Bind
  if( bind(socket_desc,(struct sockaddr *)&server , sizeof(server)) < 0)
  {


    perror("bind failed. Error");
    return 1;
  }
  puts("bind done");

  listen(socket_desc , 3);

  c = sizeof(struct sockaddr_in);

  int threadID;

  //Accept and incoming connection

  puts("Waiting for incoming connections...");

  c = sizeof(struct sockaddr_in);

  while( (client_sock = accept(socket_desc, (struct sockaddr *)&client, (socklen_t*)&c)) )

  {

    puts("Connection accepted");

    pthread_t sniffer_thread;

    new_sock = malloc(1);

    *new_sock = client_sock;

    threadID=pthread_create( &sniffer_thread , NULL ,  connection_handler , (void*) new_sock);

    if( threadID < 0)

    {

      perror("could not create thread");

      return 1;

    }

    puts("Handler assigned");

  }



  if (client_sock < 0)

  {

    perror("accept failed");

    return 1;

  }

  return 0;

}

void *connection_handler(void *socket_desc)

{

  int read_size;

  char *serverErrorMsg="Invalid Details!";

  char client_message[2000],client_poll[2000];

  int sock = *(int*)socket_desc;


  //Receive a message from client

  if( (read_size = recv(sock , client_message , 2000 , 0)) > 0 )

  {
    puts("Server Received: ");

    puts(client_message);

  }

  else

  {

    write(sock , serverErrorMsg , strlen(serverErrorMsg));

  }

  free(socket_desc);    

  return 0;

}

Клиент.РНР

<?php 

error_reporting(E_ALL);

$host    = "127.0.0.1";

$port    = 8888;

// create socket

$socket = socket_create(AF_INET, SOCK_STREAM, 0) or die("Could not create socketn");

// connect to server

$result = socket_connect($socket, $host, $port) or die("Could not connect to servern");  

// sending test type to server

$selectedType = $_POST['testType']; //html drop down with name='testType'

socket_write($socket, $selectedType, strlen($message)) or die("Could not send data to servern");

socket_close($socket);

?>

1 ответ

  1. Код полон ошибок.

    Сервер.с

    Проверка возвращаемых значений

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

    socket_desc = socket(AF_INET, SOCK_STREAM, 0)
    if (socket_desc == -1) {
      printf("Could not create socket");
    }
    

    Стандартный вход-выход

    Вы должны распечатать ошибки в стандартный дескриптор ошибокabort(), или выйти с ненулевым кодом выхода, например:

    #include <errno.h>
    #include <string.h>
    
    socket_desc = socket(AF_INET, SOCK_STREAM, 0);
    if (socket_desc == -1) {
      fprintf(stderr, "socket() failed: %s\n", strerror(errno));
      exit(1);
    }
    

    -Wall

    Очевидно, что вы не скомпилировали код с предупреждениями:

    a.c:xxx:yy warning: unused variable ‘client_poll’ [-Wunused-variable]
    

    Всегда компилируйте с -Wall.

    sizeof

    Нет необходимости хранить результат sizeofв памяти, как sizeofэто делает оператор времени компиляции:

    /* Don't do this. Use a macro, if you want to shorten sizeof expression */
    c = sizeof(struct sockaddr_in)
    

    Закрытие гнезда

    Дескриптор сокета должен быть закрыт после завершения сеанса:

    close(socket_desc);
    

    В противном случае используйте SOCK_CLOEXECфлаг ( socket()‘s typeаргумент).

    Доступ к сокетам из обработчика потоков

    Для файлового дескриптора принятого сокета выделяется только один байт:

    new_sock = malloc(1);
    

    Можно просто привести целое число к указателю void:

    #include <stdint.h>
    
    void *connection_handler(void *socket_desc)
    {
      int sock = (intptr_t) socket_desc;
      /* ... */
    }
    
    threadID = pthread_create(&sniffer_thread, NULL,
      connection_handler, (void *)(intptr_t) new_sock);
    

    Даже если вы хотите использовать mallocдля ада его, используйте sizeofоператора:

    /* Allocates memory for an integer */
    new_sock = malloc(sizeof(int));
    

    По отношению к pthread_create()

    Код, по-видимому, «думает», что pthread_create()функция возвращает идентификатор потока. Это не так. Возвращаемое значение равно нулю при успешном выполнении, в противном случае это код ошибки.

    С момента зарождения нити вы отвечаете за ее жизненный цикл, пока он не завершится. В частности, следует дождаться завершения дочерних потоков с помощью pthread_join()функции. Последний принимает a pthread_t,который инициализируетсяpthread_create(). Поэтому вам нужно pthread_tгде-то хранить буферы. Например.:

    int rc, i = 0;
    const int MAX_THREADS = 10;
    pthread_t *threads = calloc(sizeof(pthread_t), MAX_THREADS);
    struct sockaddr_storage their_addr;
    socklen_t addr_size;
    
    puts("Waiting for incoming connections...");
    addr_size = sizeof their_addr;
    while ((client_sock = accept(socket_desc, (struct sockaddr *)&their_addr, &addr_size)) > 0) {
      puts("Connection accepted");
    
      if (i >= MAX_THREADS) {
        fprintf(stderr, "Max threads limit exceeded: %d, closing client socket\n", i);
        close(client_sock);
        break;
      }
    
      rc = pthread_create(&threads[i++], NULL,
          connection_handler, (void *)(intptr_t) client_sock);
      if (rc) {
        perror("could not create thread");
        break;
      }
    }
    
    if (threads) {
      int i;
      for (i = 0; i < MAX_THREADS; i++) {
        if (threads[i])
          pthread_join(threads[i], NULL);
      }
      free(threads);
    }
    

    Обработчик сигнала

    Программа принимает подключение до тех пор, пока не будет превышен предел потока , или пользователь не нажмет ControlC, или не завершит процесс другим способом. Вы должны прикрепить обработчики сигнала, и снабдить interthread сообщение правильно для того чтобы остановить acceptING соединения etc. Поскольку это выходит за рамки вопроса, я оставлю его для самостоятельного изучения.

    Наконец, не используйте комментарии C++ В C.

    Клиент.РНР

    Вы передаете длину неопределенной переменной $messagesocket_write:

    socket_write($socket, $selectedType, strlen($message));
    

    Поскольку переменная не определена, длина вычисляется до нуля, что означает, что вы ничего не отправляете на сервер. Вот фиксированная версия, для полноты:

    socket_write($socket, $selectedType, strlen($selectedType));
    

    Тестирование

    После фиксации выше, программы отвечают на ввод пользователя:

    Терминал 1

    $ ./server
    Socket created
    bind done
    Waiting for incoming connections...
    Connection accepted
    Server Received: 
    test
    

    Терминал 2

    Я переоделся $selectedTypeClient.phpдля тестирования в CLI:

    $selectedType = isset($_POST['testType']) ? $_POST['testType'] : 'test';
    
    $ php Client.php