我正在 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/