在Ubuntu

时间:2016-11-03 07:28:10

标签: php c linux sockets

我正在Ubuntu 16.04上编写一个简单的PHP客户端和C服务器程序。在客户端,我用HTML制作了一个简单的图形用户界面,其中只有一个下拉框和一个提交按钮。当我点击按钮时,会执行PHP客户端代码(虽然是Apache服务器),但是客户端没有连接到最初在终端中启动的服务器。

我想将下拉框的值传递给C服务器,无论用户从下拉列表中选择什么。请帮我弄清楚我的代码有什么问题。

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;

}

Client.php

<?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 socket\n");

// connect to server

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

// 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 server\n");

socket_close($socket);

?>

1 个答案:

答案 0 :(得分:0)

代码中充满了错误。

Server.c

检查返回值

如果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()的{​​{1}}参数)。

从线程处理程序访问套接字

您只为接受的套接字的文件描述符分配单个字节:

type

您可以简单地cast integer to void pointer

new_sock = malloc(1);

即使您想使用#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()函数返回一个线程ID。它没有。成功时返回值为零,否则为错误代码。

从您生成线程的那一刻起,您就要对其生命周期负责,直到它终止为止。特别是,您应该等待子线程使用pthread_create()函数终止。后者接受pthread_join(),由pthread_t初始化。所以你需要在某处存储pthread_create()个缓冲区。 E.g:

pthread_t

信号处理程序

程序接受连接,直到线程限制超过,或者用户按 Control - C ,或以其他方式终止进程。您应该附加信号处理程序,并实施线程间通信以正确阻止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); } 连接等。由于这超出了问题的范围,我将留下进行自学。

最后,不要在C中使用C ++注释。

Client.php

您将未定义变量accept的长度传递给$message

socket_write

由于变量未定义,因此长度计算为零,这意味着您不向服务器发送任何内容。这是一个固定版本,为了完整性:

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

测试

修复上述内容后,程序会响应用户输入:

1号航站楼

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

2号航站楼

我在$ ./server Socket created bind done Waiting for incoming connections... Connection accepted Server Received: test 中更改了$selectedType以便在CLI中进行测试:

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