PHP socket编程示例

写在前面:最级要开始写我们的项目了,是一个网络编程的项目,语言用C++,基于Socket通信,采用JSON数据交换格式,存数据用Mysql数据库。我们开始的困难是不知道如何处理客户端,组内都没有学写APP,如果是在终端下跑那就有太多限制了,感觉反而是加大了难度。

纠结了一会,突然想到能不能用PHP来写客户端,我学过一段时间PHP,目前还不太了解高阶的用法,前不久写了一个简单的订餐系统,用到一些特性,记得看到过PHP也可以进行Socket编程。在网上搜了一下,然后我写了一个简单的测试样例,客户端是用PHP,服务端用C++,互发送一条消息之后成功接收。

PHP的语言特性决定了它不适合做socket服务器端,socket主要面向底层和网络服务开发,一般用C或Java实现,能更好的处理并发、阻塞等。和C++或C写TCP客户端是一样的,工作过程可用下面的图表示:

这里写图片描述

PHP中和Socket相关函数


socket_accept() 接受一个Socket连接
socket_bind()socket绑定在一个IP地址和端口上
socket_clear_error() 清除socket的错误或者最后的错误代码
socket_close() 关闭一个socket资源
socket_connect() 开始一个socket连接
socket_create_listen() 在指定端口打开一个socket监听
socket_create_pair() 产生一对没有区别的socket到一个数组里
socket_create() 产生一个socket,相当于产生一个socket的数据结构
socket_get_option() 获取socket选项
socket_getpeername() 获取远程类似主机的ip地址
socket_getsockname() 获取本地socketip地址
socket_iovec_add() 添加一个新的向量到一个分散/聚合的数组
socket_iovec_alloc() 这个函数创建一个能够发送接收读写的iovec数据结构
socket_iovec_delete() 删除一个已经分配的iovec
socket_iovec_fetch() 返回指定的iovec资源的数据
socket_iovec_free() 释放一个iovec资源
socket_iovec_set() 设置iovec的数据新值
socket_last_error() 获取当前socket的最后错误代码
socket_listen() 监听由指定socket的所有连接
socket_read() 读取指定长度的数据
socket_readv() 读取从分散/聚合数组过来的数据
socket_recv()socket里接收数据到缓存
socket_recvfrom() 接受数据从指定的socket,如果没有指定则默认当前socket
socket_recvmsg()iovec里接受消息
socket_select() 多路选择
socket_send() 这个函数发送数据到已连接的socket
socket_sendmsg() 发送消息到socket
socket_sendto() 发送消息到指定地址的socket
socket_set_block()socket里设置为块模式
socket_set_nonblock() socket里设置为非块模式
socket_set_option() 设置socket选项
socket_shutdown() 这个函数允许你关闭读、写、或者指定的socket
socket_strerror() 返回指定错误号的详细错误
socket_write() 写数据到socket缓存
socket_writev() 写数据到分散/聚合数组

PHP客户端

  1. 设置变量,”主机”和”端口”

    $host = "127.0.0.1"; 
    $port = 9999;
    //  设置超时时间,保证连接不会超时
    set_time_limit(0);
  2. 创建socket

    $socket = socket_create(AF_INET, SOCK_STREAM, 0 ) or die("Could not create socket!\n");
    /*
    三个参数:
        1.创建socket用的通信协议族,AF_INET是基于IPv4的Internet协议
        2.指定服务类型对TCP/IP来说,SOCK_STREAM表示传输层使用TCP协议
        3.指定socket使用哪种具体的协议
    */
  3. 连接到服务端

    $result = socket_connect($socket, $host, $port) or die("Could not connect to server\n");
  4. 向服务端写数据

    socket_write($socket, $message, strlen($message)) or die("Could not send data to server\n");
    /*
      向socket中写入指定大小的缓冲数据,三个参数,返回写入的字节数
      1.有效的socket句柄
      2.要写入的数据
      3.可选,写入socket数据的字节数
    */
  5. 从服务端接收数据

    $result = socket_read($socket,1024) or die("Could not read server response\n");
    /*
      从socket中读取指定字节的数据,三个参数,返回读取到的字符串数据
      1.有效的socket句柄
      2.指定读取的字节长度
      3.可选,默认为PHP_BINARY_READ,安全读取二进制数据
    */
  6. 关闭socket

    socket_close($socket);

