php - 在 Ubuntu 上建立 PHP 客户端和 C 服务器之间的 TCP 套接字连接

标签 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;

}

客户端.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);

?>

最佳答案

代码中充满了错误。

服务器.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 是一个编译时运算符:

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

关闭套接字

当 session 完成时,应该关闭套接字描述符:

close(socket_desc);

否则,使用SOCK_CLOEXEC 标志(socket()type 参数)。

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

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

new_sock = malloc(1);

你可以简单地cast integer to void pointer :

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

从您生成一个线程的那一刻起,您就负责它的生命周期,直到它终止。特别是,您应该使用 pthread_join() 函数等待子线程终止。后者接受一个 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);
}

信号处理程序

程序接受连接直到超过线程限制,或者用户按下Control - C,或者以其他方式终止进程。您应该附加信号处理程序,并实现线程间通信以正确停止接受连接等。由于这超出了问题的范围,我将把它留给自学。

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

客户端.php

您正在将 undefined variable $message 的长度传递给 socket_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 号航站楼

我在 Client.php 中更改了 $selectedType 以便在 CLI 中进行测试:

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

关于php - 在 Ubuntu 上建立 PHP 客户端和 C 服务器之间的 TCP 套接字连接,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40395950/

相关文章:

php - 正则表达式剥离包含特定 href 值的 <a> 标签

c - C语言中删除一个节点的列表

linux - nopage()方法实现

linux - Bash递归地替换名称上的许多空格

c - 使用 fork 和 execvp 启动/停止/etc/init.d/中的服务不起作用

php - PHPMailer 的字符串中的换行符

php - Laravel 5.2 多个 file_get_contents() 不适用于产品

php - 从具有多个要求的两个表中选择值,但只使用其中一个

c - 测试递归函数 - C

arrays - C 将宏作为参数指针传递