【问题标题】:Establishing TCP socket connection between PHP client and C server on Ubuntu在 Ubuntu 上建立 PHP 客户端和 C 服务器之间的 TCP 套接字连接
【发布时间】:2017-03-16 17:02:33
【问题描述】:

我正在 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);

?>

【问题讨论】:

  • 向我们展示终端中的输出、如何启动客户端/服务器以及您对这两个程序的期望。

标签: php c linux sockets


【解决方案1】:

代码中充满了错误。

服务器.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()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,或以其他方式终止进程。您应该附加信号处理程序,并实现线程间通信以正确停止accepting 连接等。由于这超出了问题的范围,我将把它留给自学。

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

客户端.php

您将未定义变量$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

【讨论】:

    猜你喜欢
    • 2014-06-22
    • 2021-11-06
    • 2012-04-24
    • 2011-05-20
    • 2014-02-14
    • 1970-01-01
    • 2015-09-27
    • 2015-10-04
    • 1970-01-01
    相关资源
    最近更新 更多