简单的测试样例

一个小样例,客户端用PHP,服务器端用C++,数据传递采用json格式,用jsoncpp。

server

/*server.cpp*/

/*************************************************************************
    > File Name: server.cpp
    > Author: Tanswer_
    > Mail: duxm@xiyoulinux.org
    > Created Time: 
 ************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <assert.h>
#include <errno.h>
#include <signal.h>
#include <json/json.h>

using namespace std;

#define BUF_SIZE 1024

int main(int argc, char*argv[])
{
    if(argc <= 2)
    {
        printf("usage: %s ip_address port \n",basename(argv[0]));
        return -1;
    }

    const char* ip = argv[1];
    int port = atoi(argv[2]);

    struct sockaddr_in address;
    bzero(&address,sizeof(address));
    address.sin_family = AF_INET;
    inet_pton( AF_INET, ip, &address.sin_addr );
    address.sin_port = htons( port );

    int sockfd = socket(PF_INET, SOCK_STREAM, 0);
    assert(sockfd >= 0);

    int ret = bind(sockfd, (struct sockaddr*)&address, sizeof(address));
    assert(ret != -1);

    ret = listen(sockfd,5);
    assert(ret != -1);

    struct sockaddr_in client;
    socklen_t len = sizeof(client);
    int connfd = accept(sockfd,(struct sockaddr*)&client,&len);
    if(connfd < 0)
    {
        printf("errno is : %d\n",errno);
    }
    else
    {
        /*接收数据*/
        char buffer[BUF_SIZE];
        memset(buffer,'\0',BUF_SIZE);
        ret = recv(connfd, buffer, BUF_SIZE-1, 0);
        printf("got %d bytes of normal data %s\n",ret,buffer);

        /*将json串解析*/
        Json::Value root;
        Json::Reader reader;
        if(reader.parse(buffer,root))
        {
            cout << "name: " << root["name"].asString() << endl; 
            cout << "hobbies: " << root["hobbies"].asString() << endl; 
            cout << "birthdate: " << root["birthdate"].asString() << endl; 
        }

        /*发送给客户端*/
        const char* data = "注册成功!";
        send(connfd,data,strlen(data),0);
        /*关闭*/
        close(connfd);
    }
    close(sockfd);
    return 0;
}

client

<html>
    <head>
        <meta charset="utf-8">
        <title>test</title>
    </head>
    <body>

        <form action="" method="post">
        姓名:<input type="text" name="name"><br >
        爱好:<input type="text" name="hobbies"><br >
        生日:<input type="text" name="birthdate"><br >
        <input type="submit" value="提交" name="submit">
        </form>
    </body>
</html>


<?php
if(isset($_POST['submit']))
{
    $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");  

    class Emp{
        public $name = "";
        public $hobbies = "";
        public $birthdate = "";
    }
    $e = new Emp();

    $e->name = $_POST["name"];
    $e->hobbies = $_POST["hobbies"];
    $e->birthdate = $_POST["birthdate"];

    $message = json_encode($e);
    #打印一些信息
    echo $message; #json串
    echo '<br >';  
    echo strlen($message);#json长度
    echo '<br >';

    // send string to server
    socket_write($socket, $message, strlen($message)) or die("Could not send data to server\n");
    // get server response
    $result = socket_read ($socket, 1024) or die("Could not read server response\n");
    echo "\tReply From Server  : ".$result;

    // close socket
    socket_close($socket);
}
?>

结果

编译运行server.cpp,开启服务端,等待连接

将client.php放到/home/wwwroot/default下,本地已配好 lnmp环境,在浏览器输入 localhost/client.php,可以看到自己写的页面,

这里写图片描述

然后填好表单内容点击提交,结果如下:

这里写图片描述

这里写图片描述

感觉是可行的,下面构思项目啦。

  • 3
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值