简体   繁体   English

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

[英]Establishing TCP socket connection between PHP client and C server on Ubuntu

I am writing a simple PHP client and C server programs on Ubuntu 16.04. 我正在Ubuntu 16.04上编写一个简单的PHP客户端和C服务器程序。 On client side I have made a simple graphical user interface in HTML, in which there is only one drop down box, and a submit button. 在客户端,我用HTML创建了一个简单的图形用户界面,其中只有一个下拉框和一个提交按钮。 When I click on the button, PHP client code is executed (though Apache server), but the client does not connect to the server, which is initially launched in terminal. 当我单击按钮时,将执行PHP客户端代码(尽管通过Apache服务器),但是客户端未连接到服务器,该服务器最初是在终端中启动的。

I want to pass the value of drop down box to the C server, whatever user selects from drop down. 我想将下拉框的值传递给C服务器,无论用户从下拉菜单中选择什么。 Please help me to figure out what's wrong with my code. 请帮助我找出我的代码出了什么问题。

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 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);

?>

The code is full of bugs. 该代码充满了错误。

Server.c 服务器

Checking return values 检查返回值

If socket() fails, you only print a message to the standard output. 如果socket()失败,则仅将消息打印到标准输出。 The program continues to run with invalid descriptor: 该程序继续使用无效的描述符运行:

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

Standard input/output 标准输入/输出

You should print errors to the standard error descriptor, then abort() , or exit with a non-zero exit code, eg: 您应该将错误打印到标准错误描述符中,然后输出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

Obviously, you haven't compiled the code with warnings on: 显然,您尚未在警告中编译代码:

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

Always compile with -Wall . 始终使用-Wall编译。

sizeof

There is no need in storing the result of sizeof in memory, as sizeof is a compile-time operator: 不需要将sizeof的结果存储在内存中,因为sizeof是一个编译sizeof算符:

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

Closing the socket 关闭插座

The socket descriptor should be closed when a session has been completed: 会话完成后,应关闭套接字描述符:

close(socket_desc);

Otherwise, use SOCK_CLOEXEC flag ( socket() 's type argument). 否则,请使用SOCK_CLOEXEC标志( socket()type参数)。

Accessing the sockets from thread handler 从线程处理程序访问套接字

You allocate only single byte for the file descriptor for the accepted socket: 您只为接受的套接字的文件描述符分配一个字节:

new_sock = malloc(1);

You can simply cast integer to void pointer : 您可以将整数简单地转换为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);

Even if you want to use malloc for the hell of it, use the sizeof operator: 即使您想使用malloc来解决问题,也请使用sizeof运算符:

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

Regarding pthread_create() 关于pthread_create()

The code apparently "thinks" that pthread_create() function returns a thread ID. 该代码显然“认为” pthread_create()函数返回线程ID。 It doesn't. 没有。 The return value is zero on success, otherwise it is an error code. 成功时返回值为零,否则为错误代码。

From the moment you spawn a thread, you are responsible for its life cycle until it terminates. 从产生线程的那一刻起,您要负责其生命周期直至终止。 Particularly, you should wait for the child threads to terminate using pthread_join() function. 特别是,您应该等待子线程使用pthread_join()函数终止。 The latter accepts a pthread_t , which is initialized by pthread_create() . 后者接受pthread_t ,它由pthread_create()初始化。 So you need to store pthread_t buffers somewhere. 因此,您需要将pthread_t缓冲区存储在某个地方。 Eg: 例如:

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);
}

Signal handlers 信号处理器

The program accepts connection until thread limit exceeds, or the user presses Control - C , or terminates the process in other way. 该程序将接受连接,直到超出线程限制为止,或者用户按Control - C或以其他方式终止该过程。 You should attach the signal handlers, and implement interthread communication to properly stop accept ing connections etc. As this goes beyond the scope of the question, I'll leave it for self-study. 您应该附加信号处理程序,并实现线程间通信以正确停止accept连接等。由于这超出了问题的范围,我将其留给自学。

Finally, don't use C++ comments in C. 最后,不要在C中使用C ++注释。

Client.php Client.php

You are passing length of undefined variable $message to socket_write : 您正在将未定义变量$message长度$messagesocket_write

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

Since the variable is undefined, the length is evaluated to zero, which means that you send nothing to the server. 由于该变量是未定义的,因此长度被评估为零,这意味着您什么也不发送到服务器。 Here is a fixed version, for completeness: 为了完整起见,这是一个固定版本:

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

Testing 测试中

After fixing the above, the programs respond to the user input: 解决上述问题后,程序将响应用户输入:

Terminal 1 1号航站楼

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

Terminal 2 2号航站楼

I've changed $selectedType in Client.php for testing in CLI: 我已更改Client.php $selectedType以在CLI中进行测试:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM