作为程序员一定要保持良好的睡眠,才能好编程

Swoole 学习笔记 -- 异步网络通信(1)

发布时间:2019-03-22


Swoole是使用纯C语言编写的  ,提供了PHP语言的异步多线程服务器。 


异步TCP/UDP网络客户端 、异步MYSQL、异步Redis、数据库连接池


消息队列、毫秒定时器、异步DNS查询、Swoole内置了HTTP/webSocket服务器端和客户端


crontab linux定时器 精确度到分 。  swoole 精确到 毫秒。


官网:https://www.swoole.com/



那么使用swoole能做什么项目呢?  https://wiki.swoole.com/wiki/page/p-case.html


比如说  YY语音   虎牙视频  应用场景还是很广泛的。所以今天我们来学习学习。


支持并发百万 TCP 长连接 、视频、直播、 通讯

典型的应用场景:

1、移动互联网API服务器

2、物联网

3、微服务

4、高性能web服务

5、游戏服务器

6、在线聊天系统  web IM


PHP工程师如果不懂swoole的话,还不算完美。


Swoole安装准备工作:

1、linux 环境

2、php7  swoole2.1  redis

3、源码安装php7    源码安装swoole


如何学好swoole    1、查看文档   2、实现swoole特性的功能点    3、多看其他现有swoole案例代码


边看文档 边写代码   多看别人怎么写,对于自己的提高是非常有必要的。



swoole 提问社区:

https://segmentfault.com/t/swoole



php7.1的安装


进入 php.net  下载最新版  php7.1.4       或 PHP7.2.4  进行下载并安装。


linux 安装php扩展服务

http://www.xiaosongit.com/index.php/index/detail/id/371.html



php支持swoole


http://www.xiaosongit.com/index.php/index/detail/id/369.html



好的,上边我们都已经配置好了,那么真正的项目如何开始进行呢?


现在我们就来看看吧。



我们建议使用源码进行安装


----------------------------------------------------------------------------

SWOOLE 分为  HTTP  TCP  UDP  三种连接方式。


分别是什么关系又是如何获取的呢?



swoole_server运行模式


单线程模式

这种模式就是传统的异步非阻塞。在Reactor内直接回调php的函数。如果回调函数中有阻塞操作会导致为同步模式。

work_num参数对于base模式仍然有效,swoole会启动多Reactor进程。

Base模式下Reactor和worker是同一个角色。

优点:

base模式没有IPC开销,性能更好

Base模式代码更简单,不容易出错。

缺点:

1、Tcp连接实在worker进程中维持的,所以当某个worker进程挂掉时,此worker内所有人连接都将被关闭

2、少量TCP长连接无法利用到所有worker进程

3、Tcp连接与worker是绑定的,长连接应用中某些连接的数据量大,这些连接所在的worker进程负载会非常高。

但某些连接数据量较小,所在worker进程的负载会非常低,不同worker进程无法实现负载均衡。


Base适用场景:客户端连接之间不需要交互,如Memcache/Http服务器。


进程模式

多进程模式是最复杂的方式,用了大量的进程间通信,进程管理机制。适合业务逻辑非常复杂的场景。

swoole提供了完善的进程管理、内存保护机制。在业务逻辑非常复杂的情况下,也可以长期稳定的运行。


进程模式优点:

1、连接与数据请求是分离的,不会因为某些连接数据量大,某些数据量小导致进程不均衡。

2、worker进程发送致命错误是,连接并不会被切断。


配置选项:

https://wiki.swoole.com/wiki/page/275.html



TCP服务


//创建Server对象,监听127.0.0.1:9501端口
$server=new Swoole_server("127.0.0.1",9501,SWOOLE_PROCESS,SWOOLE_SOCK_TCP);

$server->set([
    'worker_num'=>8, //worker_num 进程数
    'max_request'=>10000
]);


/**
 * @title 监听连接事件
 * $fd 客户端连接的唯一标识
 * $reactor_id  线程 ID  这是第三个参数
 */
$server->on("connect",function($server,$fd,$reactor_id){
    echo "Client: {$reactor_id}-{$fd}-Content.\n";
});

/**
 * @title 监听数据接收事件
 * $fd 客户端数据连接唯一标识
 * $reactor_id 进程ID
 * $data 发送过来的内容
 */
