实践如下:
1.配置主库my.cnf
[mysqld]
log-bin=mysql-testsyn-bin --主库二进制日志文件名的前缀
binlog-do-db=wb --要同步的数据库
server-id = 1 --serverid和辅库不同即可
修改为:
主库加帐号,10.51.178.1** 内网IP可以来访问,创建用户slave.拥有replication slave权限:
grant replication slave on *.* to "slave"@"10.51.178.1**" identified by "123FFFCCC6" with grant option;
用PHPMyadmin看也就是这两项权限: GRANT REPLICATION SLAVE ,不需要插入修改删除啥的,最小化。
查看主库状态:
show master status;
+------------------+----------+--------------+------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------+
| mysql-bin.000007 | 1606516 | | | |
+------------------+----------+--------------+------------------+-------------------+
配置辅库:
server-id = 2
master-host = 10.51.180.**
master-user = slave
master-password = 123FFFCCC6
master-port = 3306
master-connect-retry = 5 --重试间隔时间
replicate-do-db = wb --同步db
启动mysql ,查看辅库状态:
show slave status;
说明:
Slave_IO_Running:连接到主库,并读取主库的日志到本地,生成本地日志文件
Slave_SQL_Running:读取本地日志文件,并执行日志里的sql
把主库上的数据dump到辅库上
主库:10.51.180.**:
mysqldump --opt --master-data -uroot -p123FFFCCC6 > /home/mahaibo/dump-testsyn &
注意参数:--master-data
辅库:10.51.178.1**
先建立库:create database wb;
导入前停止同步:
stop slave
mysql -uroot -p123FFFCCC6 wb < /home/mahaibo/dump-testsyn
start slave;
必须先停止stop slave,然后才能导入
操作指南如下:
【=====================================
首先,关闭辅助库同步:
mysql> stop slave;
Query OK, 0 rows affected, 1 warning (0.00 sec)
其次,从主机上导出sql并在辅机上执行和主机一样。
第三,清空主机上所有位置: reset master;
mysql> reset master;
Query OK, 0 rows affected (0.01 sec)
mysql> show master status\G;
*************************** 1. row ***************************
File: mysql-bin.000001
Position: 120
Binlog_Do_DB: wb
Binlog_Ignore_DB:
Executed_Gtid_Set:
1 row in set (0.00 sec)
辅机:
mysql> show slave status\G;
Read_Master_Log_Pos: 4
第四,清空辅库的bin-log位置:
mysql> reset slave;
Query OK, 0 rows affected (0.00 sec)
第五,打开辅库的slave同步线程:
mysql> start slave;
Query OK, 0 rows affected (0.00 sec)
第六,看到辅库和主库的Read_Master_Log_Pos= 120 ,如下:
mysql> show slave status\G;
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 10.51.180.220
Master_User: slave
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysql-bin.000001
Read_Master_Log_Pos: 120
==============================================】
4.在主库10.51.180.**上在wb.user表里插入一条数据:
insert into users (username,password) values ('test1','test1');
辅库上的users表里也相应的有了数据。
5.查看主库二进制日志文件内容:
show binlog events;
注意:
1.主辅库同步主要是通过二进制日志来实现同步的。
2.在启动辅库的时候必须先把数据同步,并删除日志目录下的:master.info文件。因为master.info记录了上次要连接主库的信息,如果不删除,即使my.cnf里进行了修改,也不起作用。因为读取的还是master.info文件里的信息。
MySQL运行时间长了之后,二进制日志会占用大量硬盘空间,清楚这些日志的命令如下:
show binary logs;
purge master logs before now();
mysql> purge master logs before now();
Query OK, 0 rows affected, 1 warning (0.00 sec)
mysql> show binary logs;
+------------------+-----------+
| Log_name | File_size |
+------------------+-----------+
| mysql-bin.000004 | 46653 |
+------------------+-----------+
1 row in set (0.00 sec)
reset master 将删除日志索引文件中记录的所有binlog文件,创建一个新的日志文件 起始值从000001 开始,然而purge binary log 命令并不会修改记录binlog的顺序的数值
上面还有一个没有清掉,得用这个就彻底清了,120:
mysql> reset master;
Query OK, 0 rows affected (0.00 sec)
mysql> reset master;
Query OK, 0 rows affected (0.01 sec)
mysql> show binary logs;
+------------------+-----------+
| Log_name | File_size |
+------------------+-----------+
| mysql-bin.000001 | 120 |
+------------------+-----------+
1 row in set (0.00 sec)
mysql> RESET SLAVE
-> ;
Query OK, 0 rows affected (0.00 sec)
http://www.shangxueba.com/jingyan/1638441.html
————————————参考实践自如下链接————————————————————
http://blog.csdn.net/ljx0305/article/details/4371655
http://wenku.baidu.com/link?url=rK2b1ofBZnxgoQF5rW0JcjwU7Cn-WT6AuH_E29sOkgKDkEYeJQ6E5XGgt-NzAaYxuPzx25I_qJCB9Xe3F6QKTtILymCkKzFrEUi9rY_xtyO
新版本不支持master-host参数,[ERROR] /usr/local/mysql/bin/mysqld: unknown variable 'master-host=10.51.180.2**':
------解决方案--------------------
Mysql版本从5.1.7以后开始就不支持“master-host”类似的参数
在从库上执行如下命令;
change master to master_host='masterIP', master_user='slave', master_password='slvaePASS';
slave start;
切记:
此处是masterIP地址,不是slave地址,而登陆账号为slave账号密码
------解决方案--------------------
master-host=192.168.8.111
master-user=backup
master-password=backup
master-port=3306
master-connect-retry=60
这些参数 mysql5.5已经废弃了
必须在slave上用change master to 来设置slave
server-id = 2
#master-host = 10.51.180.** 新版本废弃
#master-user = slave
#master-password = 123FFFCCC6
#master-port = 3306
#master-connect-retry = 5
replicate-do-db = wb
mysql> change master to master_host='10.51.180.**', master_user='slave', master_password='123FFFCCC6';
Query OK, 0 rows affected, 2 warnings (0.02 sec)
mysql> stop slave;
Query OK, 0 rows affected, 1 warning (0.00 sec)
mysql> start slave;
Query OK, 0 rows affected (0.00 sec)
mysql> show slave status\G;
*************************** 1. row ***************************
Slave_IO_State: Connecting to master
Master_Host: 10.51.180.**
Master_User: slave
Master_Port: 3306
Connect_Retry: 60
Master_Log_File:
Read_Master_Log_Pos: 4
Relay_Log_File: mysql-relay-bin.000001
Relay_Log_Pos: 4
Relay_Master_Log_File:
Slave_IO_Running: Connecting
Slave_SQL_Running: Yes
Replicate_Do_DB: wb
.......
说明成功了,因为参数已经是Connecting和yes了:
Slave_IO_Running:连接到主库,并读取主库的日志到本地,生成本地日志文件
Slave_SQL_Running:读取本地日志文件,并执行日志里的sql
但此时还没有库,只是连接成功,于是,得从主库拉出数据,并停止辅库:
mysql> show databases; //slave没有wb表
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
+--------------------+
3 rows in set (0.00 sec)
照猫画虎建一个wb库:
mysql> show create database mysql;
+----------+----------------------------------------------------------------+
| Database | Create Database |
+----------+----------------------------------------------------------------+
| mysql | CREATE DATABASE `mysql` /*!40100 DEFAULT CHARACTER SET utf8 */ |
+----------+----------------------------------------------------------------+
1 row in set (0.00 sec)
mysql> CREATE DATABASE `wb` /*!40100 DEFAULT CHARACTER SET utf8 */ ;
Query OK, 1 row affected (0.00 sec)
从master下的mysql里导出表及数据sql:
10.51.180.**
mysqldump -uroot -p wb > wb2slave.09.24.sql
scp上步导出的sql到slave目录里source导入:
scp root@10.51.180.**:/root/wb2slave.09.24.sql ./
导入到刚才在slave建立的wb 库里:
mysql -uroot -p
mysql> use wb;
mysql> stop slave
Database changed
mysql> set names utf8;
Query OK, 0 rows affected (0.00 sec)
mysql> source /root/wb2slave.09.24.sql
Query OK, 0 rows affected (0.00 sec)
导入完成后,启动slave:
mysql> start slave;
Query OK, 0 rows affected (0.00 sec)
清掉刚才导入之前的,主库里的bin-log:
mysql> PURGE MASTER LOGS BEFORE '2015-09-24 17:05:00';
Query OK, 0 rows affected, 1 warning (0.00 sec)
mysql> show binary logs;
+------------------+-----------+
| Log_name | File_size |
+------------------+-----------+
| mysql-bin.000008 | 1222 |
+------------------+-----------+
mysql-bin.000007没有了,mysql-bin.000008一个了。
其它清理方法如下:
清除3天前的 binlog
PURGE MASTER LOGS BEFORE DATE_SUB( NOW( ), INTERVAL 3 DAY);
清指定文件的bin-log:
PURGE MASTER LOGS TO 'mysql-bin.000008';
清理MySQL的bin-log二进制日志
Posted by zuzhihui in mysql on 2011/11/27 with No Comments
MySQL运行时间长了之后,二进制日志会占用大量硬盘空间,清楚这些日志的命令如下:
show binary logs;
purge master logs before now();
重置mysql主从同步(MySQL Reset Master-Slave Replication):
reset master;
mysql> show binary logs;
+------------------+-----------+
| Log_name | File_size |
+------------------+-----------+
| mysql-bin.000001 | 120 |
+------------------+-----------+
http://www.shangxueba.com/jingyan/1638441.html
发现内外网不一致,加个外网:
Last_IO_Error: error connecting to master 'slave@10.51.180.220:3306' - retry-time: 60 retries: 1
Slave_SQL_Running_State: Slave has read all relay log; waiting for the slave I/O thread to update it
grant replication slave on *.* to "slave"@"10.51.180.*" identified by "123FFFCCC6" with grant option
grant replication slave on *.* to "slave"@"101.200.1.*" identified by "123FFFCCC6" with grant option
flush privileges;
一台服务器有内网ip和外网ip,如何通过iptables禁止访问本机的外网ip的某个端口,比如3306端口?
iptables防火墙 只允许某IP访问某端口、访问特定网站:
+++++++++++++++++主库:eth0 : 10.51.180.220++++++++++++++++++++++++++
让辅库IP10.51.178.1** 能访问到主的3306端口:
iptables -I INPUT -s 10.51.178.1** -p tcp --dport 3306 -j ACCEPT
写到开机启动里头 vi /etc/rc.local:
#开机就放开内部Mysql端口:让辅库内网IP能访问到该机器的3306备份端口
/usr/sbin/iptables -I INPUT -s 10.51.178.1** -p tcp --dport 3306 -j ACCEPT
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
http://www.sunzhenghua.com/msyql-grant-user-master-slave-replication-copy
参考:http://www.myexception.cn/mysql/387629.html
========================================================================
防火墙问题引起,Telnet 时出现,No route to host:
telnet :No route to host
telnet 10.51.180.** 3306
Trying 10.51.180.**...
telnet: connect to address 10.51.180.**: No route to host
[root@iZ258cfosv4Z ~]# telnet 10.51.180.** 3306
http://blog.sina.com.cn/s/blog_5022501501010pin.html
10.51.180.** //在主库上关闭掉iptables即可。
/bin/systemctl stop iptables.service
10.51.178.128
telnet 10.51.180.** 3306
Trying 10.51.180.**...
Connected to 10.51.180.**.
Escape character is '^]'.
测试连接:
mysql -uroot -h10.51.180.** -p
再测试这个,OK也就行了:
mysql -uslave -h10.51.180.** -p
show slave status\G;
Master_UUID: fef2f186-1fc5-11e5-9cb7-00163e0003e7
Slave_SQL_Running_State: Slave has read all relay log; waiting for the slave I/O thread to update it
change master to master_host='10.51.180.**', master_user='slave', master_password='123FFFCCC6';
Slave_IO_State: Waiting for master to send event
Master_Host: 10.51.180.**
Master_User: slave
Master_Port: 3306
Connect_Retry: 60
Read_Master_Log_Pos: 9687
Relay_Log_Pos: 820
Slave_IO_Running: Yes
Slave_SQL_Running: No
Replicate_Do_DB: wb
_________________________________________________________________________________
Could not find first log file name in binary log index file'的解决办法
数据库主从出错:
Slave_IO_Running: No 一方面原因是因为网络通信的问题也有可能是日志读取错误的问题。以下是日志出错问题的解决方案:
Last_IO_Error: Got fatal error 1236 from master when reading data from binary log: 'Could not find first log file name in binary log index file'
解决办法:
从机器停止slave
mysql> stop slave;
Query OK, 0 rows affected, 1 warning (0.00 sec)
mysql> reset master;
Query OK, 0 rows affected (0.00 sec)
mysql> show binary logs;
+------------------+-----------+
| Log_name | File_size |
+------------------+-----------+
| mysql-bin.000001 | 120 |
+------------------+-----------+
到master机器登陆mysql:
记录master的bin的位置,mysql> show master status;
+------------------+----------+--------------+------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------+
| mysql-bin.000001 | 120 | wb | | |
+------------------+----------+--------------+------------------+-------------------+
1 row in set (0.00 sec)
刷新日志:mysql> flush logs;
因为刷新日志file的位置会+1,即File变成为:mysqld-bin.000011
马上到slave执行
mysql> CHANGE MASTER TO MASTER_LOG_FILE='mysql-bin.000001',MASTER_LOG_POS=120;
Query OK, 0 rows affected (0.01 sec)
mysql> start slave;
Query OK, 0 rows affected (0.01 sec)
mysql> show slave status\G;
mysql> show slave status\G;
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 10.51.180.**
Master_User: slave
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysql-bin.000001
Read_Master_Log_Pos: 120
Relay_Log_File: mysql-relay-bin.000002
Relay_Log_Pos: 283
Relay_Master_Log_File: mysql-bin.000001
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
Replicate_Do_DB: wb
Master_Server_Id: 1
Master_UUID: fef2f186-1fc5-11e5-9cb7-00163e0003e7
Master_Info_File: /data/mysql/master.info
SQL_Delay: 0
SQL_Remaining_Delay: NULL
Slave_SQL_Running_State: Slave has read all relay log; waiting for the slave I/O thread to update it
Master_Retry_Count: 86400
Master_Bind:
正常了。
1.配置主库my.cnf
[mysqld]
log-bin=mysql-testsyn-bin --主库二进制日志文件名的前缀
binlog-do-db=wb --要同步的数据库
server-id = 1 --serverid和辅库不同即可
修改为:
主库加帐号,10.51.178.1** 内网IP可以来访问,创建用户slave.拥有replication slave权限:
grant replication slave on *.* to "slave"@"10.51.178.1**" identified by "123FFFCCC6" with grant option;
用PHPMyadmin看也就是这两项权限: GRANT REPLICATION SLAVE ,不需要插入修改删除啥的,最小化。
查看主库状态:
show master status;
+------------------+----------+--------------+------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------+
| mysql-bin.000007 | 1606516 | | | |
+------------------+----------+--------------+------------------+-------------------+
配置辅库:
server-id = 2
master-host = 10.51.180.**
master-user = slave
master-password = 123FFFCCC6
master-port = 3306
master-connect-retry = 5 --重试间隔时间
replicate-do-db = wb --同步db
启动mysql ,查看辅库状态:
show slave status;
说明:
Slave_IO_Running:连接到主库,并读取主库的日志到本地,生成本地日志文件
Slave_SQL_Running:读取本地日志文件,并执行日志里的sql
把主库上的数据dump到辅库上
主库:10.51.180.**:
mysqldump --opt --master-data -uroot -p123FFFCCC6 > /home/mahaibo/dump-testsyn &
注意参数:--master-data
辅库:10.51.178.1**
先建立库:create database wb;
导入前停止同步:
stop slave
mysql -uroot -p123FFFCCC6 wb < /home/mahaibo/dump-testsyn
start slave;
必须先停止stop slave,然后才能导入
操作指南如下:
【=====================================
首先,关闭辅助库同步:
mysql> stop slave;
Query OK, 0 rows affected, 1 warning (0.00 sec)
其次,从主机上导出sql并在辅机上执行和主机一样。
第三,清空主机上所有位置: reset master;
mysql> reset master;
Query OK, 0 rows affected (0.01 sec)
mysql> show master status\G;
*************************** 1. row ***************************
File: mysql-bin.000001
Position: 120
Binlog_Do_DB: wb
Binlog_Ignore_DB:
Executed_Gtid_Set:
1 row in set (0.00 sec)
辅机:
mysql> show slave status\G;
Read_Master_Log_Pos: 4
第四,清空辅库的bin-log位置:
mysql> reset slave;
Query OK, 0 rows affected (0.00 sec)
第五,打开辅库的slave同步线程:
mysql> start slave;
Query OK, 0 rows affected (0.00 sec)
第六,看到辅库和主库的Read_Master_Log_Pos= 120 ,如下:
mysql> show slave status\G;
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 10.51.180.220
Master_User: slave
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysql-bin.000001
Read_Master_Log_Pos: 120
==============================================】
4.在主库10.51.180.**上在wb.user表里插入一条数据:
insert into users (username,password) values ('test1','test1');
辅库上的users表里也相应的有了数据。
5.查看主库二进制日志文件内容:
show binlog events;
注意:
1.主辅库同步主要是通过二进制日志来实现同步的。
2.在启动辅库的时候必须先把数据同步,并删除日志目录下的:master.info文件。因为master.info记录了上次要连接主库的信息,如果不删除,即使my.cnf里进行了修改,也不起作用。因为读取的还是master.info文件里的信息。
MySQL运行时间长了之后,二进制日志会占用大量硬盘空间,清楚这些日志的命令如下:
show binary logs;
purge master logs before now();
mysql> purge master logs before now();
Query OK, 0 rows affected, 1 warning (0.00 sec)
mysql> show binary logs;
+------------------+-----------+
| Log_name | File_size |
+------------------+-----------+
| mysql-bin.000004 | 46653 |
+------------------+-----------+
1 row in set (0.00 sec)
reset master 将删除日志索引文件中记录的所有binlog文件,创建一个新的日志文件 起始值从000001 开始,然而purge binary log 命令并不会修改记录binlog的顺序的数值
上面还有一个没有清掉,得用这个就彻底清了,120:
mysql> reset master;
Query OK, 0 rows affected (0.00 sec)
mysql> reset master;
Query OK, 0 rows affected (0.01 sec)
mysql> show binary logs;
+------------------+-----------+
| Log_name | File_size |
+------------------+-----------+
| mysql-bin.000001 | 120 |
+------------------+-----------+
1 row in set (0.00 sec)
mysql> RESET SLAVE
-> ;
Query OK, 0 rows affected (0.00 sec)
http://www.shangxueba.com/jingyan/1638441.html
————————————参考实践自如下链接————————————————————
http://blog.csdn.net/ljx0305/article/details/4371655
http://wenku.baidu.com/link?url=rK2b1ofBZnxgoQF5rW0JcjwU7Cn-WT6AuH_E29sOkgKDkEYeJQ6E5XGgt-NzAaYxuPzx25I_qJCB9Xe3F6QKTtILymCkKzFrEUi9rY_xtyO
新版本不支持master-host参数,[ERROR] /usr/local/mysql/bin/mysqld: unknown variable 'master-host=10.51.180.2**':
------解决方案--------------------
Mysql版本从5.1.7以后开始就不支持“master-host”类似的参数
在从库上执行如下命令;
change master to master_host='masterIP', master_user='slave', master_password='slvaePASS';
slave start;
切记:
此处是masterIP地址,不是slave地址,而登陆账号为slave账号密码
------解决方案--------------------
master-host=192.168.8.111
master-user=backup
master-password=backup
master-port=3306
master-connect-retry=60
这些参数 mysql5.5已经废弃了
必须在slave上用change master to 来设置slave
server-id = 2
#master-host = 10.51.180.** 新版本废弃
#master-user = slave
#master-password = 123FFFCCC6
#master-port = 3306
#master-connect-retry = 5
replicate-do-db = wb
mysql> change master to master_host='10.51.180.**', master_user='slave', master_password='123FFFCCC6';
Query OK, 0 rows affected, 2 warnings (0.02 sec)
mysql> stop slave;
Query OK, 0 rows affected, 1 warning (0.00 sec)
mysql> start slave;
Query OK, 0 rows affected (0.00 sec)
mysql> show slave status\G;
*************************** 1. row ***************************
Slave_IO_State: Connecting to master
Master_Host: 10.51.180.**
Master_User: slave
Master_Port: 3306
Connect_Retry: 60
Master_Log_File:
Read_Master_Log_Pos: 4
Relay_Log_File: mysql-relay-bin.000001
Relay_Log_Pos: 4
Relay_Master_Log_File:
Slave_IO_Running: Connecting
Slave_SQL_Running: Yes
Replicate_Do_DB: wb
.......
说明成功了,因为参数已经是Connecting和yes了:
Slave_IO_Running:连接到主库,并读取主库的日志到本地,生成本地日志文件
Slave_SQL_Running:读取本地日志文件,并执行日志里的sql
但此时还没有库,只是连接成功,于是,得从主库拉出数据,并停止辅库:
mysql> show databases; //slave没有wb表
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
+--------------------+
3 rows in set (0.00 sec)
照猫画虎建一个wb库:
mysql> show create database mysql;
+----------+----------------------------------------------------------------+
| Database | Create Database |
+----------+----------------------------------------------------------------+
| mysql | CREATE DATABASE `mysql` /*!40100 DEFAULT CHARACTER SET utf8 */ |
+----------+----------------------------------------------------------------+
1 row in set (0.00 sec)
mysql> CREATE DATABASE `wb` /*!40100 DEFAULT CHARACTER SET utf8 */ ;
Query OK, 1 row affected (0.00 sec)
从master下的mysql里导出表及数据sql:
10.51.180.**
mysqldump -uroot -p wb > wb2slave.09.24.sql
scp上步导出的sql到slave目录里source导入:
scp root@10.51.180.**:/root/wb2slave.09.24.sql ./
导入到刚才在slave建立的wb 库里:
mysql -uroot -p
mysql> use wb;
mysql> stop slave
Database changed
mysql> set names utf8;
Query OK, 0 rows affected (0.00 sec)
mysql> source /root/wb2slave.09.24.sql
Query OK, 0 rows affected (0.00 sec)
导入完成后,启动slave:
mysql> start slave;
Query OK, 0 rows affected (0.00 sec)
清掉刚才导入之前的,主库里的bin-log:
mysql> PURGE MASTER LOGS BEFORE '2015-09-24 17:05:00';
Query OK, 0 rows affected, 1 warning (0.00 sec)
mysql> show binary logs;
+------------------+-----------+
| Log_name | File_size |
+------------------+-----------+
| mysql-bin.000008 | 1222 |
+------------------+-----------+
mysql-bin.000007没有了,mysql-bin.000008一个了。
其它清理方法如下:
清除3天前的 binlog
PURGE MASTER LOGS BEFORE DATE_SUB( NOW( ), INTERVAL 3 DAY);
清指定文件的bin-log:
PURGE MASTER LOGS TO 'mysql-bin.000008';
清理MySQL的bin-log二进制日志
Posted by zuzhihui in mysql on 2011/11/27 with No Comments
MySQL运行时间长了之后,二进制日志会占用大量硬盘空间,清楚这些日志的命令如下:
show binary logs;
purge master logs before now();
重置mysql主从同步(MySQL Reset Master-Slave Replication):
reset master;
mysql> show binary logs;
+------------------+-----------+
| Log_name | File_size |
+------------------+-----------+
| mysql-bin.000001 | 120 |
+------------------+-----------+
http://www.shangxueba.com/jingyan/1638441.html
发现内外网不一致,加个外网:
Last_IO_Error: error connecting to master 'slave@10.51.180.220:3306' - retry-time: 60 retries: 1
Slave_SQL_Running_State: Slave has read all relay log; waiting for the slave I/O thread to update it
grant replication slave on *.* to "slave"@"10.51.180.*" identified by "123FFFCCC6" with grant option
grant replication slave on *.* to "slave"@"101.200.1.*" identified by "123FFFCCC6" with grant option
flush privileges;
一台服务器有内网ip和外网ip,如何通过iptables禁止访问本机的外网ip的某个端口,比如3306端口?
iptables防火墙 只允许某IP访问某端口、访问特定网站:
+++++++++++++++++主库:eth0 : 10.51.180.220++++++++++++++++++++++++++
让辅库IP10.51.178.1** 能访问到主的3306端口:
iptables -I INPUT -s 10.51.178.1** -p tcp --dport 3306 -j ACCEPT
写到开机启动里头 vi /etc/rc.local:
#开机就放开内部Mysql端口:让辅库内网IP能访问到该机器的3306备份端口
/usr/sbin/iptables -I INPUT -s 10.51.178.1** -p tcp --dport 3306 -j ACCEPT
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
http://www.sunzhenghua.com/msyql-grant-user-master-slave-replication-copy
参考:http://www.myexception.cn/mysql/387629.html
========================================================================
防火墙问题引起,Telnet 时出现,No route to host:
telnet :No route to host
telnet 10.51.180.** 3306
Trying 10.51.180.**...
telnet: connect to address 10.51.180.**: No route to host
[root@iZ258cfosv4Z ~]# telnet 10.51.180.** 3306
http://blog.sina.com.cn/s/blog_5022501501010pin.html
10.51.180.** //在主库上关闭掉iptables即可。
/bin/systemctl stop iptables.service
10.51.178.128
telnet 10.51.180.** 3306
Trying 10.51.180.**...
Connected to 10.51.180.**.
Escape character is '^]'.
测试连接:
mysql -uroot -h10.51.180.** -p
再测试这个,OK也就行了:
mysql -uslave -h10.51.180.** -p
show slave status\G;
Master_UUID: fef2f186-1fc5-11e5-9cb7-00163e0003e7
Slave_SQL_Running_State: Slave has read all relay log; waiting for the slave I/O thread to update it
change master to master_host='10.51.180.**', master_user='slave', master_password='123FFFCCC6';
Slave_IO_State: Waiting for master to send event
Master_Host: 10.51.180.**
Master_User: slave
Master_Port: 3306
Connect_Retry: 60
Read_Master_Log_Pos: 9687
Relay_Log_Pos: 820
Slave_IO_Running: Yes
Slave_SQL_Running: No
Replicate_Do_DB: wb
_________________________________________________________________________________
Could not find first log file name in binary log index file'的解决办法
数据库主从出错:
Slave_IO_Running: No 一方面原因是因为网络通信的问题也有可能是日志读取错误的问题。以下是日志出错问题的解决方案:
Last_IO_Error: Got fatal error 1236 from master when reading data from binary log: 'Could not find first log file name in binary log index file'
解决办法:
从机器停止slave
mysql> stop slave;
Query OK, 0 rows affected, 1 warning (0.00 sec)
mysql> reset master;
Query OK, 0 rows affected (0.00 sec)
mysql> show binary logs;
+------------------+-----------+
| Log_name | File_size |
+------------------+-----------+
| mysql-bin.000001 | 120 |
+------------------+-----------+
到master机器登陆mysql:
记录master的bin的位置,mysql> show master status;
+------------------+----------+--------------+------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------+
| mysql-bin.000001 | 120 | wb | | |
+------------------+----------+--------------+------------------+-------------------+
1 row in set (0.00 sec)
刷新日志:mysql> flush logs;
因为刷新日志file的位置会+1,即File变成为:mysqld-bin.000011
马上到slave执行
mysql> CHANGE MASTER TO MASTER_LOG_FILE='mysql-bin.000001',MASTER_LOG_POS=120;
Query OK, 0 rows affected (0.01 sec)
mysql> start slave;
Query OK, 0 rows affected (0.01 sec)
mysql> show slave status\G;
mysql> show slave status\G;
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 10.51.180.**
Master_User: slave
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysql-bin.000001
Read_Master_Log_Pos: 120
Relay_Log_File: mysql-relay-bin.000002
Relay_Log_Pos: 283
Relay_Master_Log_File: mysql-bin.000001
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
Replicate_Do_DB: wb
Master_Server_Id: 1
Master_UUID: fef2f186-1fc5-11e5-9cb7-00163e0003e7
Master_Info_File: /data/mysql/master.info
SQL_Delay: 0
SQL_Remaining_Delay: NULL
Slave_SQL_Running_State: Slave has read all relay log; waiting for the slave I/O thread to update it
Master_Retry_Count: 86400
Master_Bind:
正常了。
diff 用过吗?老大让我a.log b.log 比较出相同,后将相同从a.log中去掉,然后显示出剩下的放入到文件x.log
==> a.log <==
1
3
2
==> b.log <==
5
4
2
3
[code]diff aa.log bb.log 结果如何记忆? <:表示a独特有的,>:表示b独特有的!
aa.log中有1在bb.log中没有,于是<1,同样:bb.log有4,5在aa.log中没有,于是:>4 >5 :
[~]# diff aa.log bb.log
1d0
< 1
3a3,4
> 4
> 5
[/code]
假设文件有5列,我想按照第3列排序应该怎么使用sort命令呢?
sort -k 3 yourfile.txt
我现在写shell统计遇到一个问题, 比如一个文件a里是
1,02
2,05
这种格式
另一个文件b里是
3,02
5,05
这种格式,我想让如果a b 逗号后面(02或05)的相同的话, 则把 b的 逗号前面的(3或5) 放在 a 对应的后面
怎么做啊?
awk -F, 'NR==FNR{a[$2]=$1}NR>FNR{print $0","a[$2]}' fileb filea
我们再来个示例:
文件:a.txt b.txt
cat a.txt
[root@vm19 diff]# cat a.txt
asp
php
jsp
csp
zzz
cat b.txt
[root@vm19 diff]# cat b.txt
jsp
php
asp
csp
java
c
python
排序a.txt b.txt
sort b.txt >>bbb.txt
sort a.txt >>aaa.txt
[root@vm19 diff]# cat aaa.txt
asp
csp
jsp
php
zzz
[root@vm19 diff]# cat bbb.txt
asp
c
csp
java
jsp
php
python
diff一下:
[root@vm19 diff]# diff bbb.txt aaa.txt
2d1
< c
4d2
< java
7c5
< python
---
> zzz
找出bbb.txt和aaa.txt中bbb.txt和aaa.txt中多余的程序语言
diff bbb.txt aaa.txt|grep -r "<"
[root@vm19 diff]# diff bbb.txt aaa.txt|grep -r "<"
< c
< java
< python
找出bbb.txt和aaa.txt中bbb.txt和aaa.txt比较中bbb.txt中没有的
[root@vm19 diff]# diff bbb.txt aaa.txt|grep -r ">"
> zzz
一个语句完成也行:但是注意取出空行空格:
diff <(sort -n a.txt) <(sort -n b.txt)
=============================================
PS技巧:
如何过滤掉 “< ”
务必参考:http://www.jackxiang.com/post/3484/
==> a.log <==
1
3
2
==> b.log <==
5
4
2
3
sort a.log >> aa.log
sort b.log >> bb.log
diff aa.log bb.log |grep "<" >> x.log
//还好老大给出了这个比较方法。。sort b.log >> bb.log
diff aa.log bb.log |grep "<" >> x.log
[code]diff aa.log bb.log 结果如何记忆? <:表示a独特有的,>:表示b独特有的!
aa.log中有1在bb.log中没有,于是<1,同样:bb.log有4,5在aa.log中没有,于是:>4 >5 :
[~]# diff aa.log bb.log
1d0
< 1
3a3,4
> 4
> 5
[/code]
假设文件有5列,我想按照第3列排序应该怎么使用sort命令呢?
sort -k 3 yourfile.txt
我现在写shell统计遇到一个问题, 比如一个文件a里是
1,02
2,05
这种格式
另一个文件b里是
3,02
5,05
这种格式,我想让如果a b 逗号后面(02或05)的相同的话, 则把 b的 逗号前面的(3或5) 放在 a 对应的后面
怎么做啊?
awk -F, 'NR==FNR{a[$2]=$1}NR>FNR{print $0","a[$2]}' fileb filea
我们再来个示例:
文件:a.txt b.txt
cat a.txt
[root@vm19 diff]# cat a.txt
asp
php
jsp
csp
zzz
cat b.txt
[root@vm19 diff]# cat b.txt
jsp
php
asp
csp
java
c
python
排序a.txt b.txt
sort b.txt >>bbb.txt
sort a.txt >>aaa.txt
[root@vm19 diff]# cat aaa.txt
asp
csp
jsp
php
zzz
[root@vm19 diff]# cat bbb.txt
asp
c
csp
java
jsp
php
python
diff一下:
[root@vm19 diff]# diff bbb.txt aaa.txt
2d1
< c
4d2
< java
7c5
< python
---
> zzz
找出bbb.txt和aaa.txt中bbb.txt和aaa.txt中多余的程序语言
diff bbb.txt aaa.txt|grep -r "<"
[root@vm19 diff]# diff bbb.txt aaa.txt|grep -r "<"
< c
< java
< python
找出bbb.txt和aaa.txt中bbb.txt和aaa.txt比较中bbb.txt中没有的
[root@vm19 diff]# diff bbb.txt aaa.txt|grep -r ">"
> zzz
一个语句完成也行:但是注意取出空行空格:
diff <(sort -n a.txt) <(sort -n b.txt)
=============================================
PS技巧:
如何过滤掉 “< ”
diff a.txt b.txt |grep "<"|awk -F"< " '{print $2}' > ddd.txt
务必参考:http://www.jackxiang.com/post/3484/
1. 准备
创建一个测试表:
然后创建一个存储过程填充数据:
run stroe process:
删除存储过程:
查看存储过程:
来看看到底有多少条记录了,以及索引情况:
2. 对比
2.1 只检索一条记录
2.2 范围检索(我发现当大于时候根本没有用到索引,小于用到了)
小贴士:
explain select * from t where d2 <= from_unixtime(1199894400); key_len :为4
explain select * from t where d3 <= from_unixtime(1199894400); key_len :为8
效率体现出来了吧?呵呵!
话外音:当大于时候根本没有用到索引,如下:(和下面in和=关于索引的情况类似,但这个> 和< 的情况我还是不太清楚,呵呵)
小结:从上面的2次对比中可以看到,对 d1 或 d2 字段检索时的索引长度都是 4,因为 TIMESTAMP 实际上是 4字节 的 INT 值。因此,实际应用中,基本上完全可以采用 TIMESTAMP 来代替另外2种类型了,并且 TIMESTAMP 还能支持自动更新成当前最新时间,何乐而不为呢?
in 和 = 在索引上的区别,建表:
发现用上了uid的索引,但这个in语句:
没有用上uid索引。
为此:认为要建立联合索引?是的,不光是要建立联合索引,而且和顺序有关,如建立:
alter table mytest add index tt(uid,rstatus);
也没有用,这样后运行:
也没有用到我们想要的tt索引,但是,我们将联合索引换个顺序:
执行:
如下说明:
1.in 和 = 在索引机制上的不同!
2.in 的mysql索引和顺序有关!
最后:我去掉联合索引,加入了强制用uid的索引:
但:
来源:
http://imysql.cn/2008_07_17_timestamp_vs_int_and_datetime
修正了存储过程的代码!
附录:
描述
CREATE PROCEDURE
建立一个存放在MySQL数据库的表格的存储过程。
CREATE FUNCTION
建立一个用户自定义的函数,尤其是返回数据的存储过程。
ALTER PROCEDURE
更改用CREATE PROCEDURE 建立的预先指定的存储过程,其不会影响相关存储过程或存储功能。.
ALTER FUNCTION
更改用CREATE FUNCTION 建立的预先指定的存储过程,其不会影响相关存储过程或存储功能。.
DROP PROCEDURE
从MySQL的表格中删除一个或多个存储过程。
DROP FUNCTION
从MySQL的表格中删除一个或多个存储函数。
SHOW CREATE PROCEDURE
返回使用CREATE PROCEDURE 建立的预先指定的存储过程的文本。这一声明是SQL:2003规范的一个MySQL扩展。
SHOW CREATE FUNCTION
返回使用CREATE FUNCTION建立的预先指定的存储过程的文本。这一声明是SQL:2003规范的一个MySQL扩展。
SHOW PROCEDURE STATUS
返回一个预先指定的存储过程的特性,包括名称、类型、建立者、建立日期、以及更改日期。这一声明是SQL:2003规范的一个MySQL扩展。
SHOW FUNCTION STATUS
返回一个预先指定的存储函数的特性,包括名称、类型、建立者、建立日期、以及更改日期。这一声明是SQL:2003规范的一个MySQL扩展。
CALL
调用一个使用CREATE PROCEDURE建立的预先指定的存储过程。
BEGIN ... END
包含一组执行的多声明。
DECLARE
用于指定当地变量、环境、处理器,以及指针。
SET
用于更改当地和全局服务器变量的值。
SELECT ... INTO
用于存储显示变量的纵列。
OPEN
用于打开一个指针。
FETCH
使用特定指针来获得下一列。
CLOSE
用于关闭和打开指针。
IF
一个An if-then-else-end if 声明。
CASE ... WHEN
一个 case声明的结构
LOOP
一个简单的循环结构;可以使用LEAVE 语句来退出。
LEAVE
用于退出IF,CASE,LOOP,REPEAT以及WHILE 语句。
ITERATE
用于重新开始循环。
REPEAT
在结束时测试的循环。
WHILE
在开始时测试的循环。
RETURNS
返回一个存储过程的值。
创建一个测试表:
mysql> CREATE TABLE `t` (
`d1` int(10) unsigned NOT NULL default '0',
`d2` timestamp NOT NULL default CURRENT_TIMESTAMP,
`d3` datetime NOT NULL,
KEY `d2` (`d2`),
KEY `d1` (`d1`),
KEY `d3` (`d3`)
);
`d1` int(10) unsigned NOT NULL default '0',
`d2` timestamp NOT NULL default CURRENT_TIMESTAMP,
`d3` datetime NOT NULL,
KEY `d2` (`d2`),
KEY `d1` (`d1`),
KEY `d3` (`d3`)
);
然后创建一个存储过程填充数据:
mysql> DELIMITER //
CREATE PROCEDURE INS_T()
BEGIN
SET @i=1;
WHILE 0<1
DO
SET @i=@i+1;
INSERT INTO t VALUES (1199116800+@i, FROM_UNIXTIME(1199116800+@i), FROM_UNIXTIME(1199116800+@i));
END WHILE;
END;//
DELIMITER ;
CREATE PROCEDURE INS_T()
BEGIN
SET @i=1;
WHILE 0<1
DO
SET @i=@i+1;
INSERT INTO t VALUES (1199116800+@i, FROM_UNIXTIME(1199116800+@i), FROM_UNIXTIME(1199116800+@i));
END WHILE;
END;//
DELIMITER ;
run stroe process:
call INS_T();
时间戳 1199116800 表示 2008-01-01 这个时间点。然后运行存储过程,大概填充几十万条记录后,中止执行,因为上面的存储过程是个死循环,所以需要人工中止(ctrl+c)。删除存储过程:
DROP PROCEDURE test.INS_T;
查看存储过程:
SHOW CREATE PROCEDURE test.INS_T;
来看看到底有多少条记录了,以及索引情况:
mysql> select count(*) from t;
+----------+
| count(*) |
+----------+
| 924707 |
+----------+
mysql> analyze table t;
+--------+---------+----------+-----------------------------+
| Table | Op | Msg_type | Msg_text |
+--------+---------+----------+-----------------------------+
| test.t | analyze | status | Table is already up to date |
+--------+---------+----------+-----------------------------+
mysql> show index from t;
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment |
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| t | 1 | d2 | 1 | d2 | A | 924707 | NULL | NULL | | BTREE | |
| t | 1 | d1 | 1 | d1 | A | 924707 | NULL | NULL | | BTREE | |
| t | 1 | d3 | 1 | d3 | A | 924707 | NULL | NULL | | BTREE | |
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
+----------+
| count(*) |
+----------+
| 924707 |
+----------+
mysql> analyze table t;
+--------+---------+----------+-----------------------------+
| Table | Op | Msg_type | Msg_text |
+--------+---------+----------+-----------------------------+
| test.t | analyze | status | Table is already up to date |
+--------+---------+----------+-----------------------------+
mysql> show index from t;
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment |
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| t | 1 | d2 | 1 | d2 | A | 924707 | NULL | NULL | | BTREE | |
| t | 1 | d1 | 1 | d1 | A | 924707 | NULL | NULL | | BTREE | |
| t | 1 | d3 | 1 | d3 | A | 924707 | NULL | NULL | | BTREE | |
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
2. 对比
2.1 只检索一条记录
mysql> explain select * from t where d1 = 1199579155;
+----+-------------+-------+------+---------------+------+---------+-------+------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+-------+------+-------+
| 1 | SIMPLE | t | ref | d1 | d1 | 4 | const | 1 | |
+----+-------------+-------+------+---------------+------+---------+-------+------+-------+
mysql> explain select * from t where d2 = '2008-01-06 08:25:55';
+----+-------------+-------+------+---------------+------+---------+-------+------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+-------+------+-------+
| 1 | SIMPLE | t | ref | d2 | d2 | 4 | const | 1 | |
+----+-------------+-------+------+---------------+------+---------+-------+------+-------+
mysql> explain select * from t where d3 = '2008-01-06 08:25:55';
+----+-------------+-------+------+---------------+------+---------+-------+------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+-------+------+-------+
| 1 | SIMPLE | t | ref | d3 | d3 | 8 | const | 1 | |
+----+-------------+-------+------+---------------+------+---------+-------+------+-------+
+----+-------------+-------+------+---------------+------+---------+-------+------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+-------+------+-------+
| 1 | SIMPLE | t | ref | d1 | d1 | 4 | const | 1 | |
+----+-------------+-------+------+---------------+------+---------+-------+------+-------+
mysql> explain select * from t where d2 = '2008-01-06 08:25:55';
+----+-------------+-------+------+---------------+------+---------+-------+------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+-------+------+-------+
| 1 | SIMPLE | t | ref | d2 | d2 | 4 | const | 1 | |
+----+-------------+-------+------+---------------+------+---------+-------+------+-------+
mysql> explain select * from t where d3 = '2008-01-06 08:25:55';
+----+-------------+-------+------+---------------+------+---------+-------+------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+-------+------+-------+
| 1 | SIMPLE | t | ref | d3 | d3 | 8 | const | 1 | |
+----+-------------+-------+------+---------------+------+---------+-------+------+-------+
2.2 范围检索(我发现当大于时候根本没有用到索引,小于用到了)
mysql> explain select * from t where d1 <= 1199894400;
+----+-------------+-------+-------+---------------+------+---------+------+--------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+------+---------+------+--------+-------------+
| 1 | SIMPLE | t | range | d1 | d1 | 4 | NULL | 121961 | Using where |
+----+-------------+-------+-------+---------------+------+---------+------+--------+-------------+
mysql> explain select * from t where d2 <= from_unixtime(1199894400);
+----+-------------+-------+-------+---------------+------+---------+------+--------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+------+---------+------+--------+-------------+
| 1 | SIMPLE | t | range | d2 | d2 | 4 | NULL | 121961 | Using where |
+----+-------------+-------+-------+---------------+------+---------+------+--------+-------------+
mysql> explain select * from t where d3 <= from_unixtime(1199894400);
+----+-------------+-------+-------+---------------+------+---------+------+--------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+------+---------+------+--------+-------------+
| 1 | SIMPLE | t | range | d3 | d3 | 8 | NULL | 120625 | Using where |
+----+-------------+-------+-------+---------------+------+---------+------+--------+-------------+
+----+-------------+-------+-------+---------------+------+---------+------+--------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+------+---------+------+--------+-------------+
| 1 | SIMPLE | t | range | d1 | d1 | 4 | NULL | 121961 | Using where |
+----+-------------+-------+-------+---------------+------+---------+------+--------+-------------+
mysql> explain select * from t where d2 <= from_unixtime(1199894400);
+----+-------------+-------+-------+---------------+------+---------+------+--------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+------+---------+------+--------+-------------+
| 1 | SIMPLE | t | range | d2 | d2 | 4 | NULL | 121961 | Using where |
+----+-------------+-------+-------+---------------+------+---------+------+--------+-------------+
mysql> explain select * from t where d3 <= from_unixtime(1199894400);
+----+-------------+-------+-------+---------------+------+---------+------+--------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+------+---------+------+--------+-------------+
| 1 | SIMPLE | t | range | d3 | d3 | 8 | NULL | 120625 | Using where |
+----+-------------+-------+-------+---------------+------+---------+------+--------+-------------+
小贴士:
explain select * from t where d2 <= from_unixtime(1199894400); key_len :为4
explain select * from t where d3 <= from_unixtime(1199894400); key_len :为8
效率体现出来了吧?呵呵!
话外音:当大于时候根本没有用到索引,如下:(和下面in和=关于索引的情况类似,但这个> 和< 的情况我还是不太清楚,呵呵)
mysql> explain select * from t where d1 >= 1199894400;
+----+-------------+-------+------+---------------+------+---------+------+---------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+---------+-------------+
| 1 | SIMPLE | t | ALL | d1 | NULL | NULL | NULL | 9871898 | Using where |
+----+-------------+-------+------+---------------+------+---------+------+---------+-------------+
mysql> explain select * from t where d2 >= from_unixtime(1199894400);
+----+-------------+-------+------+---------------+------+---------+------+---------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+---------+-------------+
| 1 | SIMPLE | t | ALL | d2 | NULL | NULL | NULL | 9871898 | Using where |
+----+-------------+-------+------+---------------+------+---------+------+---------+-------------+
mysql> explain select * from t where d3 >= from_unixtime(1199894400);
+----+-------------+-------+------+---------------+------+---------+------+---------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+---------+-------------+
| 1 | SIMPLE | t | ALL | d3 | NULL | NULL | NULL | 9871898 | Using where |
+----+-------------+-------+------+---------------+------+---------+------+---------+-------------+
+----+-------------+-------+------+---------------+------+---------+------+---------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+---------+-------------+
| 1 | SIMPLE | t | ALL | d1 | NULL | NULL | NULL | 9871898 | Using where |
+----+-------------+-------+------+---------------+------+---------+------+---------+-------------+
mysql> explain select * from t where d2 >= from_unixtime(1199894400);
+----+-------------+-------+------+---------------+------+---------+------+---------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+---------+-------------+
| 1 | SIMPLE | t | ALL | d2 | NULL | NULL | NULL | 9871898 | Using where |
+----+-------------+-------+------+---------------+------+---------+------+---------+-------------+
mysql> explain select * from t where d3 >= from_unixtime(1199894400);
+----+-------------+-------+------+---------------+------+---------+------+---------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+---------+-------------+
| 1 | SIMPLE | t | ALL | d3 | NULL | NULL | NULL | 9871898 | Using where |
+----+-------------+-------+------+---------------+------+---------+------+---------+-------------+
小结:从上面的2次对比中可以看到,对 d1 或 d2 字段检索时的索引长度都是 4,因为 TIMESTAMP 实际上是 4字节 的 INT 值。因此,实际应用中,基本上完全可以采用 TIMESTAMP 来代替另外2种类型了,并且 TIMESTAMP 还能支持自动更新成当前最新时间,何乐而不为呢?
in 和 = 在索引上的区别,建表:
CREATE TABLE `mytest` (
`id` int(11) NOT NULL auto_increment,
`uid` int(11) NOT NULL,
`rstatus` int(11) default NULL,
PRIMARY KEY (`id`),
KEY `uid` (`uid`)
) ENGINE=MyISAM AUTO_INCREMENT=16 DEFAULT CHARSET=utf8
`id` int(11) NOT NULL auto_increment,
`uid` int(11) NOT NULL,
`rstatus` int(11) default NULL,
PRIMARY KEY (`id`),
KEY `uid` (`uid`)
) ENGINE=MyISAM AUTO_INCREMENT=16 DEFAULT CHARSET=utf8
EXPLAIN SELECT *
FROM `mytest`
FORCE INDEX ( uid )
WHERE uid =1
AND rstatus =1
FROM `mytest`
FORCE INDEX ( uid )
WHERE uid =1
AND rstatus =1
发现用上了uid的索引,但这个in语句:
explain SELECT * FROM `mytest` WHERE uid IN ( 1,2,7) and rstatus =1
没有用上uid索引。
为此:认为要建立联合索引?是的,不光是要建立联合索引,而且和顺序有关,如建立:
alter table mytest add index tt(uid,rstatus);
也没有用,这样后运行:
explain SELECT * FROM `mytest` WHERE uid IN ( 1,2,7) and rstatus =1
也没有用到我们想要的tt索引,但是,我们将联合索引换个顺序:
alter table mytest add index tt(rstatus,uid);
执行:
explain SELECT * FROM `mytest` WHERE uid IN ( 1,2,7) and rstatus =1
,就用到了我们的联合索引了!如下说明:
1.in 和 = 在索引机制上的不同!
2.in 的mysql索引和顺序有关!
最后:我去掉联合索引,加入了强制用uid的索引:
但:
SELECT * FROM `mytest` force index(uid) WHERE uid IN ( 1,2,7) and rstatus =1
也就ok了!来源:
http://imysql.cn/2008_07_17_timestamp_vs_int_and_datetime
修正了存储过程的代码!
附录:
描述
CREATE PROCEDURE
建立一个存放在MySQL数据库的表格的存储过程。
CREATE FUNCTION
建立一个用户自定义的函数,尤其是返回数据的存储过程。
ALTER PROCEDURE
更改用CREATE PROCEDURE 建立的预先指定的存储过程,其不会影响相关存储过程或存储功能。.
ALTER FUNCTION
更改用CREATE FUNCTION 建立的预先指定的存储过程,其不会影响相关存储过程或存储功能。.
DROP PROCEDURE
从MySQL的表格中删除一个或多个存储过程。
DROP FUNCTION
从MySQL的表格中删除一个或多个存储函数。
SHOW CREATE PROCEDURE
返回使用CREATE PROCEDURE 建立的预先指定的存储过程的文本。这一声明是SQL:2003规范的一个MySQL扩展。
SHOW CREATE FUNCTION
返回使用CREATE FUNCTION建立的预先指定的存储过程的文本。这一声明是SQL:2003规范的一个MySQL扩展。
SHOW PROCEDURE STATUS
返回一个预先指定的存储过程的特性,包括名称、类型、建立者、建立日期、以及更改日期。这一声明是SQL:2003规范的一个MySQL扩展。
SHOW FUNCTION STATUS
返回一个预先指定的存储函数的特性,包括名称、类型、建立者、建立日期、以及更改日期。这一声明是SQL:2003规范的一个MySQL扩展。
CALL
调用一个使用CREATE PROCEDURE建立的预先指定的存储过程。
BEGIN ... END
包含一组执行的多声明。
DECLARE
用于指定当地变量、环境、处理器,以及指针。
SET
用于更改当地和全局服务器变量的值。
SELECT ... INTO
用于存储显示变量的纵列。
OPEN
用于打开一个指针。
FETCH
使用特定指针来获得下一列。
CLOSE
用于关闭和打开指针。
IF
一个An if-then-else-end if 声明。
CASE ... WHEN
一个 case声明的结构
LOOP
一个简单的循环结构;可以使用LEAVE 语句来退出。
LEAVE
用于退出IF,CASE,LOOP,REPEAT以及WHILE 语句。
ITERATE
用于重新开始循环。
REPEAT
在结束时测试的循环。
WHILE
在开始时测试的循环。
RETURNS
返回一个存储过程的值。
1.Linux/FreeBSD下用C语言开发PHP的so扩展模块例解:
http://www.toplee.com/blog/56.html
2.扩展实战 ------ 获得ip的来源地址:
http://my.huhoo.net/archives/2008/02/php_ip.html#4_3_configure
3.Linux/FreeBSD下用C语言开发PHP的so扩展模块例解:(估计和1重复)
http://info.codepub.com/2008/08/info-21341-4.html
4.在linux下编写php扩展模块三(函数参数和返回值)
http://mydraft.cn/posts/22 //这篇文章对与参数的传入比较详细,不错!
5.php扩展开发学习笔记 3
http://syre.blogbus.com/logs/13318038.html
http://www.toplee.com/blog/56.html
2.扩展实战 ------ 获得ip的来源地址:
http://my.huhoo.net/archives/2008/02/php_ip.html#4_3_configure
3.Linux/FreeBSD下用C语言开发PHP的so扩展模块例解:(估计和1重复)
http://info.codepub.com/2008/08/info-21341-4.html
4.在linux下编写php扩展模块三(函数参数和返回值)
http://mydraft.cn/posts/22 //这篇文章对与参数的传入比较详细,不错!
5.php扩展开发学习笔记 3
http://syre.blogbus.com/logs/13318038.html
在Linux终端:export LANG=GBK;
在SecureCRT字符设置:默认
上传:gbk编码,和utf8编码都没有乱码问题。。。
在Linux终端:export LANG=en_US.utf8;
在SecureCRT字符设置:默认
上传:gbk编码,和utf8! utf8 编码都没有乱码,但是gbk有问题。
最好是第一种为好,两种情况显示都ok。。。其余设置都有乱码问题,舍弃!
有人这样setting:
使用SecreCRT远程访问中文版Linux主机时,对于中文显示会有乱码。
设置SecureCRT设置:选项(Options)->会话选项(Session Options)->外观(Appearance)->字符(Character),选择UTF-8。
我的系统是 LANG="en_US.UTF-8",改完SecureCRT设置重新登录即可.
通常就可以了,因为Linux默认LANG就是UTF-8。如果不是,则设置一下/etc/sysconfig/i18n,将LANG设置支持UTF-8。
[root@localhost sysconfig]# more i18n
LANG="zh_CN.UTF-8"
SUPPORTED="zh_CN.UTF-8:zh_CN:zh:en_US.UTF-8:en_US:en"
SYSFONT="latarcyrheb-sun16"
重新登录就可以了!
在SecureCRT字符设置:默认
上传:gbk编码,和utf8编码都没有乱码问题。。。
在Linux终端:export LANG=en_US.utf8;
在SecureCRT字符设置:默认
上传:gbk编码,和utf8! utf8 编码都没有乱码,但是gbk有问题。
最好是第一种为好,两种情况显示都ok。。。其余设置都有乱码问题,舍弃!
有人这样setting:
使用SecreCRT远程访问中文版Linux主机时,对于中文显示会有乱码。
设置SecureCRT设置:选项(Options)->会话选项(Session Options)->外观(Appearance)->字符(Character),选择UTF-8。
我的系统是 LANG="en_US.UTF-8",改完SecureCRT设置重新登录即可.
通常就可以了,因为Linux默认LANG就是UTF-8。如果不是,则设置一下/etc/sysconfig/i18n,将LANG设置支持UTF-8。
[root@localhost sysconfig]# more i18n
LANG="zh_CN.UTF-8"
SUPPORTED="zh_CN.UTF-8:zh_CN:zh:en_US.UTF-8:en_US:en"
SYSFONT="latarcyrheb-sun16"
重新登录就可以了!
之前我在一篇文章里面讲到把故人居网站升级为UTF8字符集,看过的也知道一些有关PHP和MySQL字符集的问题,通常情况下MySQL默认使用的字符集是latin1,如果我们的系统要使用utf8或者别的字符集,就需要对MySQL进行配置,并且在PHP程序中做一点处理,大致的方法如下:
1.修改my.ini (或者my.cnf)文件,在文件的[mysqld]中加入下面一行
character_set_server = utf8
由于MySQL的字符集和连接校对有分级,分别是操作系统级、数据库服务器级、数据库客户端级,这几个级别是从上往下包含的,我上面的那一行 character_set_server 参数实际上就是设置了全局的字符集,这样不管是MySQL数据存储、数据连接、结果返回都将是utf8,当然,如果您愿意,您也可以进行分别的设置,比如做如下设置
default-character-set = utf8
default-collation = utf8_general_ci
这样的设置可以设置一个默认字符集,在您的应用中如果没有特殊指定字符集,那将默认使用utf8作为字符集,并且使用utf8_general_ci作为连接校对的默认字符集;
简单的处理方法就是如我前面的那样,加入一行即可。
2.PHP程序中连接MySQL的时候,或者在执行mysql_query的时候,执行以下一行SQL语句
SET NAMES utf8
就是说在执行mysql_query之前,或者在完成mysql_connect()之后,执行 mysql_query(”SET NAMES utf8)
有了前面的两个处理,您就可以正常的进行utf8字符集的数据库操作,不管在页面显示还是数据库中,字符都不会出现乱码。
前面说到的方法是以前用到的常用方法,最近在MySQL的官方发现了这样一个参数 init_connect ,它的意思呢就是在MySQL启动的时候,自动执行init_connect 参数里面的SQL语句,支持用分号间隔的多个语句,于是我们可以把 SET NAMES utf8语句加到my.ini文件里面,在PHP程序里面就不用单独处理了,加入参数的方法很简单,就是在my.ini文件的 [mysqld] 段加入下面一行
init_connect = ‘SET NAMES utf8′
不过这个方法有一个需要注意的地方,那就是该参数对于连接数据库的用户是超级用户组的用户将被忽略,那么在PHP程序中用来连接MySQL数据库的用户不能是SUPER组的用户,比如root用户就肯定不行,这样是为了避免该参数导致数据库致命错误,而无法使用任何一个用户连接上修改该项配置,之前我搞了两天都没有发现这样的问题,害我郁闷了很久。。。
有关MySQL的配置文件中用到的参数可以参考官方的文档 : http://dev.mysql.com/doc/refman/4.1/en/server-system-variables.html
呵呵,让人又爱又恨的MySQL!
注意:
出现你这样的原因是虽然你的WP设置了使用utf8,但是PHP在进行数据库连接的时候并没有使用utf8连接校验,这样插入到里面的数据存储方式虽然是 utf8,但是数据本身并不是utf8的,PHP读出来的时候使用的方法和插入一样,所以WP里面看到的并不会是乱码,相反在更加聪明的 phpmyadmin里面却看到了乱码,因为它使用了正确的utf8连接校验。
1.修改my.ini (或者my.cnf)文件,在文件的[mysqld]中加入下面一行
character_set_server = utf8
由于MySQL的字符集和连接校对有分级,分别是操作系统级、数据库服务器级、数据库客户端级,这几个级别是从上往下包含的,我上面的那一行 character_set_server 参数实际上就是设置了全局的字符集,这样不管是MySQL数据存储、数据连接、结果返回都将是utf8,当然,如果您愿意,您也可以进行分别的设置,比如做如下设置
default-character-set = utf8
default-collation = utf8_general_ci
这样的设置可以设置一个默认字符集,在您的应用中如果没有特殊指定字符集,那将默认使用utf8作为字符集,并且使用utf8_general_ci作为连接校对的默认字符集;
简单的处理方法就是如我前面的那样,加入一行即可。
2.PHP程序中连接MySQL的时候,或者在执行mysql_query的时候,执行以下一行SQL语句
SET NAMES utf8
就是说在执行mysql_query之前,或者在完成mysql_connect()之后,执行 mysql_query(”SET NAMES utf8)
有了前面的两个处理,您就可以正常的进行utf8字符集的数据库操作,不管在页面显示还是数据库中,字符都不会出现乱码。
前面说到的方法是以前用到的常用方法,最近在MySQL的官方发现了这样一个参数 init_connect ,它的意思呢就是在MySQL启动的时候,自动执行init_connect 参数里面的SQL语句,支持用分号间隔的多个语句,于是我们可以把 SET NAMES utf8语句加到my.ini文件里面,在PHP程序里面就不用单独处理了,加入参数的方法很简单,就是在my.ini文件的 [mysqld] 段加入下面一行
init_connect = ‘SET NAMES utf8′
不过这个方法有一个需要注意的地方,那就是该参数对于连接数据库的用户是超级用户组的用户将被忽略,那么在PHP程序中用来连接MySQL数据库的用户不能是SUPER组的用户,比如root用户就肯定不行,这样是为了避免该参数导致数据库致命错误,而无法使用任何一个用户连接上修改该项配置,之前我搞了两天都没有发现这样的问题,害我郁闷了很久。。。
有关MySQL的配置文件中用到的参数可以参考官方的文档 : http://dev.mysql.com/doc/refman/4.1/en/server-system-variables.html
呵呵,让人又爱又恨的MySQL!
注意:
出现你这样的原因是虽然你的WP设置了使用utf8,但是PHP在进行数据库连接的时候并没有使用utf8连接校验,这样插入到里面的数据存储方式虽然是 utf8,但是数据本身并不是utf8的,PHP读出来的时候使用的方法和插入一样,所以WP里面看到的并不会是乱码,相反在更加聪明的 phpmyadmin里面却看到了乱码,因为它使用了正确的utf8连接校验。
#!/bin/sh
#
# Created by xiangdong#
# To determine whether slave is running or not.
echo "Enter your Username"
read USERNAME
echo "Enter your password"
stty -echo
read PASSWD
stty echo
RESULT=`mysql -h10.69.3.198 -P4406 -u$USERNAME -p$PASSWD -A relation < sql_in.txt > sql_data_out.
txt`
#
# Created by xiangdong#
# To determine whether slave is running or not.
echo "Enter your Username"
read USERNAME
echo "Enter your password"
stty -echo
read PASSWD
stty echo
RESULT=`mysql -h10.69.3.198 -P4406 -u$USERNAME -p$PASSWD -A relation < sql_in.txt > sql_data_out.
txt`
http://blog.chinaunix.net/u/29134/showart_970894.html
#!/bin/bash
# Tetris Game
# 10.21.2003 xhchen
#颜色定义
cRed=1
cGreen=2
cYellow=3
cBlue=4
cFuchsia=5
cCyan=6
cWhite=7
colorTable=($cRed $cGreen $cYellow $cBlue $cFuchsia $cCyan $cWhite)
#位置和大小
iLeft=3
iTop=2
((iTrayLeft = iLeft + 2))
((iTrayTop = iTop + 1))
((iTrayWidth = 10))
((iTrayHeight = 15))
#颜色设置
cBorder=$cGreen
cScore=$cFuchsia
cScoreValue=$cCyan
#控制信号
#改游戏使用两个进程,一个用于接收输入,一个用于游戏流程和显示界面;
#当前者接收到上下左右等按键时,通过向后者发送signal的方式通知后者。
sigRotate=25
sigLeft=26
sigRight=27
sigDown=28
sigAllDown=29
sigExit=30
#七中不同的方块的定义
#通过旋转,每种方块的显示的样式可能有几种
box0=(0 0 0 1 1 0 1 1)
box1=(0 2 1 2 2 2 3 2 1 0 1 1 1 2 1 3)
box2=(0 0 0 1 1 1 1 2 0 1 1 0 1 1 2 0)
box3=(0 1 0 2 1 0 1 1 0 0 1 0 1 1 2 1)
box4=(0 1 0 2 1 1 2 1 1 0 1 1 1 2 2 2 0 1 1 1 2 0 2 1 0 0 1 0 1 1 1 2)
box5=(0 1 1 1 2 1 2 2 1 0 1 1 1 2 2 0 0 0 0 1 1 1 2 1 0 2 1 0 1 1 1 2)
box6=(0 1 1 1 1 2 2 1 1 0 1 1 1 2 2 1 0 1 1 0 1 1 2 1 0 1 1 0 1 1 1 2)
#所有其中方块的定义都放到box变量中
box=(${box0[@]} ${box1[@]} ${box2[@]} ${box3[@]} ${box4[@]} ${box5[@]} ${box6[@]})
#各种方块旋转后可能的样式数目
countBox=(1 2 2 2 4 4 4)
#各种方块再box数组中的偏移
offsetBox=(0 1 3 5 7 11 15)
#每提高一个速度级需要积累的分数
iScoreEachLevel=50 #be greater than 7
#运行时数据
sig=0 #接收到的signal
iScore=0 #总分
iLevel=0 #速度级
boxNew=() #新下落的方块的位置定义
cBoxNew=0 #新下落的方块的颜色
iBoxNewType=0 #新下落的方块的种类
iBoxNewRotate=0 #新下落的方块的旋转角度
boxCur=() #当前方块的位置定义
cBoxCur=0 #当前方块的颜色
iBoxCurType=0 #当前方块的种类
iBoxCurRotate=0 #当前方块的旋转角度
boxCurX=-1 #当前方块的x坐标位置
boxCurY=-1 #当前方块的y坐标位置
iMap=() #背景方块图表
#初始化所有背景方块为-1, 表示没有方块
for ((i = 0; i < iTrayHeight * iTrayWidth; i++)); do iMap[$i]=-1; done
#接收输入的进程的主函数
function RunAsKeyReceiver()
{
local pidDisplayer key aKey sig cESC sTTY
pidDisplayer=$1
aKey=(0 0 0)
cESC=`echo -ne "\33"`
cSpace=`echo -ne "\40"`
#保存终端属性。在read -s读取终端键时,终端的属性会被暂时改变。
#如果在read -s时程序被不幸杀掉,可能会导致终端混乱,
#需要在程序退出时恢复终端属性。
sTTY=`stty -g`
#捕捉退出信号
trap "MyExit;" INT TERM
trap "MyExitNoSub;" $sigExit
#隐藏光标
echo -ne "\33[?25l"
while (( 1 ))
do
#读取输入。注-s不回显,-n读到一个字符立即返回
read -s -n 1 key
aKey[0]=${aKey[1]}
aKey[1]=${aKey[2]}
aKey[2]=$key
sig=0
#判断输入了何种键
if [[ $key == $cESC && ${aKey[1]} == $cESC ]]
then
#ESC键
MyExit
elif [[ ${aKey[0]} == $cESC && ${aKey[1]} == "[" ]]
then
if [[ $key == "A" ]]; then sig=$sigRotate #<向上键>
elif [[ $key == "B" ]]; then sig=$sigDown #<向下键>
elif [[ $key == "D" ]]; then sig=$sigLeft #<向左键>
elif [[ $key == "C" ]]; then sig=$sigRight #<向右键>
fi
elif [[ $key == "W" || $key == "w" ]]; then sig=$sigRotate #W, w
elif [[ $key == "S" || $key == "s" ]]; then sig=$sigDown #S, s
elif [[ $key == "A" || $key == "a" ]]; then sig=$sigLeft #A, a
elif [[ $key == "D" || $key == "d" ]]; then sig=$sigRight #D, d
elif [[ "[$key]" == "[]" ]]; then sig=$sigAllDown #空格键
elif [[ $key == "Q" || $key == "q" ]] #Q, q
then
MyExit
fi
if [[ $sig != 0 ]]
then
#向另一进程发送消息
kill -$sig $pidDisplayer
fi
done
}
#退出前的恢复
function MyExitNoSub()
{
local y
#恢复终端属性
stty $sTTY
((y = iTop + iTrayHeight + 4))
#显示光标
echo -e "\33[?25h\33[${y};0H"
exit
}
function MyExit()
{
#通知显示进程需要退出
kill -$sigExit $pidDisplayer
MyExitNoSub
}
#处理显示和游戏流程的主函数
function RunAsDisplayer()
{
local sigThis
InitDraw
#挂载各种信号的处理函数
trap "sig=$sigRotate;" $sigRotate
trap "sig=$sigLeft;" $sigLeft
trap "sig=$sigRight;" $sigRight
trap "sig=$sigDown;" $sigDown
trap "sig=$sigAllDown;" $sigAllDown
trap "ShowExit;" $sigExit
while (( 1 ))
do
#根据当前的速度级iLevel不同,设定相应的循环的次数
for ((i = 0; i < 21 - iLevel; i++))
do
sleep 0.02
sigThis=$sig
sig=0
#根据sig变量判断是否接受到相应的信号
if ((sigThis == sigRotate)); then BoxRotate; #旋转
elif ((sigThis == sigLeft)); then BoxLeft; #左移一列
elif ((sigThis == sigRight)); then BoxRight; #右移一列
elif ((sigThis == sigDown)); then BoxDown; #下落一行
elif ((sigThis == sigAllDown)); then BoxAllDown; #下落到底
fi
done
#kill -$sigDown $$
BoxDown #下落一行
done
}
#BoxMove(y, x), 测试是否可以把移动中的方块移到(x, y)的位置, 返回0则可以, 1不可以
function BoxMove()
{
local j i x y xTest yTest
yTest=$1
xTest=$2
for ((j = 0; j < 8; j += 2))
do
((i = j + 1))
((y = ${boxCur[$j]} + yTest))
((x = ${boxCur[$i]} + xTest))
if (( y < 0 || y >= iTrayHeight || x < 0 || x >= iTrayWidth))
then
#撞到墙壁了
return 1
fi
if ((${iMap[y * iTrayWidth + x]} != -1 ))
then
#撞到其他已经存在的方块了
return 1
fi
done
return 0;
}
#将当前移动中的方块放到背景方块中去,
#并计算新的分数和速度级。(即一次方块落到底部)
function Box2Map()
{
local j i x y xp yp line
#将当前移动中的方块放到背景方块中去
for ((j = 0; j < 8; j += 2))
do
((i = j + 1))
((y = ${boxCur[$j]} + boxCurY))
((x = ${boxCur[$i]} + boxCurX))
((i = y * iTrayWidth + x))
iMap[$i]=$cBoxCur
done
#消去可被消去的行
line=0
for ((j = 0; j < iTrayWidth * iTrayHeight; j += iTrayWidth))
do
for ((i = j + iTrayWidth - 1; i >= j; i--))
do
if ((${iMap[$i]} == -1)); then break; fi
done
if ((i >= j)); then continue; fi
((line++))
for ((i = j - 1; i >= 0; i--))
do
((x = i + iTrayWidth))
iMap[$x]=${iMap[$i]}
done
for ((i = 0; i < iTrayWidth; i++))
do
iMap[$i]=-1
done
done
if ((line == 0)); then return; fi
#根据消去的行数line计算分数和速度级
((x = iLeft + iTrayWidth * 2 + 7))
((y = iTop + 11))
((iScore += line * 2 - 1))
#显示新的分数
echo -ne "\33[1m\33[3${cScoreValue}m\33[${y};${x}H${iScore} "
if ((iScore % iScoreEachLevel < line * 2 - 1))
then
if ((iLevel < 20))
then
((iLevel++))
((y = iTop + 14))
#显示新的速度级
echo -ne "\33[3${cScoreValue}m\33[${y};${x}H${iLevel} "
fi
fi
echo -ne "\33[0m"
#重新显示背景方块
for ((y = 0; y < iTrayHeight; y++))
do
((yp = y + iTrayTop + 1))
((xp = iTrayLeft + 1))
((i = y * iTrayWidth))
echo -ne "\33[${yp};${xp}H"
for ((x = 0; x < iTrayWidth; x++))
do
((j = i + x))
if ((${iMap[$j]} == -1))
then
echo -ne " "
else
echo -ne "\33[1m\33[7m\33[3${iMap[$j]}m\33[4${iMap[$j]}m[]\33[0m"
fi
done
done
}
#下落一行
function BoxDown()
{
local y s
((y = boxCurY + 1)) #新的y坐标
if BoxMove $y $boxCurX #测试是否可以下落一行
then
s="`DrawCurBox 0`" #将旧的方块抹去
((boxCurY = y))
s="$s`DrawCurBox 1`" #显示新的下落后方块
echo -ne $s
else
#走到这儿, 如果不能下落了
Box2Map #将当前移动中的方块贴到背景方块中
RandomBox #产生新的方块
fi
}
#左移一列
function BoxLeft()
{
local x s
((x = boxCurX - 1))
if BoxMove $boxCurY $x
then
s=`DrawCurBox 0`
((boxCurX = x))
s=$s`DrawCurBox 1`
echo -ne $s
fi
}
#右移一列
function BoxRight()
{
local x s
((x = boxCurX + 1))
if BoxMove $boxCurY $x
then
s=`DrawCurBox 0`
((boxCurX = x))
s=$s`DrawCurBox 1`
echo -ne $s
fi
}
#下落到底
function BoxAllDown()
{
local k j i x y iDown s
iDown=$iTrayHeight
#计算一共需要下落多少行
for ((j = 0; j < 8; j += 2))
do
((i = j + 1))
((y = ${boxCur[$j]} + boxCurY))
((x = ${boxCur[$i]} + boxCurX))
for ((k = y + 1; k < iTrayHeight; k++))
do
((i = k * iTrayWidth + x))
if (( ${iMap[$i]} != -1)); then break; fi
done
((k -= y + 1))
if (( $iDown > $k )); then iDown=$k; fi
done
s=`DrawCurBox 0` #将旧的方块抹去
((boxCurY += iDown))
s=$s`DrawCurBox 1` #显示新的下落后的方块
echo -ne $s
Box2Map #将当前移动中的方块贴到背景方块中
RandomBox #产生新的方块
}
#旋转方块
function BoxRotate()
{
local iCount iTestRotate boxTest j i s
iCount=${countBox[$iBoxCurType]} #当前的方块经旋转可以产生的样式的数目
#计算旋转后的新的样式
((iTestRotate = iBoxCurRotate + 1))
if ((iTestRotate >= iCount))
then
((iTestRotate = 0))
fi
#更新到新的样式, 保存老的样式(但不显示)
for ((j = 0, i = (${offsetBox[$iBoxCurType]} + $iTestRotate) * 8; j < 8; j++, i++))
do
boxTest[$j]=${boxCur[$j]}
boxCur[$j]=${box[$i]}
done
if BoxMove $boxCurY $boxCurX #测试旋转后是否有空间放的下
then
#抹去旧的方块
for ((j = 0; j < 8; j++))
do
boxCur[$j]=${boxTest[$j]}
done
s=`DrawCurBox 0`
#画上新的方块
for ((j = 0, i = (${offsetBox[$iBoxCurType]} + $iTestRotate) * 8; j < 8; j++, i++))
do
boxCur[$j]=${box[$i]}
done
s=$s`DrawCurBox 1`
echo -ne $s
iBoxCurRotate=$iTestRotate
else
#不能旋转,还是继续使用老的样式
for ((j = 0; j < 8; j++))
do
boxCur[$j]=${boxTest[$j]}
done
fi
}
#DrawCurBox(bDraw), 绘制当前移动中的方块, bDraw为1, 画上, bDraw为0, 抹去方块。
function DrawCurBox()
{
local i j t bDraw sBox s
bDraw=$1
s=""
if (( bDraw == 0 ))
then
sBox="\40\40"
else
sBox="[]"
s=$s"\33[1m\33[7m\33[3${cBoxCur}m\33[4${cBoxCur}m"
fi
for ((j = 0; j < 8; j += 2))
do
((i = iTrayTop + 1 + ${boxCur[$j]} + boxCurY))
((t = iTrayLeft + 1 + 2 * (boxCurX + ${boxCur[$j + 1]})))
#\33[y;xH, 光标到(x, y)处
s=$s"\33[${i};${t}H${sBox}"
done
s=$s"\33[0m"
echo -n $s
}
#更新新的方块
function RandomBox()
{
local i j t
#更新当前移动的方块
iBoxCurType=${iBoxNewType}
iBoxCurRotate=${iBoxNewRotate}
cBoxCur=${cBoxNew}
for ((j = 0; j < ${#boxNew[@]}; j++))
do
boxCur[$j]=${boxNew[$j]}
done
#显示当前移动的方块
if (( ${#boxCur[@]} == 8 ))
then
#计算当前方块该从顶端哪一行"冒"出来
for ((j = 0, t = 4; j < 8; j += 2))
do
if ((${boxCur[$j]} < t)); then t=${boxCur[$j]}; fi
done
((boxCurY = -t))
for ((j = 1, i = -4, t = 20; j < 8; j += 2))
do
if ((${boxCur[$j]} > i)); then i=${boxCur[$j]}; fi
if ((${boxCur[$j]} < t)); then t=${boxCur[$j]}; fi
done
((boxCurX = (iTrayWidth - 1 - i - t) / 2))
#显示当前移动的方块
echo -ne `DrawCurBox 1`
#如果方块一出来就没处放,Game over!
if ! BoxMove $boxCurY $boxCurX
then
kill -$sigExit ${PPID}
ShowExit
fi
fi
#清除右边预显示的方块
for ((j = 0; j < 4; j++))
do
((i = iTop + 1 + j))
((t = iLeft + 2 * iTrayWidth + 7))
echo -ne "\33[${i};${t}H "
done
#随机产生新的方块
((iBoxNewType = RANDOM % ${#offsetBox[@]}))
((iBoxNewRotate = RANDOM % ${countBox[$iBoxNewType]}))
for ((j = 0, i = (${offsetBox[$iBoxNewType]} + $iBoxNewRotate) * 8; j < 8; j++, i++))
do
boxNew[$j]=${box[$i]};
done
((cBoxNew = ${colorTable[RANDOM % ${#colorTable[@]}]}))
#显示右边预显示的方块
echo -ne "\33[1m\33[7m\33[3${cBoxNew}m\33[4${cBoxNew}m"
for ((j = 0; j < 8; j += 2))
do
((i = iTop + 1 + ${boxNew[$j]}))
((t = iLeft + 2 * iTrayWidth + 7 + 2 * ${boxNew[$j + 1]}))
echo -ne "\33[${i};${t}H[]"
done
echo -ne "\33[0m"
}
#初始绘制
function InitDraw()
{
clear
RandomBox #随机产生方块,这时右边预显示窗口中有方快了
RandomBox #再随机产生方块,右边预显示窗口中的方块被更新,原先的方块将开始下落
local i t1 t2 t3
#显示边框
echo -ne "\33[1m"
echo -ne "\33[3${cBorder}m\33[4${cBorder}m"
((t2 = iLeft + 1))
((t3 = iLeft + iTrayWidth * 2 + 3))
for ((i = 0; i < iTrayHeight; i++))
do
((t1 = i + iTop + 2))
echo -ne "\33[${t1};${t2}H||"
echo -ne "\33[${t1};${t3}H||"
done
((t2 = iTop + iTrayHeight + 2))
for ((i = 0; i < iTrayWidth + 2; i++))
do
((t1 = i * 2 + iLeft + 1))
echo -ne "\33[${iTrayTop};${t1}H=="
echo -ne "\33[${t2};${t1}H=="
done
echo -ne "\33[0m"
#显示"Score"和"Level"字样
echo -ne "\33[1m"
((t1 = iLeft + iTrayWidth * 2 + 7))
((t2 = iTop + 10))
echo -ne "\33[3${cScore}m\33[${t2};${t1}HScore"
((t2 = iTop + 11))
echo -ne "\33[3${cScoreValue}m\33[${t2};${t1}H${iScore}"
((t2 = iTop + 13))
echo -ne "\33[3${cScore}m\33[${t2};${t1}HLevel"
((t2 = iTop + 14))
echo -ne "\33[3${cScoreValue}m\33[${t2};${t1}H${iLevel}"
echo -ne "\33[0m"
}
#退出时显示GameOVer!
function ShowExit()
{
local y
((y = iTrayHeight + iTrayTop + 3))
echo -e "\33[${y};0HGameOver!\33[0m"
exit
}
#游戏主程序在这儿开始.
if [[ $1 != "--show" ]]
then
bash $0 --show& #以参数--show将本程序再运行一遍
RunAsKeyReceiver $! #以上一行产生的进程的进程号作为参数
exit
else
#当发现具有参数--show时,运行显示函数
RunAsDisplayer
exit
fi
# Tetris Game
# 10.21.2003 xhchen
#颜色定义
cRed=1
cGreen=2
cYellow=3
cBlue=4
cFuchsia=5
cCyan=6
cWhite=7
colorTable=($cRed $cGreen $cYellow $cBlue $cFuchsia $cCyan $cWhite)
#位置和大小
iLeft=3
iTop=2
((iTrayLeft = iLeft + 2))
((iTrayTop = iTop + 1))
((iTrayWidth = 10))
((iTrayHeight = 15))
#颜色设置
cBorder=$cGreen
cScore=$cFuchsia
cScoreValue=$cCyan
#控制信号
#改游戏使用两个进程,一个用于接收输入,一个用于游戏流程和显示界面;
#当前者接收到上下左右等按键时,通过向后者发送signal的方式通知后者。
sigRotate=25
sigLeft=26
sigRight=27
sigDown=28
sigAllDown=29
sigExit=30
#七中不同的方块的定义
#通过旋转,每种方块的显示的样式可能有几种
box0=(0 0 0 1 1 0 1 1)
box1=(0 2 1 2 2 2 3 2 1 0 1 1 1 2 1 3)
box2=(0 0 0 1 1 1 1 2 0 1 1 0 1 1 2 0)
box3=(0 1 0 2 1 0 1 1 0 0 1 0 1 1 2 1)
box4=(0 1 0 2 1 1 2 1 1 0 1 1 1 2 2 2 0 1 1 1 2 0 2 1 0 0 1 0 1 1 1 2)
box5=(0 1 1 1 2 1 2 2 1 0 1 1 1 2 2 0 0 0 0 1 1 1 2 1 0 2 1 0 1 1 1 2)
box6=(0 1 1 1 1 2 2 1 1 0 1 1 1 2 2 1 0 1 1 0 1 1 2 1 0 1 1 0 1 1 1 2)
#所有其中方块的定义都放到box变量中
box=(${box0[@]} ${box1[@]} ${box2[@]} ${box3[@]} ${box4[@]} ${box5[@]} ${box6[@]})
#各种方块旋转后可能的样式数目
countBox=(1 2 2 2 4 4 4)
#各种方块再box数组中的偏移
offsetBox=(0 1 3 5 7 11 15)
#每提高一个速度级需要积累的分数
iScoreEachLevel=50 #be greater than 7
#运行时数据
sig=0 #接收到的signal
iScore=0 #总分
iLevel=0 #速度级
boxNew=() #新下落的方块的位置定义
cBoxNew=0 #新下落的方块的颜色
iBoxNewType=0 #新下落的方块的种类
iBoxNewRotate=0 #新下落的方块的旋转角度
boxCur=() #当前方块的位置定义
cBoxCur=0 #当前方块的颜色
iBoxCurType=0 #当前方块的种类
iBoxCurRotate=0 #当前方块的旋转角度
boxCurX=-1 #当前方块的x坐标位置
boxCurY=-1 #当前方块的y坐标位置
iMap=() #背景方块图表
#初始化所有背景方块为-1, 表示没有方块
for ((i = 0; i < iTrayHeight * iTrayWidth; i++)); do iMap[$i]=-1; done
#接收输入的进程的主函数
function RunAsKeyReceiver()
{
local pidDisplayer key aKey sig cESC sTTY
pidDisplayer=$1
aKey=(0 0 0)
cESC=`echo -ne "\33"`
cSpace=`echo -ne "\40"`
#保存终端属性。在read -s读取终端键时,终端的属性会被暂时改变。
#如果在read -s时程序被不幸杀掉,可能会导致终端混乱,
#需要在程序退出时恢复终端属性。
sTTY=`stty -g`
#捕捉退出信号
trap "MyExit;" INT TERM
trap "MyExitNoSub;" $sigExit
#隐藏光标
echo -ne "\33[?25l"
while (( 1 ))
do
#读取输入。注-s不回显,-n读到一个字符立即返回
read -s -n 1 key
aKey[0]=${aKey[1]}
aKey[1]=${aKey[2]}
aKey[2]=$key
sig=0
#判断输入了何种键
if [[ $key == $cESC && ${aKey[1]} == $cESC ]]
then
#ESC键
MyExit
elif [[ ${aKey[0]} == $cESC && ${aKey[1]} == "[" ]]
then
if [[ $key == "A" ]]; then sig=$sigRotate #<向上键>
elif [[ $key == "B" ]]; then sig=$sigDown #<向下键>
elif [[ $key == "D" ]]; then sig=$sigLeft #<向左键>
elif [[ $key == "C" ]]; then sig=$sigRight #<向右键>
fi
elif [[ $key == "W" || $key == "w" ]]; then sig=$sigRotate #W, w
elif [[ $key == "S" || $key == "s" ]]; then sig=$sigDown #S, s
elif [[ $key == "A" || $key == "a" ]]; then sig=$sigLeft #A, a
elif [[ $key == "D" || $key == "d" ]]; then sig=$sigRight #D, d
elif [[ "[$key]" == "[]" ]]; then sig=$sigAllDown #空格键
elif [[ $key == "Q" || $key == "q" ]] #Q, q
then
MyExit
fi
if [[ $sig != 0 ]]
then
#向另一进程发送消息
kill -$sig $pidDisplayer
fi
done
}
#退出前的恢复
function MyExitNoSub()
{
local y
#恢复终端属性
stty $sTTY
((y = iTop + iTrayHeight + 4))
#显示光标
echo -e "\33[?25h\33[${y};0H"
exit
}
function MyExit()
{
#通知显示进程需要退出
kill -$sigExit $pidDisplayer
MyExitNoSub
}
#处理显示和游戏流程的主函数
function RunAsDisplayer()
{
local sigThis
InitDraw
#挂载各种信号的处理函数
trap "sig=$sigRotate;" $sigRotate
trap "sig=$sigLeft;" $sigLeft
trap "sig=$sigRight;" $sigRight
trap "sig=$sigDown;" $sigDown
trap "sig=$sigAllDown;" $sigAllDown
trap "ShowExit;" $sigExit
while (( 1 ))
do
#根据当前的速度级iLevel不同,设定相应的循环的次数
for ((i = 0; i < 21 - iLevel; i++))
do
sleep 0.02
sigThis=$sig
sig=0
#根据sig变量判断是否接受到相应的信号
if ((sigThis == sigRotate)); then BoxRotate; #旋转
elif ((sigThis == sigLeft)); then BoxLeft; #左移一列
elif ((sigThis == sigRight)); then BoxRight; #右移一列
elif ((sigThis == sigDown)); then BoxDown; #下落一行
elif ((sigThis == sigAllDown)); then BoxAllDown; #下落到底
fi
done
#kill -$sigDown $$
BoxDown #下落一行
done
}
#BoxMove(y, x), 测试是否可以把移动中的方块移到(x, y)的位置, 返回0则可以, 1不可以
function BoxMove()
{
local j i x y xTest yTest
yTest=$1
xTest=$2
for ((j = 0; j < 8; j += 2))
do
((i = j + 1))
((y = ${boxCur[$j]} + yTest))
((x = ${boxCur[$i]} + xTest))
if (( y < 0 || y >= iTrayHeight || x < 0 || x >= iTrayWidth))
then
#撞到墙壁了
return 1
fi
if ((${iMap[y * iTrayWidth + x]} != -1 ))
then
#撞到其他已经存在的方块了
return 1
fi
done
return 0;
}
#将当前移动中的方块放到背景方块中去,
#并计算新的分数和速度级。(即一次方块落到底部)
function Box2Map()
{
local j i x y xp yp line
#将当前移动中的方块放到背景方块中去
for ((j = 0; j < 8; j += 2))
do
((i = j + 1))
((y = ${boxCur[$j]} + boxCurY))
((x = ${boxCur[$i]} + boxCurX))
((i = y * iTrayWidth + x))
iMap[$i]=$cBoxCur
done
#消去可被消去的行
line=0
for ((j = 0; j < iTrayWidth * iTrayHeight; j += iTrayWidth))
do
for ((i = j + iTrayWidth - 1; i >= j; i--))
do
if ((${iMap[$i]} == -1)); then break; fi
done
if ((i >= j)); then continue; fi
((line++))
for ((i = j - 1; i >= 0; i--))
do
((x = i + iTrayWidth))
iMap[$x]=${iMap[$i]}
done
for ((i = 0; i < iTrayWidth; i++))
do
iMap[$i]=-1
done
done
if ((line == 0)); then return; fi
#根据消去的行数line计算分数和速度级
((x = iLeft + iTrayWidth * 2 + 7))
((y = iTop + 11))
((iScore += line * 2 - 1))
#显示新的分数
echo -ne "\33[1m\33[3${cScoreValue}m\33[${y};${x}H${iScore} "
if ((iScore % iScoreEachLevel < line * 2 - 1))
then
if ((iLevel < 20))
then
((iLevel++))
((y = iTop + 14))
#显示新的速度级
echo -ne "\33[3${cScoreValue}m\33[${y};${x}H${iLevel} "
fi
fi
echo -ne "\33[0m"
#重新显示背景方块
for ((y = 0; y < iTrayHeight; y++))
do
((yp = y + iTrayTop + 1))
((xp = iTrayLeft + 1))
((i = y * iTrayWidth))
echo -ne "\33[${yp};${xp}H"
for ((x = 0; x < iTrayWidth; x++))
do
((j = i + x))
if ((${iMap[$j]} == -1))
then
echo -ne " "
else
echo -ne "\33[1m\33[7m\33[3${iMap[$j]}m\33[4${iMap[$j]}m[]\33[0m"
fi
done
done
}
#下落一行
function BoxDown()
{
local y s
((y = boxCurY + 1)) #新的y坐标
if BoxMove $y $boxCurX #测试是否可以下落一行
then
s="`DrawCurBox 0`" #将旧的方块抹去
((boxCurY = y))
s="$s`DrawCurBox 1`" #显示新的下落后方块
echo -ne $s
else
#走到这儿, 如果不能下落了
Box2Map #将当前移动中的方块贴到背景方块中
RandomBox #产生新的方块
fi
}
#左移一列
function BoxLeft()
{
local x s
((x = boxCurX - 1))
if BoxMove $boxCurY $x
then
s=`DrawCurBox 0`
((boxCurX = x))
s=$s`DrawCurBox 1`
echo -ne $s
fi
}
#右移一列
function BoxRight()
{
local x s
((x = boxCurX + 1))
if BoxMove $boxCurY $x
then
s=`DrawCurBox 0`
((boxCurX = x))
s=$s`DrawCurBox 1`
echo -ne $s
fi
}
#下落到底
function BoxAllDown()
{
local k j i x y iDown s
iDown=$iTrayHeight
#计算一共需要下落多少行
for ((j = 0; j < 8; j += 2))
do
((i = j + 1))
((y = ${boxCur[$j]} + boxCurY))
((x = ${boxCur[$i]} + boxCurX))
for ((k = y + 1; k < iTrayHeight; k++))
do
((i = k * iTrayWidth + x))
if (( ${iMap[$i]} != -1)); then break; fi
done
((k -= y + 1))
if (( $iDown > $k )); then iDown=$k; fi
done
s=`DrawCurBox 0` #将旧的方块抹去
((boxCurY += iDown))
s=$s`DrawCurBox 1` #显示新的下落后的方块
echo -ne $s
Box2Map #将当前移动中的方块贴到背景方块中
RandomBox #产生新的方块
}
#旋转方块
function BoxRotate()
{
local iCount iTestRotate boxTest j i s
iCount=${countBox[$iBoxCurType]} #当前的方块经旋转可以产生的样式的数目
#计算旋转后的新的样式
((iTestRotate = iBoxCurRotate + 1))
if ((iTestRotate >= iCount))
then
((iTestRotate = 0))
fi
#更新到新的样式, 保存老的样式(但不显示)
for ((j = 0, i = (${offsetBox[$iBoxCurType]} + $iTestRotate) * 8; j < 8; j++, i++))
do
boxTest[$j]=${boxCur[$j]}
boxCur[$j]=${box[$i]}
done
if BoxMove $boxCurY $boxCurX #测试旋转后是否有空间放的下
then
#抹去旧的方块
for ((j = 0; j < 8; j++))
do
boxCur[$j]=${boxTest[$j]}
done
s=`DrawCurBox 0`
#画上新的方块
for ((j = 0, i = (${offsetBox[$iBoxCurType]} + $iTestRotate) * 8; j < 8; j++, i++))
do
boxCur[$j]=${box[$i]}
done
s=$s`DrawCurBox 1`
echo -ne $s
iBoxCurRotate=$iTestRotate
else
#不能旋转,还是继续使用老的样式
for ((j = 0; j < 8; j++))
do
boxCur[$j]=${boxTest[$j]}
done
fi
}
#DrawCurBox(bDraw), 绘制当前移动中的方块, bDraw为1, 画上, bDraw为0, 抹去方块。
function DrawCurBox()
{
local i j t bDraw sBox s
bDraw=$1
s=""
if (( bDraw == 0 ))
then
sBox="\40\40"
else
sBox="[]"
s=$s"\33[1m\33[7m\33[3${cBoxCur}m\33[4${cBoxCur}m"
fi
for ((j = 0; j < 8; j += 2))
do
((i = iTrayTop + 1 + ${boxCur[$j]} + boxCurY))
((t = iTrayLeft + 1 + 2 * (boxCurX + ${boxCur[$j + 1]})))
#\33[y;xH, 光标到(x, y)处
s=$s"\33[${i};${t}H${sBox}"
done
s=$s"\33[0m"
echo -n $s
}
#更新新的方块
function RandomBox()
{
local i j t
#更新当前移动的方块
iBoxCurType=${iBoxNewType}
iBoxCurRotate=${iBoxNewRotate}
cBoxCur=${cBoxNew}
for ((j = 0; j < ${#boxNew[@]}; j++))
do
boxCur[$j]=${boxNew[$j]}
done
#显示当前移动的方块
if (( ${#boxCur[@]} == 8 ))
then
#计算当前方块该从顶端哪一行"冒"出来
for ((j = 0, t = 4; j < 8; j += 2))
do
if ((${boxCur[$j]} < t)); then t=${boxCur[$j]}; fi
done
((boxCurY = -t))
for ((j = 1, i = -4, t = 20; j < 8; j += 2))
do
if ((${boxCur[$j]} > i)); then i=${boxCur[$j]}; fi
if ((${boxCur[$j]} < t)); then t=${boxCur[$j]}; fi
done
((boxCurX = (iTrayWidth - 1 - i - t) / 2))
#显示当前移动的方块
echo -ne `DrawCurBox 1`
#如果方块一出来就没处放,Game over!
if ! BoxMove $boxCurY $boxCurX
then
kill -$sigExit ${PPID}
ShowExit
fi
fi
#清除右边预显示的方块
for ((j = 0; j < 4; j++))
do
((i = iTop + 1 + j))
((t = iLeft + 2 * iTrayWidth + 7))
echo -ne "\33[${i};${t}H "
done
#随机产生新的方块
((iBoxNewType = RANDOM % ${#offsetBox[@]}))
((iBoxNewRotate = RANDOM % ${countBox[$iBoxNewType]}))
for ((j = 0, i = (${offsetBox[$iBoxNewType]} + $iBoxNewRotate) * 8; j < 8; j++, i++))
do
boxNew[$j]=${box[$i]};
done
((cBoxNew = ${colorTable[RANDOM % ${#colorTable[@]}]}))
#显示右边预显示的方块
echo -ne "\33[1m\33[7m\33[3${cBoxNew}m\33[4${cBoxNew}m"
for ((j = 0; j < 8; j += 2))
do
((i = iTop + 1 + ${boxNew[$j]}))
((t = iLeft + 2 * iTrayWidth + 7 + 2 * ${boxNew[$j + 1]}))
echo -ne "\33[${i};${t}H[]"
done
echo -ne "\33[0m"
}
#初始绘制
function InitDraw()
{
clear
RandomBox #随机产生方块,这时右边预显示窗口中有方快了
RandomBox #再随机产生方块,右边预显示窗口中的方块被更新,原先的方块将开始下落
local i t1 t2 t3
#显示边框
echo -ne "\33[1m"
echo -ne "\33[3${cBorder}m\33[4${cBorder}m"
((t2 = iLeft + 1))
((t3 = iLeft + iTrayWidth * 2 + 3))
for ((i = 0; i < iTrayHeight; i++))
do
((t1 = i + iTop + 2))
echo -ne "\33[${t1};${t2}H||"
echo -ne "\33[${t1};${t3}H||"
done
((t2 = iTop + iTrayHeight + 2))
for ((i = 0; i < iTrayWidth + 2; i++))
do
((t1 = i * 2 + iLeft + 1))
echo -ne "\33[${iTrayTop};${t1}H=="
echo -ne "\33[${t2};${t1}H=="
done
echo -ne "\33[0m"
#显示"Score"和"Level"字样
echo -ne "\33[1m"
((t1 = iLeft + iTrayWidth * 2 + 7))
((t2 = iTop + 10))
echo -ne "\33[3${cScore}m\33[${t2};${t1}HScore"
((t2 = iTop + 11))
echo -ne "\33[3${cScoreValue}m\33[${t2};${t1}H${iScore}"
((t2 = iTop + 13))
echo -ne "\33[3${cScore}m\33[${t2};${t1}HLevel"
((t2 = iTop + 14))
echo -ne "\33[3${cScoreValue}m\33[${t2};${t1}H${iLevel}"
echo -ne "\33[0m"
}
#退出时显示GameOVer!
function ShowExit()
{
local y
((y = iTrayHeight + iTrayTop + 3))
echo -e "\33[${y};0HGameOver!\33[0m"
exit
}
#游戏主程序在这儿开始.
if [[ $1 != "--show" ]]
then
bash $0 --show& #以参数--show将本程序再运行一遍
RunAsKeyReceiver $! #以上一行产生的进程的进程号作为参数
exit
else
#当发现具有参数--show时,运行显示函数
RunAsDisplayer
exit
fi
select FQQ,FScoreCount from Tbl_User into outfile "/tmp/terminatedtest.txt" fields terminated by ",";
http://blog.chinaunix.net/u/29134/showart_1074828.html
select * into destTbl from srcTbl
insert into destTbl(fld1, fld2) select fld1, 5 from srcTbl
以上两句都是将 srcTbl 的数据插入到 destTbl,但两句又有区别的:
•第一句(select into from)要求目标表(destTbl)不存在,因为在插入时会自动创建。
•第二句(insert into select from)要求目标表(destTbl)存在,由于目标表已经存在,所以我们除了插入源表(srcTbl)的字段外,还可以插入常量,如例中的:5。
mysql> select * into user_score_20090429 from user_score_20090430;
要求目标表( user_score_20090429 )不存在insert into user_score_20090504 select * from user_score_20090505 where uid=1608843755;
//这个靠谱些验证过ERROR 1062 (23000): Duplicate entry '67' for key 1
唯一键id冲突,那就:
truncate table `user_score_20090504`;
修改表名称(发现权限不够):
RENAME TABLE user_score_20090505 TO user_score_20090504;
用文本方式将数据装入一个数据库表
如果一条一条地输入,很麻烦。我们可以用文本文件的方式将所有记录加入你的数据库表中。创建一个文本文件“mysql.txt”,每行包含一个记录,用定位符(tab)把值分开,并且以在CREATE TABLE语句中列出的列次序给出,例如:
abccs f 1977-07-07 china mary f 1978-12-12 usa tom m 1970-09-02 usa
使用下面命令将文本文件“mytable.txt”装载到mytable表中:mysql> LOAD DATA LOCAL INFILE "mytable.txt" INTO TABLE pet;
复制表
create table table2 select * from table1 limit 21;//也可以复制整个表。。。
如果需要的只是某些列也可以将*改为那些列的名字。
复制表的某些列也可以使用这样的方法:
create table b as select a.id, a.name, a.address from user a;
阅读全文
如果一条一条地输入,很麻烦。我们可以用文本文件的方式将所有记录加入你的数据库表中。创建一个文本文件“mysql.txt”,每行包含一个记录,用定位符(tab)把值分开,并且以在CREATE TABLE语句中列出的列次序给出,例如:
abccs f 1977-07-07 china mary f 1978-12-12 usa tom m 1970-09-02 usa
使用下面命令将文本文件“mytable.txt”装载到mytable表中:mysql> LOAD DATA LOCAL INFILE "mytable.txt" INTO TABLE pet;
复制表
create table table2 select * from table1 limit 21;//也可以复制整个表。。。
如果需要的只是某些列也可以将*改为那些列的名字。
复制表的某些列也可以使用这样的方法:
create table b as select a.id, a.name, a.address from user a;
阅读全文
强制索引示例:
强制不使用缓存查询示例:
强制不使用索引示例:
强制使用临时表:
其他强制操作,优先操作如下:阅读全文
select information.group, information.connection, information.productid, information.invitetype,relation.id, relation.owneruid, relation.otheruid, relation.type, relation.status, relation.infoid from relation FORCE INDEX (oo,infoid) left join information FORCE INDEX (g_i_c) on relation.infoid=information.infoid where information.group = 0 and relation.owneruid = 1257432324 and relation.type = 1;
强制不使用缓存查询示例:
select SQL_NO_CACHE information.group, information.connection, information.productid, information.invitetype,relation.id, relation.owneruid, relation.otheruid, relation.type, relation.status, relation.infoid from relation FORCE INDEX (oo,infoid) left join information FORCE INDEX (g_i_c) on relation.infoid=information.infoid where information.group = 0 and relation.owneruid = 1257432324 and relation.type = 1;
强制不使用索引示例:
select SQL_NO_CACHE relation.id, relation.owneruid, relation.otheruid, relation.type, relation.status, relation.infoid, information.group, information.connection, information.productid, information.invitetype from relation IGNORE INDEX (PRIMARY,otc,oo,ots,uniq_key,infoid) left join information IGNORE INDEX (PRIMARY,g_i_c) on relation.infoid=information.infoid where information.group = 0 and relation.owneruid = 1257432324 and relation.type = 1;
强制使用临时表:
select SQL_NO_CACHE SQL_BUFFER_RESULT relation.id, relation.owneruid, relation.otheruid, relation.type, relation.status, relation.infoid, information.group, information.connection, information.productid, information.invitetype from relation left join information on relation.infoid=information.infoid where information.group = 0 and relation.owneruid = 1257432324 and relation.type = 1;
其他强制操作,优先操作如下:阅读全文
由于出现很多连接错误,主机'host_name'被屏蔽。 可使用'mysqladmin flush-hosts'解除屏蔽。
可使用'mysqladmin flush-hosts'解除屏蔽。
允许的中断连接请求的数目由max_connect_errors系统变量的值决定。当超出max_connect_errors规定的连接请求时,mysqld将认为某处出错(例如,某人正试图插入),并屏蔽主机的进一步连接请求,直至执行了mysqladmin flush-hosts命令,或发出了FLUSH HOSTS语句为止。
在默认情况下,mysqld会在10次连接错误后屏蔽主机。你可以通过下述方式启动服务器来调整该值:
shell> mysqld_safe --max_connect_errors=10000 &
如果在给定主机上遇到该错误,首先应核实该主机的TCP/IP连接是否正确。如果存在网络问题,增加max_connect_errors变量的值不会有任何好处。
GRANT ALL PRIVILEGES ON *.* TO 'space'@'%' IDENTIFIED BY '123qwe';
GRANT ALL PRIVILEGES ON *.* TO 'space'@'localhost' IDENTIFIED BY '123qwe';
只对某个库分配权限:
mysql -uspace -p123qwe -P3306
最后,刷新:
FLUSH PRIVILEGES
可使用'mysqladmin flush-hosts'解除屏蔽。
允许的中断连接请求的数目由max_connect_errors系统变量的值决定。当超出max_connect_errors规定的连接请求时,mysqld将认为某处出错(例如,某人正试图插入),并屏蔽主机的进一步连接请求,直至执行了mysqladmin flush-hosts命令,或发出了FLUSH HOSTS语句为止。
在默认情况下,mysqld会在10次连接错误后屏蔽主机。你可以通过下述方式启动服务器来调整该值:
shell> mysqld_safe --max_connect_errors=10000 &
如果在给定主机上遇到该错误,首先应核实该主机的TCP/IP连接是否正确。如果存在网络问题,增加max_connect_errors变量的值不会有任何好处。
GRANT ALL PRIVILEGES ON *.* TO 'space'@'%' IDENTIFIED BY '123qwe';
GRANT ALL PRIVILEGES ON *.* TO 'space'@'localhost' IDENTIFIED BY '123qwe';
只对某个库分配权限:
GRANT ALL ON DB_***team2010***.* TO kary@localhost IDENTIFIED BY "zu9UWep**";
FLUSH PRIVILEGES ;
mysql -ukary -pzu9UWepr
FLUSH PRIVILEGES ;
mysql -ukary -pzu9UWepr
mysql -uspace -p123qwe -P3306
最后,刷新:
FLUSH PRIVILEGES
http://www.linuxidc.com/Linux/2008-10/16760p2.htm
[ 起源 ]
Linux/Unix下守护进程(Daemon)大家都知道,比如我们常用的httpd、mysqld等等,就是常驻内存运行的程序,类似于Windows下的服务。一般守护进程都是使用C/C++来写,就是通过fork生成子进程,当前台shell下的父进程被杀掉,子进程就转到后台运行,为了不在终端产生输出信息,就通过 syslog等函数来写日志文件。
我们知道php是脚本语言,通过php的脚本引擎来执行,所以要做成守护进程比较麻烦,我们今天就来结合Unix/Linux的命令来实现我们守护进程的功能。
[ 原理 ]
Unix中的nohup命令的功能就是不挂断地运行命令,同时nohup把程序的所有输出到放到当前目录的nohup.out文件中,如果文件不可写,则放到<用户主目录>/nohup.out 文件中。那么有了这个命令以后,我们的php程序就写程shell脚本,使用循环来让我们的脚本一直运行,那么不管我们终端窗口是否关闭,都能够让我们的php脚本一直运行。当然,当我们的php进程被杀或者我们的操作系统重启了,自然就会中止了。
[ 功能 ]
肯定会问,让我们的php脚本做了守护进程又有什么用处呢?当然有,比如最典型的作用,能够基本的替代cron的功能,比如我们需要定期实行的某些操作,完全可以交给它来做,不再需要cron,当然,如果服务器重启就没有办法了,不过,一般的Unix服务器不是那么容易重启的。另外,我们还可以做一个简单的服务器端的功能,比如做一个能够Telnet过去的服务器,嘿嘿,可以做成一个小后门,不过这样实现稍微有点复
杂。
[ 实践 ]
例子一:自动生成文件
我们现在来做两个例子来证明我们上面的说法。首先第一个是每个三十秒自动生成一个文件,永远执行下去。
首必须确保操作系统是Unix或者Linux,比如可以是FreeBSD、Redhat、Fedora或者SUSE什么的。然后我们必须确保我们的php脚本引擎是在 /usr/local/php/bin/php,具体路径可以按照你实际路径来写,如果没有脚本引擎,请自行安装。
比如当前目录是 /home/heiyeluren/,那么我们使用vi或者其他编辑器编写一个叫做php_daemon1.php的文件:
$ vi php_daemon1.php
然后写入如下代码:
然后保存并且退出vi,然后赋予php_daemon1.php文件可执行权限:
$ chmod +x /home/heiyeluren/php_daemon1.php
然后再让我们的脚本再后台执行,执行如下命令:
$ nohup /home/heiyeluren/php_daemon1.php &
记得最后加上 & 符号,这样才能够跑到后台去运行,执行上述命令后出现如下提示:
[1] 82480
appending output to nohup.out
再 回后车后将出现shell提示符。那么上面的提示就是说,所有命令执行的输出信息都会放到 nohup.out 文件中,这个上面已经讲了。然后执行上面命令后,我们每个三十秒在当前目录就会看到多出以test_开头的文件,比如: test_1139901144.txt test_1139901154.txt等等文件,那么就证明我们的程序已经再后台运行了。
那么我们如何终止程序的运行呢?最好办法就是重启操作系统,呵呵,当然,这是不可取的,我们可以使用kill命令来杀掉这个进程,杀进程之前自然后知道进程的PID号,就是Process ID,使用ps命令就能够看到了。
上面我们已经看到了我们的php的进程id是:82510 ,于是我们再执行kill命令:
看到这么提示就明白这个进程被杀了,再ps,就会发现没有了:
$ ps
PID TT STAT TIME COMMAND
82374 p3 Ss 0:00.17 -bash (bash)
82535 p3 R+ 0:00.00 ps
如果直接ps命令无法看到进程,那么就使用 ps & apos 两个结合命令来查看,一定能够看到进程。
再上面的基础上进程扩展,能够做成属于自己的cron程序,那就不需要cron啦,当然,这只是一种方式
例子二:服务器端的守护进程
这个例子跟网络有关,大致就是模拟使用php做服务器端,然后一直后台运行,达到服务器端Daemon的效果。
继续在我们的主目录下:/home/heiyeluren,编辑文件php_daemon2.php:
输入如下代码(代码来自PHP手册,我进行了修改注释):
保存以上代码退出。
上面的代码大致就是完成一个类似于Telnet服务器端的功能,就是当服务器端运行该程序的时候,客户端能够连接该服务器的10000端口进行通信。
加上文件的可执行权限:
在服务器上执行命令:
就进入了后台运行,我们通过Windows的客户端telnet上去:
如果提示:
正在连接到192.168.0.188...不能打开到主机的连接, 在端口 10000: 连接失败
则说明服务器端没有开启,或者上面的程序没有正确执行,请检查php是否 --enable-sockets 功能。如果提示:
php>
则说明顺利连接上了我们的PHP写的服务器端守护进程,在php>提示符后面能够执行help、quit、shutdown等三个命令,如果命令输入不是这三
个,则提示:
这个服务器端就不介绍了,可以自行扩展。
杀进程跟例子一类似。
[ 总结 ]
通过以上学习,我们知道php也可以做守护进程,如果设计的好,功能也会比较强大,不过我们这里只是学习而已,可以自行研究更新。
本文参考了php中文手册,多看手册,对自己非常有好处
Linux/Unix下守护进程(Daemon)大家都知道,比如我们常用的httpd、mysqld等等,就是常驻内存运行的程序,类似于Windows下的服务。一般守护进程都是使用C/C++来写,就是通过fork生成子进程,当前台shell下的父进程被杀掉,子进程就转到后台运行,为了不在终端产生输出信息,就通过 syslog等函数来写日志文件。
我们知道php是脚本语言,通过php的脚本引擎来执行,所以要做成守护进程比较麻烦,我们今天就来结合Unix/Linux的命令来实现我们守护进程的功能。
[ 原理 ]
Unix中的nohup命令的功能就是不挂断地运行命令,同时nohup把程序的所有输出到放到当前目录的nohup.out文件中,如果文件不可写,则放到<用户主目录>/nohup.out 文件中。那么有了这个命令以后,我们的php程序就写程shell脚本,使用循环来让我们的脚本一直运行,那么不管我们终端窗口是否关闭,都能够让我们的php脚本一直运行。当然,当我们的php进程被杀或者我们的操作系统重启了,自然就会中止了。
[ 功能 ]
肯定会问,让我们的php脚本做了守护进程又有什么用处呢?当然有,比如最典型的作用,能够基本的替代cron的功能,比如我们需要定期实行的某些操作,完全可以交给它来做,不再需要cron,当然,如果服务器重启就没有办法了,不过,一般的Unix服务器不是那么容易重启的。另外,我们还可以做一个简单的服务器端的功能,比如做一个能够Telnet过去的服务器,嘿嘿,可以做成一个小后门,不过这样实现稍微有点复
杂。
[ 实践 ]
例子一:自动生成文件
我们现在来做两个例子来证明我们上面的说法。首先第一个是每个三十秒自动生成一个文件,永远执行下去。
首必须确保操作系统是Unix或者Linux,比如可以是FreeBSD、Redhat、Fedora或者SUSE什么的。然后我们必须确保我们的php脚本引擎是在 /usr/local/php/bin/php,具体路径可以按照你实际路径来写,如果没有脚本引擎,请自行安装。
比如当前目录是 /home/heiyeluren/,那么我们使用vi或者其他编辑器编写一个叫做php_daemon1.php的文件:
$ vi php_daemon1.php
然后写入如下代码:
#! /usr/local/php/bin/php
<?
set_time_limit(0);
while(1)
{
@fopen("test_".time().".txt","w");
sleep(30);
}
?>
<?
set_time_limit(0);
while(1)
{
@fopen("test_".time().".txt","w");
sleep(30);
}
?>
然后保存并且退出vi,然后赋予php_daemon1.php文件可执行权限:
$ chmod +x /home/heiyeluren/php_daemon1.php
然后再让我们的脚本再后台执行,执行如下命令:
$ nohup /home/heiyeluren/php_daemon1.php &
记得最后加上 & 符号,这样才能够跑到后台去运行,执行上述命令后出现如下提示:
[1] 82480
appending output to nohup.out
再 回后车后将出现shell提示符。那么上面的提示就是说,所有命令执行的输出信息都会放到 nohup.out 文件中,这个上面已经讲了。然后执行上面命令后,我们每个三十秒在当前目录就会看到多出以test_开头的文件,比如: test_1139901144.txt test_1139901154.txt等等文件,那么就证明我们的程序已经再后台运行了。
那么我们如何终止程序的运行呢?最好办法就是重启操作系统,呵呵,当然,这是不可取的,我们可以使用kill命令来杀掉这个进程,杀进程之前自然后知道进程的PID号,就是Process ID,使用ps命令就能够看到了。
$ ps
PID TT STAT TIME COMMAND
82374 p3 Ss 0:00.14 -bash (bash)
82510 p3 S 0:00.06 /usr/local/php/bin/php /home/heiyeluren/php_daemon1.php
82528 p3 R+ 0:00.00 ps
PID TT STAT TIME COMMAND
82374 p3 Ss 0:00.14 -bash (bash)
82510 p3 S 0:00.06 /usr/local/php/bin/php /home/heiyeluren/php_daemon1.php
82528 p3 R+ 0:00.00 ps
上面我们已经看到了我们的php的进程id是:82510 ,于是我们再执行kill命令:
$ kill -9 82510
[1]+ Killed nohup /home/heiyeluren/php_daemon1.php
[1]+ Killed nohup /home/heiyeluren/php_daemon1.php
看到这么提示就明白这个进程被杀了,再ps,就会发现没有了:
$ ps
PID TT STAT TIME COMMAND
82374 p3 Ss 0:00.17 -bash (bash)
82535 p3 R+ 0:00.00 ps
如果直接ps命令无法看到进程,那么就使用 ps & apos 两个结合命令来查看,一定能够看到进程。
再上面的基础上进程扩展,能够做成属于自己的cron程序,那就不需要cron啦,当然,这只是一种方式
例子二:服务器端的守护进程
这个例子跟网络有关,大致就是模拟使用php做服务器端,然后一直后台运行,达到服务器端Daemon的效果。
继续在我们的主目录下:/home/heiyeluren,编辑文件php_daemon2.php:
$ vi php_daemon2.php
输入如下代码(代码来自PHP手册,我进行了修改注释):
#! /usr/local/php/bin/php
<?php
/* 设置不显示任何错误 */
error_reporting(0);
/* 脚本超时为无限 */
set_time_limit(0);
/* 开始固定清除 */
ob_implicit_flush();
/* 本机的IP和需要开放的端口 */
$address = '192.168.0.1';
$port = 10000;
/* 产生一个Socket */
if (($sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP)) < 0) {
echo "socket_create() failed: reason: " . socket_strerror($sock) . "\n";
}
/* 把IP地址端口进行绑定 */
if (($ret = socket_bind($sock, $address, $port)) < 0) {
echo "socket_bind() failed: reason: " . socket_strerror($ret) . "\n";
}
/* 监听Socket连接 */
if (($ret = socket_listen($sock, 5)) < 0) {
echo "socket_listen() failed: reason: " . socket_strerror($ret) . "\n";
}
/* 永远循环监接受用户连接 */
do {
if (($msgsock = socket_accept($sock)) < 0) {
echo "socket_accept() failed: reason: " . socket_strerror($msgsock) . "\n";
break;
}
/* 发送提示信息给连接上来的用户 */
$msg = "==========================================\r\n" .
" Welcome to the PHP Test Server. \r\n\r\n".
" To quit, type 'quit'. \r\n" .
" To shut down the server type 'shutdown'.\r\n" .
" To get help message type 'help'.\r\n" .
"==========================================\r\n" .
"php> ";
socket_write($msgsock, $msg, strlen($msg));
do {
if (false === ($buf = socket_read($msgsock, 2048, PHP_NORMAL_READ))) {
echo "socket_read() failed: reason: " . socket_strerror($ret) . "\n";
break 2;
}
if (!$buf = trim($buf)) {
continue;
}
/* 客户端输入quit命令时候关闭客户端连接 */
if ($buf == 'quit') {
break;
}
/* 客户端输入shutdown命令时候服务端和客户端都关闭 */
if ($buf == 'shutdown') {
socket_close($msgsock);
break 2;
}
/* 客户端输入help命令时候输出帮助信息 */
if ($buf == 'help') {
$msg = " PHP Server Help Message \r\n\r\n".
" To quit, type 'quit'. \r\n" .
" To shut down the server type 'shutdown'.\r\n" .
" To get help message type 'help'.\r\n" .
"php> ";
socket_write($msgsock, $msg, strlen($msg));
continue;
}
/* 客户端输入命令不存在时提示信息 */
$talkback = "PHP: unknow command '$buf'.\r\nphp> ";
socket_write($msgsock, $talkback, strlen($talkback));
echo "$buf\n";
} while (true);
socket_close($msgsock);
} while (true);
/* 关闭Socket连接 */
socket_close($sock);
?>
<?php
/* 设置不显示任何错误 */
error_reporting(0);
/* 脚本超时为无限 */
set_time_limit(0);
/* 开始固定清除 */
ob_implicit_flush();
/* 本机的IP和需要开放的端口 */
$address = '192.168.0.1';
$port = 10000;
/* 产生一个Socket */
if (($sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP)) < 0) {
echo "socket_create() failed: reason: " . socket_strerror($sock) . "\n";
}
/* 把IP地址端口进行绑定 */
if (($ret = socket_bind($sock, $address, $port)) < 0) {
echo "socket_bind() failed: reason: " . socket_strerror($ret) . "\n";
}
/* 监听Socket连接 */
if (($ret = socket_listen($sock, 5)) < 0) {
echo "socket_listen() failed: reason: " . socket_strerror($ret) . "\n";
}
/* 永远循环监接受用户连接 */
do {
if (($msgsock = socket_accept($sock)) < 0) {
echo "socket_accept() failed: reason: " . socket_strerror($msgsock) . "\n";
break;
}
/* 发送提示信息给连接上来的用户 */
$msg = "==========================================\r\n" .
" Welcome to the PHP Test Server. \r\n\r\n".
" To quit, type 'quit'. \r\n" .
" To shut down the server type 'shutdown'.\r\n" .
" To get help message type 'help'.\r\n" .
"==========================================\r\n" .
"php> ";
socket_write($msgsock, $msg, strlen($msg));
do {
if (false === ($buf = socket_read($msgsock, 2048, PHP_NORMAL_READ))) {
echo "socket_read() failed: reason: " . socket_strerror($ret) . "\n";
break 2;
}
if (!$buf = trim($buf)) {
continue;
}
/* 客户端输入quit命令时候关闭客户端连接 */
if ($buf == 'quit') {
break;
}
/* 客户端输入shutdown命令时候服务端和客户端都关闭 */
if ($buf == 'shutdown') {
socket_close($msgsock);
break 2;
}
/* 客户端输入help命令时候输出帮助信息 */
if ($buf == 'help') {
$msg = " PHP Server Help Message \r\n\r\n".
" To quit, type 'quit'. \r\n" .
" To shut down the server type 'shutdown'.\r\n" .
" To get help message type 'help'.\r\n" .
"php> ";
socket_write($msgsock, $msg, strlen($msg));
continue;
}
/* 客户端输入命令不存在时提示信息 */
$talkback = "PHP: unknow command '$buf'.\r\nphp> ";
socket_write($msgsock, $talkback, strlen($talkback));
echo "$buf\n";
} while (true);
socket_close($msgsock);
} while (true);
/* 关闭Socket连接 */
socket_close($sock);
?>
保存以上代码退出。
上面的代码大致就是完成一个类似于Telnet服务器端的功能,就是当服务器端运行该程序的时候,客户端能够连接该服务器的10000端口进行通信。
加上文件的可执行权限:
$ chmod +x /home/heiyeluren/php_daemon2.php
在服务器上执行命令:
$ nohup /home/heiyeluren/php_daemon2.php &
就进入了后台运行,我们通过Windows的客户端telnet上去:
C:\>telnet 192.168.0.1 10000
如果提示:
正在连接到192.168.0.188...不能打开到主机的连接, 在端口 10000: 连接失败
则说明服务器端没有开启,或者上面的程序没有正确执行,请检查php是否 --enable-sockets 功能。如果提示:
==========================================
Welcome to the PHP Test Server.
To quit, type 'quit'.
To shut down the server type 'shutdown'.
To get help message type 'help'.
==========================================
Welcome to the PHP Test Server.
To quit, type 'quit'.
To shut down the server type 'shutdown'.
To get help message type 'help'.
==========================================
php>
则说明顺利连接上了我们的PHP写的服务器端守护进程,在php>提示符后面能够执行help、quit、shutdown等三个命令,如果命令输入不是这三
个,则提示:
php> asdf
PHP: unknow command 'asdf'.
执行help命令可以获取帮助:
php> help
PHP Server Help Message
To quit, type 'quit'.
To shut down the server type 'shutdown'.
To get help message type 'help'.
PHP: unknow command 'asdf'.
执行help命令可以获取帮助:
php> help
PHP Server Help Message
To quit, type 'quit'.
To shut down the server type 'shutdown'.
To get help message type 'help'.
这个服务器端就不介绍了,可以自行扩展。
杀进程跟例子一类似。
[ 总结 ]
通过以上学习,我们知道php也可以做守护进程,如果设计的好,功能也会比较强大,不过我们这里只是学习而已,可以自行研究更新。
本文参考了php中文手册,多看手册,对自己非常有好处
文件:
a.php b.php
aTest.php
a.php:
b.php
<?php
class b
{ protected $a = 0;
protected $b = 0;
public function __construct($a,$b)
{
$this->a = $a;
$this->b = $b;
echo $this->b;
}
public function need_mock($a)
{
$b = $this->a+$a;
return $b;
}
}
?>
aTest.php
a.php b.php
aTest.php
a.php:
<?php
class a
{
private $inHandle;
public function getHandle($handle='')
{
if ('' != $handle)
{
$this->inHandle = $handle;
return ;
}
elseif ('' != $this->inHandle)
{
return;
}
$this->inHandle = new b();
return;
}
public function use_b_class($num)
{ //调用b类的:need_mock方法,假如是外部资源,为此需要mock
$value = $this->inHandle->need_mock($num);
$result = $value;
return $result;
}
}
?>
class a
{
private $inHandle;
public function getHandle($handle='')
{
if ('' != $handle)
{
$this->inHandle = $handle;
return ;
}
elseif ('' != $this->inHandle)
{
return;
}
$this->inHandle = new b();
return;
}
public function use_b_class($num)
{ //调用b类的:need_mock方法,假如是外部资源,为此需要mock
$value = $this->inHandle->need_mock($num);
$result = $value;
return $result;
}
}
?>
b.php
<?php
class b
{ protected $a = 0;
protected $b = 0;
public function __construct($a,$b)
{
$this->a = $a;
$this->b = $b;
echo $this->b;
}
public function need_mock($a)
{
$b = $this->a+$a;
return $b;
}
}
?>
aTest.php
<?php
require_once 'a.php';
require_once 'b.php';
require_once 'PHPUnit/Framework/TestCase.php';
/**
* a test case.
*/
class aTest extends PHPUnit_Framework_TestCase {
/**
* @var a
*/
private $a;
/**
* Prepares the environment before running a test.
*/
protected function setUp() {
parent::setUp ();
// TODO Auto-generated aTest::setUp()
$this->a = new a(/* parameters */);
}
/**
* Cleans up the environment after running a test.
*/
protected function tearDown() {
// TODO Auto-generated aTest::tearDown()
$this->a = null;
parent::tearDown ();
}
/**
* Constructs the test case.
*/
public function __construct() {
// TODO Auto-generated constructor
}
/**
* Tests a->getHandle()
*/
public function testGetHandle() {
// TODO Auto-generated aTest->testGetHandle()
$this->markTestIncomplete ( "getHandle test not implemented" );
$this->a->getHandle(/* parameters */);
}
/**
* Tests a->use_b_class()
*/
public function testUse_b_class() {
// TODO Auto-generated aTest->testUse_b_class()
//$this->markTestIncomplete ( "use_b_class test not implemented" );
//$this->a->use_b_class(/* parameters */);
$a = array(1,"第二个参数");//注意:必须传array(构造函数参数1,构造函数参数2,构造函数参数3)
$stub = $this->getMock('b', array('need_mock'),$a);
$stub->expects($this->any())
->method('need_mock')
->with(
$this->equalTo( 1 )//传入一个参数
)
->will($this->returnValue(11));//设定返回为11
$this->a->getHandle($stub);//传入经过mock的对象
echo $this->a->use_b_class(1);
$this->assertEquals($this->a->use_b_class(1) , 11 );
$this->assertEquals(array(array(0,1,2)),array(array(0,1,2)));//必须是所谓的二维数组,否则出错
}
}
require_once 'a.php';
require_once 'b.php';
require_once 'PHPUnit/Framework/TestCase.php';
/**
* a test case.
*/
class aTest extends PHPUnit_Framework_TestCase {
/**
* @var a
*/
private $a;
/**
* Prepares the environment before running a test.
*/
protected function setUp() {
parent::setUp ();
// TODO Auto-generated aTest::setUp()
$this->a = new a(/* parameters */);
}
/**
* Cleans up the environment after running a test.
*/
protected function tearDown() {
// TODO Auto-generated aTest::tearDown()
$this->a = null;
parent::tearDown ();
}
/**
* Constructs the test case.
*/
public function __construct() {
// TODO Auto-generated constructor
}
/**
* Tests a->getHandle()
*/
public function testGetHandle() {
// TODO Auto-generated aTest->testGetHandle()
$this->markTestIncomplete ( "getHandle test not implemented" );
$this->a->getHandle(/* parameters */);
}
/**
* Tests a->use_b_class()
*/
public function testUse_b_class() {
// TODO Auto-generated aTest->testUse_b_class()
//$this->markTestIncomplete ( "use_b_class test not implemented" );
//$this->a->use_b_class(/* parameters */);
$a = array(1,"第二个参数");//注意:必须传array(构造函数参数1,构造函数参数2,构造函数参数3)
$stub = $this->getMock('b', array('need_mock'),$a);
$stub->expects($this->any())
->method('need_mock')
->with(
$this->equalTo( 1 )//传入一个参数
)
->will($this->returnValue(11));//设定返回为11
$this->a->getHandle($stub);//传入经过mock的对象
echo $this->a->use_b_class(1);
$this->assertEquals($this->a->use_b_class(1) , 11 );
$this->assertEquals(array(array(0,1,2)),array(array(0,1,2)));//必须是所谓的二维数组,否则出错
}
}