[英]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. 该代码充满了错误。
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 ++注释。
You are passing length of undefined variable $message
to socket_write
: 您正在将未定义变量
$message
长度$message
给socket_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));
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.