$server->on("receive",function($server,$fd,$reactor_id,$data){
    $server->send($fd,"Server:{$reactor_id}-{$fd} {$data}");
});


/**
 * @title 关闭连接
 * $server
 * $fd 客户端数据连接唯一标识
 */
$server->on("close",function($server,$fd){
    echo "Clinet:close".$fd;
});

//启动服务
$server->start();


还有其他三种调用方式,请查看图片:

截图00.png


tcp服务已经写好了,那么如何来连接?

telnet ip 端口

[root@localhost ~]# telnet 127.0.0.1 9501
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
nihao
Server:0-1 nihao
5656
Server:0-1 5656


服务器端:

root@localhost swoole]# php tcp.php
Client: 0-1-Content.
Client: 0-2-Content.



swoole连接mysql查询数据的案例

[root@localhost swoole]# php tcp.php 
启动的时候初始化....onStart
启动的时候初始化....onStart
启动的时候初始化....onStart
启动的时候初始化....onStart
启动的时候初始化....onStart
启动的时候初始化....onStart
启动的时候初始化....onStart
启动的时候初始化....onStart
Client: 0-1-Content.
收到客户端信息:a:2:{s:7:"message";s:16:"hellow1553245896";s:4:"page";i:2;}Clinet:close1
Client: 0-2-Content.
收到客户端信息:a:2:{s:7:"message";s:16:"hellow1553245902";s:4:"page";i:2;}Clinet:close2
Client: 0-3-Content.
收到客户端信息:a:2:{s:7:"message";s:16:"hellow1553245909";s:4:"page";i:3;}Clinet:close3
Client: 0-4-Content.
收到客户端信息:a:2:{s:7:"message";s:16:"hellow1553245919";s:4:"page";i:1;}Clinet:close4
Client: 0-5-Content.
收到客户端信息:a:2:{s:7:"message";s:16:"hellow1553245941";s:4:"page";i:1;}Clinet:close5


服务器端代码:

<?php

//创建Server对象,监听127.0.0.1:9501端口
$server=new Swoole_server("0.0.0.0",9501,SWOOLE_PROCESS,SWOOLE_SOCK_TCP);

$server->set([
    'worker_num'=>8, //worker_num 进程数
    'max_request'=>10000
]);

$server->on('WorkerStart',function($server,$worker_id){
    echo "启动的时候初始化....onStart\n";
		//每一次连接都要启动吗?
		$dsn="mysql:host=localhost;dbname=test;port=3306";
		//$dsn="mysql:localhost=localhost;dbname=test;port=3306";

		//以上这两种localhost 和 host 这是一样的, 记住没以后面都没有引号或单引号

		$root="root";
		$pass="song";
		$param=[
				PDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTION
				];
		
		$server->db=new pdo($dsn,$root,$pass,$param);
});

/**
 * @title 监听连接事件
 * $fd 客户端连接的唯一标识
 * $reactor_id  线程 ID  这是第三个参数
 */
$server->on("connect",function($server,$fd,$reactor_id){
    echo "Client: {$reactor_id}-{$fd}-Content.\n";
	

		//每一次连接都要启动吗?
		//$dsn="mysql:host=localhost;dbname=test;port=3306";
		//$dsn="mysql:localhost=localhost;dbname=test;port=3306";

		//以上这两种localhost 和 host 这是一样的, 记住没以后面都没有引号或单引号
    /*
		$root="root";
		$pass="song";
		$param=[
				PDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTION
				];
		$server->db=new pdo($dsn,$root,$pass,$param);
		*/
		//在这里不能立马发送信息给客户端,如果发送信息,则断开与客户端的连接
		//$server->send($fd,$fd." nihao");
});

/**
 * @title 监听数据接收事件
 * $fd 客户端数据连接唯一标识
 * $reactor_id 进程ID
 * $data 发送过来的内容
 */
$server->on("receive",function($server,$fd,$reactor_id,$data){
		printf("收到客户端信息:%s",$data);
		

		$data=unserialize($data);
		//在这里查询数据库么
		
		//$info=str_repeat($server->db,10).time();

		$start=($data['page']-1)*10;
	  $sql="select  * from user limit {$start},10";			
		$stmt=$server->db->prepare($sql);
		$stmt->execute();
		
		$obj=$stmt->fetchAll(PDO::FETCH_CLASS);
    
		$info=var_export($obj,true);

    $server->send($fd,"Server:{$reactor_id}-{$fd} {$data['message']} {$info}");
});


/**
 * @title 关闭连接
 * $server
 * $fd 客户端数据连接唯一标识
 */
$server->on("close",function($server,$fd){
    echo "Clinet:close".$fd."\n";
});

//启动服务
$server->start();



客户端连接:

$client=stream_socket_client('tcp://172.28.81.174:9501',$errno,$error);

if(!$client){
    print_r($errno);
    print_r($error);
}

$message=serialize([
'message'=>'hellow'.time(),
'page'=>1,
]);

fwrite($client,$message,mb_strlen($message,'utf-8'));

$info=fread($client,1024);


echo "服务器说:".$info."\n";

fclose($client);
服务器说:Server:0-5 hellow1553245941 array (
  0 => 
  stdClass::__set_state(array(
     'id' => '1',
     'name' => 'hoe',
     'gongzi' => '7000',
     'class_id' => '1',
  )),
  1 => 
  stdClass::__set_state(array(
     'id' => '2',
     'name' => 'james',
     'gongzi' => '4000',
     'class_id' => '2',
  )),
  2 => 
  stdClass::__set_state(array(
     'id' => '3',
     'name' => 'jack',
     'gongzi' => '1200',
     'class_id' => '3',
  )),
  3 => 
  stdClass::__set_state(array(
     'id' => '4',
     'name' => 'jim',
     'gongzi' => '700',
     'class_id' => '2',
  )),
  4 => 
  stdClass::__set_state(array(
     'id' => '5',
     'name' => 'jack',
     'gongzi' => '1200',
     'class_id' => '5',
  )),
  5 => 
  stdClass::__set_state(array(
     'id' => '6',
     'name' => 'hoe',
     'gongzi' => '7000',
     'class_id' => '1',
  )),
  6 => 
  stdClass::__set_state(array(
     'id' => '7',
     'name' => 'james',
     'gongzi' => '4000',
     'class_id' => '2',
  )),
  7 => 
  stdClass::__set_state(array(
     '
[Finished in 0.6s]


查看连接mysql的连接数:

[root@localhost ~]# mysqladmin -uroot -psong processlist
Warning: Using a password on the command line interface can be insecure.
+----+------+-----------+------+---------+------+-------+------------------+
| Id | User | Host      | db   | Command | Time | State | Info             |
+----+------+-----------+------+---------+------+-------+------------------+
| 43 | root | localhost | test | Sleep   | 106  |       |                  |
| 44 | root | localhost | test | Sleep   | 106  |       |                  |
| 45 | root | localhost | test | Sleep   | 106  |       |                  |
| 46 | root | localhost | test | Sleep   | 106  |       |                  |
| 47 | root | localhost | test | Sleep   | 32   |       |                  |
| 48 | root | localhost | test | Sleep   | 106  |       |                  |
| 49 | root | localhost | test | Sleep   | 106  |       |                  |
| 50 | root | localhost | test | Sleep   | 106  |       |                  |
| 57 | root | localhost |      | Query   | 0    | init  | show processlist |
+----+------+-----------+------+---------+------+-------+------------------+






TCP客户端连接

我们一直使用telnet 这样的方式连接 swoole server  ,那么有没有写成php脚本的形式去连接呢,下面我们就来看一看。

截图01.png


好的,现在我们来看一看代码如何实现:


php  tcp_server.php  这样的命令 一执行 ,就好似 nginx 开启了服务,我们就可以直接通过IP 和端口去使用


tcp_client.php

//连接 swoole tcp 服务
$client=new swoole_client(SWOOLE_SOCK_TCP);
if(!$client->connect("127.0.0.1",9501)){
    echo "服务器连接失败";
    exit;
}


//cli常量  swoole大部分代码在cli下运行。
fwrite(STDOUT,"请输入要发送的值");
$msg=trim(fgets(STDIN));

//把消息发送给tcp server服务器
$client->send($msg);

//接收来自server的数据
$result=$client->recv();

echo $result;


上面的程序 执行一次就关闭了,那么如何像telnet 一样可以多次输入值呢?


看下面的代码:

//连接 swoole tcp 服务
$client=new swoole_client(SWOOLE_SOCK_TCP);
if(!$client->connect("127.0.0.1",9501)){
    echo "服务器连接失败";
    exit;
}


while(true){
    //cli常量  swoole大部分代码在cli下运行。
    fwrite(STDOUT,"请输入要发送的值,如果需要退出请输入 exit :");
    $msg=trim(fgets(STDIN));
    if($msg=="exit"){
        break;
    }
    //把消息发送给tcp server服务器
    $client->send($msg);

    //接收来自server的数据
    $result=$client->recv();
    echo $result;
}



问题:

我如何知道我开启了几个进程?

ps aft | grep tcp_server.php

截图02.png


相关命令:

grep.png


杀死所有关于tcp.php 的进程


kill -9 `ps -ef | grep tcp.php | grep -v "grep" | awk '{print $2}'| xargs`







如何创建UDP服务呢?


udp_server.php

//创建udp服务器  其实和tcp差不不多,就是最后传递的参数不一样
$server=new Swoole_server("127.0.0.1",9502,SWOOLE_PROCESS,SWOOLE_SOCK_UDP);

//监听数据接收事件
/**
 *
 * $server,swoole_server对象
 * $data,收到的数据内容,可能是文本或者二进制内容
 * $client_info,客户端信息包括address/port/server_socket 3项数据
 *
 *
 */
$server->on("packet",function($server,$data,$clientInfo){
    $server->sendto($clientInfo['address'],$clientInfo['port'],"Server say:".$data."\n");
    var_dump($clientInfo);
    var_dump($data."\n");
});

$server->start();



udp_client.php

//创建连接udp服务器客户端
$client=new Swoole_client(SWOOLE_SOCK_UDP);

if(!$client->connect("127.0.0.1",9502)){
    echo "服务器UDP服务连接失败";
    exit;
}

//向服务器发送数据
fwrite(STDOUT,"请输入要发送的数据:");
$msg=trim(fgets(STDIN));

$client->send($msg);

//接收来自server的数据
$result=$client->recv();

echo $result;



使用命令终端连接:

#centos下安装nc应该是 yum -y install nc ,而且UDP是无连接传输,所以coonect事件是监控不到的
yum -y install nc
nc -u 127.0.0.1 9502



如图所示:

01.gif



http_server.php

这个启动和nginx类似,像访问nginx一样就可以访问swoole 

但是不能在线浏览php文件。



swoole_http_server 继承 swoole_server  ,是一个完整的http服务器实现。 swoole_http_server 支持同步和异步 2 种模式。

http/websocket服务器都是继承自swoole_server,所以swoole_server提供的API,如task/finish/tick等都可以使用


onRequest


onTask

onFinish

onTick

这些回调函数都是可以使用的,因为 swoole_http_server 继承于 swoole_server .




无论是同步模式还是异步模式,swoole_http_server 都可以支持大量TCP 客户端连接。


同步和异步仅仅体现在 对请求的处理方式上。


同步模式:

这种模式等同于nginx/php-fpm/apache ,它需要大量的worker来完成并发处理。编程方式与普通的php web 程序完全一致。


与php-fpm/apache 不同的是 客户端连接并不会独占进程,服务器依然可以应对大量并发连接。




异步模式:

这种模式整个服务器是异步非阻塞的,服务器可以应对大规模的并发连接和并发请求,但是编程方式完全使用异步API。

如:mysql、redis、http_client 、file_get_contents、sleep 等阻塞IO操作必须切换为异步的方式

如异步 swoole_client  swoole_event_add,swoole_timer等API。


http_server.php

//创建http swoole服务
$http=new swoole_http_server('0.0.0.0',8811);

//这里可以使用set来进行设置swoole服务器。



$http->on("request",function($request,$response){
    
    //如果多次向浏览器输出内容,请使用 $response->write();
    //如果一次性向浏览器输出内容,使用$response->end();
    
    $response->end("HTTP SERVER SWOOLE SAY:".$request->get['title']);

});

//启动服务
$http->start();


启动服务:

php http_server.php


测试服务:

连接方法有多种:  curl  http://127.0.0.1:8811


或者直接在浏览器中打开 也是可以的。

http://192.168.61.103:8811

如果传递参数:

http://192.168.61.103:8811/?username=james&age=22



自己实例:

//创建http swoole服务
$http=new swoole_http_server('0.0.0.0',8811);

$http->on("request",function($request,$response){

    //如果多次向浏览器输出内容,请使用 $response->write();
    //如果一次性向浏览器输出内容,使用$response->end(); 
    //这种方式可以实现,但不是最好的,浏览器一致处于等待状态,可以使用 swoole_sock_server(); 这样会更好

    for($i=1;$i<50;$i++){
        $response->write("HTTP SERVER SWOOLE SAY :".$i."<br>");
        sleep(1);
    }
    $response->end("HTTP SERVER SWOOLE SAY  end");

});

//启动服务
$http->start();



http_server 中 onrequest的回调函数中,有两个参数, $request   $response

分别看看都是什么意思:

$request
swoole_http_request->$header  //Http请求的头部信息。类型为数组,所有key均为小写。

echo $request->header['host'];
echo $request->header['accept-language'];

swoole_http_request->$server  //Http请求相关的服务器信息,相当于PHP的$_SERVER数组
echo $request->server['request_time'];

swoole_http_request->$get   //Http请求的GET参数
// 如:index.php?hello=123
echo $request->get['hello'];

// 获取所有GET参数
var_dump($request->get);

swoole_http_request->$post  //HTTP POST参数,格式为数组。
echo $request->post['hello'];

swoole_http_request->$cookie   //HTTP请求携带的COOKIE信息,与PHP的$_COOKIE相同
echo $request->cookie['username'];

swoole_http_request->$files   //文件上传信息。 类型以form名称为key的二维数组。与php的$_FILES相同。
Array(
    [name] => facepalm.jpg
    [type] => image/jpeg
    [tmp_name] => /tmp/swoole.upfile.n3FmFr
    [error] => 0
    [size] => 15476
    )
name 浏览器上传时传入的文件名称
type MIME类型
tmp_name 上传的临时文件,文件名以/tmp/swoole.upfile开头
size 文件尺寸

swoole_http_request->rawContent


swoole_http_request->getData    //获取完整的原始Http请求报文。包括Http Header和Http Body
function swoole_http_request->getData() : string


获取url中的参数:

截图03.png

服务器代码:

//创建http swoole服务
$http=new swoole_http_server('0.0.0.0',8811);

$http->on("request",function($request,$response){

    //如果多次向浏览器输出内容,请使用 $response->write();
    //如果一次性向浏览器输出内容,使用$response->end();

    //$response->end("HTTP SERVER SWOOLE SAY:".$request->server['request_uri']);q


    $response->end("HTTP SERVER SWOOLE SAY:".$request->get['username']);

});

//启动服务
$http->start();






配置静态路径根目录swoole_http_server

#创建swoole_http_server 服务

$server=new swoole_http_server("127.0.0.1",8812);

//给swoole进行配置
/**
* 配置静态文件根目录,与enable_static_handler配合使用。
* 设置document_root并设置 enable_static_handler 为true的时候,底层收到http请求后会先判断 
* document_root路径下是否存在此文件,如果存在就直接返回,不在触发 onRequest 回调。
* 使用静态文件处理特性时,应当将动态PHP代码和静态文件进行隔离,静态文件存放到特定的目录
*/

$server->set([
    'document_root'=>'/usr/local/nginx/html/swoole/',
    'enable_static_handler'=>true,
]);

#进行监听 客户端发来的信息
$server->on("request",function($request,$response){
    $response->end("SWOOLE SERVER RETURN DATA:".$request->get['username']);
});

#启动服务
$server->start();


截图04.png



这是运行结果:

2.gif


设置文件上传的临时目录

$server=new swoole_http_server("127.0.0.1",8012);

$server->set([
    "upload_tmp_dir"=>'/usr/local/nginx/html/data/'
]);

$server->on("request",function($request,$response){
    
    $response->end("server...");    
    
});

$server->start();




webSocket服务端以及客户端连接实例

 websocket_server.php

//创建webSocket服务器
$ws=new swoole_websocket_server("0.0.0.0",9999,SWOOLE_PROCESS);

//监听webSocket连接打开事件
$ws->on("open",function($ws,$request){
    var_dump($request->fd,$request->get,$request->server);
    $ws->push($request->fd,"hello ,welcome \n");
});

//监听websocket消息事件
$ws->on("message",function($ws,$frame){
    echo $frame->fd."----say: ".$frame->data."\n";
    $ws->push($frame->fd,"server say:".$frame->data."--".date("Y-m-d H:i:s"));
});

//监听websocket的关闭事件
$ws->on("close",function($ws,$fd){
    echo "client close".$fd."\n";
});

//启动websocket服务
$ws->start();



html页面代码:

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
    <style type="text/css">
        #container{
            overflow-y: scroll;
        }
        #container div{
            font-size: 14px;
            color:#666;
            padding: 5px 0px;
            margin:0px auto;
            width:95%;

        }
    </style>

    <script type="text/javascript">

        window.onload=function(){
            var container=document.getElementById("container");
            var submitButton=document.getElementById("submit");
            var message=null;
            var webSocket=new WebSocket("ws://192.168.61.103:9999");

            webSocket.onopen=function(event){
                webSocket.send("你好!");
                console.log("服务器连接成功...");
            }

            webSocket.onmessage=function(event){
                console.log("服务器回复说:"+event.data);
                container.appendChild(createDiv(event.data));
            }

            webSocket.onclose=function(event){
                console.log("connect close");
            }

            submitButton.onclick=function(){
                message=document.getElementById("message").value;
                if(message){
                    webSocket.send(message);
                    document.getElementById("message").value="";
                }else{
                    alert("请输入内容后,点击发送");
                }
            }

            function createDiv(message){
                var div=document.createElement("div");
                var textNode=document.createTextNode(message);
                div.appendChild(textNode);
                return div;
            }

        }


    </script>

</head>
<body>

<div id="container" style="border:1px solid #ccc; height:360px;width:600px;">

</div>

<input type="text" id="message"><input type="button" id="submit" value="发送">


</body>
</html>


服务器端执行  php websocket_server.php  进行监听


客户端打开 html页面 进行测试


效果就是这样:


3.gif


webSocket改造成 面向对象编程方式

ws_server.php

class Ws{
    public $server=null;
    CONST HOST="0.0.0.0";
    const PORT=9999;
    public function __construct(){
        $this->server=new swoole_websocket_server(self::HOST,self::PORT);
        $this->server->on("open",[$this,"onOpen"]);
        $this->server->on("message",[$this,"onMessage"]);
        $this->server->on("close",[$this,"onClose"]);
        $this->server->start();
    }

    public function onOpen($server,$frame){
        echo $frame->fd."---连接成功\n";
    }

    public function onMessage($server,$frame){
        echo $frame->fd."----发来消息说:".$frame->data."\n";
        $server->push($frame->fd,"服务器返回消息说:".$frame->data."--".date("Y-m-d H:i:s"));
    }

    public function onClose($server,$fd){
        echo $fd." 客户端已经关闭";
    }
}

new Ws();


html页面保持不变,还是和原来一样

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
    <style type="text/css">
        #container{
            overflow-y: scroll;
        }
        #container div{
            font-size: 14px;
            color:#666;
            padding: 5px 0px;
            margin:0px auto;
            width:95%;

        }
    </style>

    <script type="text/javascript">

        window.onload=function(){
            var container=document.getElementById("container");
            var submitButton=document.getElementById("submit");
            var message=null;
            var webSocket=new WebSocket("ws://192.168.61.103:9999");

            webSocket.onopen=function(event){
                webSocket.send("你好!");
                console.log("服务器连接成功...");
            }

            webSocket.onmessage=function(event){
                console.log("服务器回复说:"+event.data);
                container.appendChild(createDiv(event.data));
            }

            webSocket.onclose=function(event){
                console.log("connect close");
            }

            submitButton.onclick=function(){
                message=document.getElementById("message").value;
                if(message){
                    webSocket.send(message);
                    document.getElementById("message").value="";
                }else{
                    alert("请输入内容后,点击发送");
                }
            }

            function createDiv(message){
                var div=document.createElement("div");
                var textNode=document.createTextNode(message);
                div.appendChild(textNode);
                return div;
            }

        }


    </script>

</head>
<body>

<div id="container" style="border:1px solid #ccc; height:360px;width:600px;">

</div>

<input type="text" id="message"><input type="button" id="submit" value="发送">


</body>
</html>


进行测试:


截图06.png