试了N多方法,貌似在终端执行命令:
export LC_ALL=zh_CN.GB2312;export LANG=zh_CN.GB2312是最有效的。
=======================
1.不管用那种ssh客户端,字体设定一定要设为可以显示中文的字体。
2.远程的locale一定要设置为LANG=zh_CN.UTF-8
========================================
修改/etc/profile
增加这一行
export LC_ALL=zh_CN.GBK
========================================
SSH显示中文乱码问题
(1) 打开/etc/sysconfig/i18n
设置为:
LANG="zh_CN.GB2312"
LANGUAGE="zh_CN.GB18030:zh_CN.GB2312:zh_CN"
SUPPORTED="zh_CN.GB18030:zh_CN.GB2312:zh_CN.UTF-8:zh:en_US.UTF-8:en_US:en:ja_JP.UTF-8:ja_JP:ja"
SYSFONT="lat0-sun16"
SYSFONTACM="8859-15"
其中LANG="zh_CN.GB2312" 是必须的(如果你不想让中文乱码的话!!!)
其它的可以按照自已的需求来改变。
(2) 打开smb.conf
添加:
display charset=cp936
unix charset=cp936
doc charset=cp936
========================
与association一样,collection元素也有两种形式,现介绍如下:
一、嵌套的resultMap
实际上以前的示例使用的就是这种方法,今天介绍它的另一种写法。还是以教师映射为例,修改映射文件TeacherMapper.xml如下(点击此处进入嵌套resultMap形式的示例源码下载页面。注:本示例代码是在修改本系列的上篇博文示例代码的基础上完成的,用到了MapperScannerConfigurer和注解等知识。对这些知识不熟悉的读者,可参考上篇博文:http://legend2011.blog.51cto.com/3018495/980150):
<?xmlversion="1.0"encoding="utf8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--与以前一样,namespace的值是对应的映射器接口的完整名称-->
<mappernamespace="com.abc.mapper.TeacherMapper">
<!--TeacherMapper接口中getById方法对应的SQL语句。
查询教师及其指导的学生的信息。由于教师、学生都有
id、name、gender等属性,因此给教师的字段都起了别名-->
<selectid="getById"parameterType="int"resultMap="supervisorResultMap">
select t.id t_id, t.name t_name, t.gender t_gender,
t.research_area t_research_area, t.title t_title,
s.id,s.name, s.gender,s.major,s.grade
from teacher t,student s where t.id=#{id}
and s.supervisor_id = t.id
</select>
<!--教师实体映射-->
<resultMapid="supervisorResultMap"type="Teacher">
<idproperty="id"column="t_id"/>
<resultproperty="name"column="t_name"/>
<resultproperty="gender"column="t_gender"/>
<resultproperty="researchArea"column="t_research_area"/>
<resultproperty="title"column="t_title"/>
<!--需要注意的是,上面的select语句中学生的字段名/别名应与
下面的column属性一致。ofType指collection包含的元素的类型,
此属性不可少-->
<collectionproperty="supStudents"ofType="Student">
<idproperty="id"column="id"/>
<resultproperty="name"column="name"/>
<resultproperty="gender"column="gender"/>
<resultproperty="major"column="major"/>
<resultproperty="grade"column="grade"/>
<!--映射学生的指导教师属性,用到了
supervisorResultMap本身-->
<associationproperty="supervisor"
resultMap="supervisorResultMap"/>
</collection>
</resultMap>
</mapper>
运行程序结果如下:
与以前的写法相比,这种写法的缺点是学生实体映射被嵌入到教师实体映射中,因此学生实体映射不能被重用。
二、嵌套的select语句
这种方式是使用一条单独的select语句来加载关联的实体(在本例中就是学生实体),然后在collection元素中引用此select语句(注:此方法会产生N+1问题,关于这个问题可参考本系列博客中的“MyBatis中的N+1问题”)。首先修改TeacherMapper.xml如下(点击此处进入嵌套select语句形式示例源码下载页面):
<?xmlversion="1.0"encoding="utf8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--与以前一样,namespace的值是对应的映射器接口的完整名称-->
<mappernamespace="com.abc.mapper.TeacherMapper">
<!--TeacherMapper接口中getById方法对应的SQL语句。
查询教师的信息。-->
<selectid="getById"parameterType="int"resultMap="supervisorResultMap">
select * from teacher where id=#{id}
</select>
<!--教师实体映射-->
<resultMapid="supervisorResultMap"type="Teacher">
<idproperty="id"column="id"/>
<resultproperty="name"column="name"/>
<resultproperty="gender"column="gender"/>
<resultproperty="researchArea"column="research_area"/>
<resultproperty="title"column="title"/>
<!--ofType指collection包含的元素的类型,此属性不可少。
column属性指把上述的getById的select语句中的教师id列的值作为参数
传递给将要引用到的下述的getStudents的select语句,此属性不可少。
引用的形式为:命名空间.select语句id-->
<collectionproperty="supStudents"column="id"ofType="Student"
select="com.abc.mapper.StudentMapper.getStudents"/>
</resultMap>
</mapper>
在这里把根据指导教师id查询学生信息的SQL语句写在StudentMapper.xml中,并引用其中的学生实体映射studentResultMap。修改StudentMapper.xml如下:
<?xmlversion="1.0"encoding="utf8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mappernamespace="com.abc.mapper.StudentMapper">
<resultMapid="studentResultMap"type="Student">
<idproperty="id"column="id"/>
<resultproperty="name"column="name"/>
<resultproperty="gender"column="gender"/>
<resultproperty="major"column="major"/>
<resultproperty="grade"column="grade"/>
<!--在这里引用supervisorResultMap和getById,亦采用
命名空间名.相关元素id的形式。column="supervisor_id"
属性不可少-->
<associationproperty="supervisor"
resultMap="com.abc.mapper.TeacherMapper.supervisorResultMap"
select="com.abc.mapper.TeacherMapper.getById"column="supervisor_id"/>
</resultMap>
<!--根据指导教师id查询学生信息-->
<selectid="getStudents"parameterType="int"
resultMap="studentResultMap">
select * from student where supervisor_id = #{id}
</select>
</mapper>
执行结果如下:
最近在工作中遇到了一个需求
在执行数据库操作时需要先判断指定的数据是否存在,如果不存在则插入,存在则更新
最开始使用的是三条SQL语句:
- SELECT bl_count,bl_src,bl_date,bl_topic FROM temp_table WHERE bl_topic=? AND bl_src=? AND bl_date=?;
-
- UPDATE temp_table SET bl_count=? WHERE bl_topic=? AND bl_src=? AND bl_date=?;
-
- INSERT INTO temp_table (bl_src,bl_date,bl_count,bl_topic) values(?,?,?,?)
逻辑是:
- if(SELECT!= null){
- UPDATE
- }else{
- INSERT
- }
后来leader提示还有新的方法,一条SQL语句就能搞定:
- INSERT INTO temp_table(bl_src,bl_date,bl_count,bl_topic) VALUES(?,?,?,?) ON DUPLICATE KEY UPDATE bl_count=bl_count+?;
但是有个前提就是:什么时候会执行update语句?在SQL语句中并没有条件。
后来在网上看到的,执行update语句的条件是insert语句的执行会造成唯一键的重复。
所以,在创建表的时候还要加上唯一键的约束:
- ALTER TABLE temp_table ADD CONSTRAINT c_topic_src_date UNIQUE(bl_topic,bl_src,bl_date);
这样就能达到目的。
分类: 其他 2012-04-06 10:51
2572人阅读 评论(2) 收藏 举报 JSP 中include 另一个文件时有个很偏的属性,叫flush,默认为 false。
在同一个 JSP 中,如果不断 include 自己(源文件),在逻辑上会形成死循环。若默认情况下,服务器会等待该文件被读到底端,然后才输出到客户端,并且销毁该次访问的 request 和 response。而当把flush 属性赋为真值时,在缓存累积了一定数据时,服务器会先提供一部分数据给浏览器,并等待后续内容。
由此可以得出结论,在简单页面中,该属性不纳入考虑,而在页面包含大量数据时,为缩短客户端延迟,可将一部分内容先行输出。该属性在 Servlet 中也有对应的应用。
大家都在为项目开发成功而喜悦,但可不知成功的路上是会经常出错的,下面是我碰到的一些错误集合!
【错误信息】
01-16 17:16:18.945: I/magh(979): org.apache.http.conn.HttpHostConnectException: Connection to http://127.0.0.1:8080 refused
在android模拟器连接本机访问web时报这错,把127.0.0.1改成localhost也是一样的
原因:
在向本机发送HTTP请求时,有一点必须注意,就是在android
虚拟机中,
127.0.0.1为android 虚拟机的IP地址,如果要访问本机,IP地址应该改为
10.0.2.2。否则肯定会导致访问不成功!
==========================================================================
【错误信息】
[2011-01-19 16:39:10 - ApiDemos] WARNING: Application does not specify an API level requirement!
[2011-01-19 16:39:10 - ApiDemos] Device API version is 8 (Android 2.2)
原因:
不影响正常运行。在AndroidManifest.xml文件中没有加API的版本号,在<manifest> </manifest> 之间加<uses-sdk android:minSdkVersion="3"></uses-sdk>
[2011-01-19 16:55:04 - ApiDemos] Installation error: INSTALL_FAILED_INSUFFICIENT_STORAGE
[2011-01-19 16:55:04 - ApiDemos] Please check logcat output for more details.
[2011-01-19 16:55:05 - ApiDemos] Launch canceled!
该设备没有足够的存储空间来安装应用程序,
【错误信息】
[2011-02-18 11:46:53] Failed to push selection: Is a directory
原因:
原先目录已经有pkg_3.apk的文件夹,再copy一个pkg_3.apk安装文件时出现问题,解决办法,先删除掉pkg_3.apk的文件夹
[2011-03-04 09:25:12 - ActivityMain]: Dx
UNEXPECTED TOP-LEVEL EXCEPTION:
java.lang.IllegalArgumentException: already added: Lorg1/apache/commons/codec/net/RFC1522Codec;
[2011-03-04 09:25:12 - ActivityMain]: Dx at com.android.dx.dex.file.ClassDefsSection.add(ClassDefsSection.java:123)
[2011-03-04 09:25:12 - ActivityMain]: Dx at com.android.dx.dex.file.DexFile.add(DexFile.java:143)
.....
[2011-03-04 09:25:12 - ActivityMain]: Dx1 error; aborting
[2011-03-04 09:25:12 - ActivityMain] Conversion to Dalvik format failed with error 1
原因:
【错误信息】
启动Eclipse时出现:
this android sdk requires android developer toolkit version 10.0.0 or above.
current version is 8.0.1.v201012062107-82219.
please update adt to the latest version
原因:
Eclipse的android开发插件版本过低,应该下载ADT-10.0.0,并且
1. 启动 Eclipse, 然后进入 Help > Install New Software.
2. 在 Available Software 对话框里,点击 Add....
【错误信息】
[2011-03-09 15:21:34 - Info] Failed to install Info.apk on device '?': Unable to open sync connection!
[2011-03-09 15:21:34 - Info] java.io.IOException: Unable to open sync connection!
[2011-03-09 15:21:34 - Info] Launch canceled!
原因:
关闭模拟器和eclipse,执行adb kill-server命令,然后重试一下
【错误信息】
调用Webservice时出现
java.net.SocketException: Permission denied (maybe missing INTERNET permission)
原因:
需要访问到网络,所以,在AndroidManifest.xml中,需要进行如下配置:
<uses-permission android:name="android.permission.INTERNET" />
【错误信息】
org.xmlpull.v1.XmlPullParserException: expected: START_TAG {http://schemas.xmlsoap.org/soap/envelope/}Envelope (position:START_TAG <{http://schemas.xmlsoap.org/wsdl/}wsdl:definitions targetNamespace='http://bo.webservice.nqbx.nq.com'>@2:603 injava.io.InputStreamReader@44a3a7b0)
原因有可能是以下2个之一:
1)Webservice服务器的Soap版本为1.0,所以客户端指定
SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
VER11改为VER10
2)String serviceUrl = "http://200.200.200.11:10000/nqbx/service/InqBxWebService?wsdl";
Url指的是你的webservice的地址.一般都是以***.wsdl或者***.?wsdl结束的...但是.需要注意的是..要去掉后面的.wsdl或者.?wsdl
【错误信息】
在新的线程中 public class HttpThread extends Thread {...}
增加一个弹出窗体:
new AlertDialog.Builder(this).setTitle("数据加载失败").setMessage("请检查网络连接情况") .setPositiveButton("OK", new DialogInterface.OnClickListener(){ public void onClick(DialogInterface dialoginterface, int i) { } }).show();
原因及解决办法:
//不能在线程中操作UI界面
java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
修改后:
new AlertDialog.Builder(com.nantsing.infoquery.chuanbo_detail.this).setTitle(" 数据加载失败").setMessage("请检查网络连接情况") .setPositiveButton("OK", new DialogInterface.OnClickListener(){ public void onClick(DialogInterface dialoginterface, int i) { }
【错误信息】
The constructor AlertDialog.Builder(chuanbo_detail.HttpThread) is undefined
原因及解决办法:
在UI主线程之外是无法对UI组件进行控制的。因为你必须在新线程任务完成之后利用各种方法先UI主线程发送消息通知任务完成从而来显示各种提示消息。
线程间通信方法有多种,常用的是用handler来传递消息。
如下:
线程中构造消息:
//构造消息Message message = handle.obtainMessage();Bundle b = new Bundle();b.putString("tag", "1");message.setData(b);handle.sendMessage(message);
另外自定义消息:
/** * 捕获消息队列 fubin.pan 2011-04-02 */Handler handler = new Handler() {public void handleMessage(Message m) {if (!m.getData().getString("tag").equals("1")){ ...}else{new AlertDialog.Builder(chuanbo_detail.this).setTitle("数据加载失败").setMessage(" 请检查网络连接情况!") .setPositiveButton("OK", new DialogInterface.OnClickListener(){ public void onClick(DialogInterface dialoginterface, int i) { } }).show();}}};
【错误信息】
android低版本工程(如1.5)放到高版本环境中(如2.2)可能会上述错误,解决方法如下:
1。 如果不修改android sdk版本,则使用project clean 命令作用于某工程即可。
(该处理方式只是在高版本中兼容了低版本工程,未真正意义上的升级)
2。 如果修改android sdk版本,则需要以下几个步骤:
1)修改SDK
选择工程,build path --> configure build path ---> library 删除引用的低版本SDK,
然后add External JARs,选择高版本SDK,OK,保存
2)修改classpath文件
该文件可能存在该项: <classpathentry kind="lib" path ="你所指定的高版本的地址"
把她修改成<classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK" />
3) 修改AndroidManifest.xml
在AndroidManifest.xml文件中,application标签后添加<uses-sdk android:minSdkVersion="3"></uses-sdk>
4) 修改default.properties(很重要)
该文件最后一行(前面没用#的)target=android-3 该成target=android-8,保存。
再看看你的工程和新建的android 2.2的工程结构就一样了。
【错误信息】
在线程debug(运行没有问题)时调用Webservice时出现:
'JDI thread evaluations' has encountered a problem
Exception processing async thread queue
Exception processing async thread queue
JDI thread evaluations
原因及解决办法:
与运行无关的错误,关掉'expressions'视图就可以了
【错误信息】
打开开源项目JavaEye Android client时出错
http://javaeye-android-client.googlecode.com/svn/trunk/
这是 JavaEye 网站基于 Android 平台的客户端软件,可用以阅读动静、帖子、闲谈, 收躲, RSS 等功用。
[2011-04-19 10:55:11 - JavaEye Android Client] Project has no default.properties file! Edit the project properties to set one.
原因及解决办法:
遇到这种情况,可以创建一个default.properties文件,如果创建之后还是有错误,那么delete这个project,重新import。
编辑default.properties 之后,一般会自动创建 gen 目录, 如果没有,也可尝试手工创建。
✿Adroid Adapter ADB Interface 严重错误
今天在配置完Eclipse和Android SDK开发环境之后,想用华为C8500手机通过USB连接电脑,并在手机上去调试,但莫名其妙出现Adroid Adapter ADB Interface 安装严重错误,在豌豆荚手机精灵安装驱动的时候,也出现这个错误,后面也莫名奇妙的多装几次就好了,还没找到什么原因。
【错误信息】
用手机调试运行出现:
ActivityManager: Warning: Activity not started, its current task has been brought to the front
原因及解决办法:
该手机已经启动了相同名字的应用,关闭之后再试!
【错误信息】
最近(2012-04-05)在打开SDK Manager.exe,更新SDK时,会出现如下错误:
Failed to fetch URL https://dl-ssl.google.com/android/repository/repository.xml,
reason: Connection timed out: connect
原因及解决办法:
dl-ssl.google.com在大陆封掉了
解决方法就是修改
C:\Windows\System32\drivers\etc\hosts文件。添加一行:
74.125.237.1 dl-ssl.google.com
保存,重新启动SDK Manager.exe
【错误信息】
[2012-04-08 17:42:24 - JavaEye Android Client] ------------------------------
[2012-04-08 17:42:24 - JavaEye Android Client] Android Launch!
[2012-04-08 17:42:24 - JavaEye Android Client] The connection to adb is down, and a severe error has occured.
[2012-04-08 17:42:24 - JavaEye Android Client] You must restart adb and Eclipse.
[2012-04-08 17:42:24 - JavaEye Android Client] Please ensure that adb is correctly located at 'C:\android\android-sdk-windows\platform-tools\adb.exe' and can be executed.
原因及解决办法:
查看任务管理器,关闭所有adb.exe
重启eclipse即可
【错误信息】
更新SDK时错误信息:
Site Authentication
Please login to the following ......
原因及解决办法:
Cancel跳过提示
【错误信息】
打开Eclipse 提示安装ADT 17
原因及解决办法:
最新的Android SDK只能安装ADT 17.0.0
可用的下载地址:http://download.csdn.net/detail/merrido/4169460,
这里可不能用常规方法安装这个 ADT 17.0.0.zip 文件, 首先得解压这个文件,将里面的文件夹覆盖掉Eclipse安装目录下的文件夹。
然后再用Help-> install new software->Add -> Name: ADT Archive:选择ADT 17.0.0.zip
【错误信息】
安装ADT 17.0.0时,提示:
Your original request has been modified.
"Android DDMS" is already installed, so an update will be performed instead.
"Android Development Tools" is already installed, so an update will be performed instead.
"Android Hierarchy Viewer" is already installed, so an update will be performed instead.
"Android Traceview" is already installed, so an update will be performed instead.
Cannot complete the install because one or more required items could not be found.
Software being installed: Android Development Tools 17.0.0.v201203161636-291853 (com.android.ide.eclipse.adt.feature.group 17.0.0.v201203161636-291853)
Missing requirement: Android Development Tools 17.0.0.v201203161636-291853 (com.android.ide.eclipse.adt.feature.group 17.0.0.v201203161636-291853) requires 'org.eclipse.core.runtime 3.6.0' but it could not be found
原因及解决办法:
【错误信息】
Updates ADT 17.0.0时提示:
Cannot complete the install because one or more required items could not be found.
Software being installed: Android Development Tools 17.0.0.v201203161636-291853 (com.android.ide.eclipse.adt.feature.group 17.0.0.v201203161636-291853)
Missing requirement: Android Development Tools 17.0.0.v201203161636-291853 (com.android.ide.eclipse.adt.feature.group 17.0.0.v201203161636-291853) requires 'org.eclipse.core.runtime 3.6.0' but it could not be found
原因及解决办法:
requires 'org.eclipse.core.runtime 3.6.0' but it could not be found
requires 'org.eclipse.ui 3.6.0' but it could not be found
eclipse需要升级到3.6.0,我的版本是3.5.2
【错误信息】
[2012-04-09 17:14:49 - Info] ------------------------------
[2012-04-09 17:14:49 - Info] Android Launch!
[2012-04-09 17:14:49 - Info] Connection with adb was interrupted.
[2012-04-09 17:14:49 - Info] 0 attempts have been made to reconnect.
[2012-04-09 17:14:49 - Info] You may want to manually restart adb from the Devices view.
原因及解决办法:
重新启动eclipse
【错误信息】
[2012-04-10 09:45:49 - adb] ADB server didn't ACK
[2012-04-10 09:45:49 - adb] * failed to start daemon *
原因及解决办法:
查看任务管理器,关闭所有adb.exe
重启eclipse
【错误信息】
[2012-04-10 09:53:50 - ApiDemos] ------------------------------
[2012-04-10 09:53:50 - ApiDemos] Android Launch!
[2012-04-10 09:53:50 - ApiDemos] The connection to adb is down, and a severe error has occured.
[2012-04-10 09:53:50 - ApiDemos] You must restart adb and Eclipse.
[2012-04-10 09:53:50 - ApiDemos] Please ensure that adb is correctly located at 'C:\android\android-sdk-windows\platform-tools\adb.exe' and can be executed.
原因及解决办法:
重启eclipse
【错误信息】
安装android sdk时:
-= warning! =- A folder failed to be renamed or moved. On Windows this typically means that a program Is using that Folder (for example Windows Explorer or your anti-virus software.) Please momentarily deactivate your anti-virus software. Please also close any running programs that may be accessing the directory 'C:\android\android-sdk-windows/android-sdk-windows/too!s'. When ready, press YES to try again.
原因及解决办法:
1, 复制 tools目录
为一个新的目录 tools-copy ,此时在android-sdk-windows 目录下有两个目录 tools 和 tools-copy
2, 在tools-copy目录以管理员身份运行 android.bat ,这样就可以正常 update all 了
3.重新运行SDK Manager.exe.问题解决!
【错误信息】
“正在启动JavaEyeApiAccessor“遇到问题。
不能连接至VM
原因及解决办法:
连接不到手机虚拟机
重启拔插手机连接线
【错误信息】
调试的时候:
[2012-04-13 17:46:27 - IpsosAutoAndroid] Failed to install IpsosAutoAndroid.apk on device '?': timeout
[2012-04-13 17:46:27 - IpsosAutoAndroid] Launch canceled!
原因及解决办法:
连接真机调试的时候如果连接太久没响应就会出现timeout
1.在window-》prensent....-》android-》设置ddms的timeout时间。这种是就最有效、最简洁的。
2.delete android里面的 apk,保证速度。不过试过一次后,真机好像变“聪明了”,也出现timeout。
3.Cleaning the project (Project->Clean),不行就重启eclipse或者android,很郁闷的是,重启后运行第一次可以。第二次就开始变慢了,也就是出现timeout
4.关闭eclipse ,然后再重启,就ok
【错误信息】
调用org.ksoap2.*访问webservice时
04-13 10:09:49.565: E/dalvikvm(354): Could not find class 'org.ksoap2.serialization.SoapObject', referenced from method......
04-13 10:09:49.585: E/dalvikvm(354): Could not find class 'org.ksoap2.transport.HttpTransportSE', referenced from method......
【错误信息】
Unable to open stack trace file '/data/anr/traces.txt': Permission denied
原因及解决办法:
Unable to open stack trace file '/data/anr/traces.txt': Permission 多见于这个Activity你没有在AndroidManifest.xml中注册,就会报这样的错误。
【错误信息】
source not found
找不到源
原因及解决办法:
android目录下没有对应的sources文件
如下图,不知道为什么,最新的SDK更新API 14/15中有Sources for Android SDK,而之前的版本的源码就不更新,气愤!
下载对应的SDK Sources后,放到\android-sdk-windows\sources 目录下就OK了!
【错误信息】
Android使用KSOAP2调用WebService时:
java.lang.NoClassDefFoundError: org.ksoap2.serialization.SoapObject
原因及解决办法:
虽然标明上 Java Build Path->Libraries中已经引用了ksoap2-android 包,但是需要order and export中也把该包勾选上
【错误信息】
error: Error: No resource found that matches the given name (at 'layout_toLeftOf' with value'@id/top_send_btn').
header_questionitemlist.xml /IpsosAutoAndroid/res/layout 第 27 行 Android AAPT Problem
原因及解决办法:
【错误信息】
无法解析导入 com.renren.api.connect.android.R
原因及解决办法:
导入android源码有错,R.java文件不能自动生成解决方法
【错误信息】
Eclipse中的DDMS无法打开data文件夹下的内容,也不能往里面写东西
原因及解决办法:
通过软件获取ROOT权限
【错误信息】
Fri May 04 16:27:46 CST 2012
Internal error logged from JDI Debug:
org.eclipse.jdi.TimeoutException: 等待包 8 时发生超时。
at org.eclipse.jdi.internal.connect.PacketReceiveManager.getReply(PacketReceiveManager.java:171)
at org.eclipse.jdi.internal.connect.PacketReceiveManager.getReply(PacketReceiveManager.java:180)
......
原因及解决办法:
重新启动eclipse,不行的话重启机器
【错误信息】
java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
原因及解决办法:
如下是有问题的代码:
Thread t = new Thread() {@Overridepublic void run() {super.run();try {QuestionItemlist = quesHandler.getData();if (QuestionItemlist.size() == 0) {Toast.makeText(questionitemlist2.this,"问卷题目为 空",Toast.LENGTH_LONG).show();} else {Toast.makeText(questionitemlist2.this,"问卷题目已经获 取",Toast.LENGTH_LONG).show();}} catch (Exception e) {e.printStackTrace();}}};t.start();
【错误信息】
java.lang.IllegalArgumentException: The key must be an application-specific resource id.
原因及解决办法:
mRadioButton.setTag(1,sQuestionItem.get(i).getToNext());//设置监听 ToNext:下 一题目mRadioButton.setTag(2,sQuestionItem.get(i).getToEnd());//设置监听 ToEnd: 是否终止 抛出IllegalArgumentException的原因就在于key不唯一,正确代码如下:
mRadioButton.setTag(R.id.tag_tonext,sQuestionItem.get(i).getToNext());// 设置监听 ToNext:下一题目 mRadioButton.setTag(R.id.tag_toend,sQuestionItem.get(i).getToEnd());//设置 监听 ToEnd:是否终止
【错误信息】
点击Debug 运行 结果模拟器总是会弹出Waiting for Debugger 然后程序又可以正常运行
如果你想调试的时候去掉 Waiting for Debugger 提示
原因及解决办法:
重启启动机器就OK
本文出自 “java之路” 博客,请务必保留此出处http://2402766.blog.51cto.com/2392766/1102373
Fedora12下搭建Qt Creator的ARM开发环境 并 移植Qt4.6.2到Micro2440(一)
管理提醒: 本帖被 kasim 执行置顶操作(2010-04-11)
Fedora12下搭建Qt Creator的ARM开发环境 并 移植Qt4.6.2到Micro2440(一)
参考:
环境:虚拟机Fedora12(建议安装Vmware Tools,详细安装方法参照Vmware帮助文档),USB串口,minicom终端。(minicom经常打不开ttyUSB0设备,我的解决方法是,打不开时就将USB串口移除,运行minicom,然后再接上USB串口,此时运行minicom一般都能打开设备)
软件准备:
到http://qt.nokia.com/downloads-cn下载最新版的软件包,当前是:
用于 Linux/X11 32位 的 Qt Creator 1.3.1 二进制软件包qt-creator-linux-x86-opensource-1.3.1.bin(http://qt.nokia.com/downloads/qt-creator-binary-for-linux-x11-32-bit)
用于嵌入式 Linux 的 Qt 库 4.6.2包qt-everywhere-opensource-src-4.6.2.tar.gz(http://qt.nokia.com/downloads/embedded-linux-cpp)
到http://hi.baidu.com/jiyeqian/blog/item/f46d26a2ff3f7da6caefd0d6.html下载arm920t-eabi.tgz(即arm-linux-gcc-4.1.2)(http://qtextended.org/downloads/toolchains/arm920t-eabi.tgz)
到http://www.arm9.net/download.asp下载Root_Qtopia,我用的是友善光盘里的root_qtopia-20100108.tar.gz(http://www.arm123.com.cn/linux/root_qtopia-20100108.tar.gz)
下载tslib1.4,这个忘了在哪下载的了,网上有很多,有些不能用,大家自己找个能用的吧。
将 qt-everywhere-opensource-src-4.6.2.tar.gz 压缩包解压为3份,分别编译 PC ,嵌入式 x86 和 arm 三个版本。
我在root目录下建立tmp文件夹,将qt-everywhere-opensource-src-4.6.2.tar.gz直接解压后复制2分,分别命名为pc、x86、arm。
1. 编译 PC 版:
进入pc目录
#./configure
# gmake
# gmake install
安装过程比较长,没有碰到过错误。
2. 编译嵌入式x86版:
进入x86目录
# ./configure -embedded x86 -qt-gfx-qvfb -qt-kbd-qvfb -qt-mouse-qvfb
# gmake
# gmake install
安装过程比较长,没有碰到过错误。
编译安装PC版中的 qvfb:
进入pc/tools/qvfb/目录
#make
编译完毕,将pc/bin目录下的qvfb文件复制到/usr/local/Trolltech/QtEmbedded-4.6.2/bin目录。
3. 编译嵌入式arm版(需要 arm-linux-gcc 的支持):
使用友善自带的ARM-Linux GCC 4.3.2编译完了,程序移植到开发板上后,出现Segmentation Fault错误,按原文,使用4.1.2正常。
直接将arm920t-eabi.tgz解压缩到根目录,不可以像文章中说的那样“我把它放在:/usr/local/arm/4.1.2/ ”,最起码我放过去后出错了。
把编译器路径加入系统环境变量,运行命令:
#gedit /root/.bashrc
编辑/root/.bashrc文件,在最后一行加上 export PATH=/opt/toolchains/arm920t-eabi/bin:$PATH
编译tslib对触摸屏支持:
下载,tslib1.4.tar.gz,解压后:
# ./configure --prefix=/usr/local/tslib/ --host=arm-linux ac_cv_func_malloc_0_nonnull=yes
# make
# make install
我下载的包解压后没有configure文件,需要运行autogen.sh后才能生成。
设置环境变量,以便编译时找到相关的库:
# export CPLUS_INCLUDE_PATH=/opt/toolchains/arm920t-eabi/arm-angstrom-linux-gnueabi/include/c++:/opt/toolchains/arm920t-eabi/arm-angstrom-linux-gnueabi/include/c++/arm-none-linux-gnueabi
# export PATH=/opt/toolchains/arm920t-eabi/bin:$PATH
修改qt-everywhere-opensource-src-4.6.2/mkspecs/qws/linux-arm-g++/qmake.conf 文件(添加lts参数):
QMAKE_CC = arm-linux-gcc -lts
QMAKE_CXX = arm-linux-g++ -lts
QMAKE_LINK = arm-linux-g++ -lts
QMAKE_LINK_SHLIB = arm-linux-g++ -lts
这一步必须有,不然肯定出错。
配置:
必须加上“-prefix /usr/local/Trolltech/QtEmbedded-4.6.2-arm ”参数, 不然安装后不在QtEmbedded-4.6.2-arm文件夹下,而是覆盖了QtEmbedded-4.6.2。
# ./configure \
-prefix /usr/local/Trolltech/QtEmbedded-4.6.2-arm \
-opensource \
-confirm-license \
-release -shared \
-embedded arm \
-xplatform qws/linux-arm-g++ \
-depths 16,18,24 \
-fast \
-optimized-qmake \
-pch \
-qt-sql-sqlite \
-qt-libjpeg \
-qt-zlib \
-qt-libpng \
-qt-freetype \
-little-endian -host-little-endian \
-no-qt3support \
-no-libtiff -no-libmng \
-no-opengl \
-no-mmx -no-sse -no-sse2 \
-no-3dnow \
-no-openssl \
-no-webkit \
-no-qvfb \
-no-phonon \
-no-nis \
-no-opengl \
-no-cups \
-no-glib \
-no-xcursor -no-xfixes -no-xrandr -no-xrender \
-no-separate-debug-info \
-nomake examples -nomake tools -nomake docs \
-qt-mouse-tslib -I/usr/local/tslib/include -L/usr/local/tslib/lib
上面划掉的蓝色内容,可以不要的,这样编辑也不会出错(虚拟机搞坏了,不得已重装,配置参数时忘了干上面的工作了,结果发现没出错)。
关于配置参数,参照一下这篇文章吧,可以用configure -embedded –help查看。
http://www.cuteqt.com/blog/?p=582
如果你放弃配置,则使用命令:# gmake confclean
编译:# gmake
安装:# gmake install
安装完成后,在 /usr/local/Trolltech 目录中有三个文件夹:Qt-4.6.2、QtEmbedded-4.6.2、QtEmbedded-4.6.2-arm。
4、移植
我是通过NFS启动的系统,具体操作可以参照友善的手册,在http://www.arm9.net/download.asp有下载,在第5.5.3节通过NFS启动系统。
将Fedora12上 /usr/local/Trolltech/QtEmbedded-4.6.2-arm/lib 中的所有文件复制到/opt/FriendlyARM/mini2440/root_qtopia/usr/local/Trolltech/QtEmbedded-4.6.2-arm/lib目录中(对应目录复制,相当于复制到了开发板对应目录中),其实需要的时候可以裁剪,看原文吧。
将Fedora12上 /usr/local/tslib 中的库复制到/opt/FriendlyARM/mini2440/root_qtopia/usr/local中。即将/usr/local/tslib下的所有文件复制到/opt/FriendlyARM/mini2440/root_qtopia/usr/local文件夹下。
如果运行时还缺少其他的库,复制方法相同。也可以使用arm-angstrom-linux-gnueabi-readelf -a 程序名 | grep "Share",命令查看需要哪些共享库,一起复制过去。
为支持触摸屏,开机自动设置环境变量,在2440的 /etc/profile中追加:
export LD_LIBRARY_PATH=/usr/local/lib:$QTDIR/lib:$LD_LIBRARY_PATH
export TSLIB_ROOT=/usr/local/lib
export TSLIB_TSDEVICE=/dev/input/event0
export TSLIB_FBDEVICE=/dev/fb0
export TSLIB_PLUGINDIR=/usr/local/lib/ts
export TSLIB_CONSOLEDEVICE=none
export TSLIB_CONFFILE=/usr/local/etc/ts.conf
export POINTERCAL_FILE=/etc/pointercal
export TSLIB_CALIBFILE=/etc/pointercal
export QWS_MOUSE_PROTO=Tslib:/dev/input/event0
取消/usr/local/etc/ts.conf中的第一个注释:
# module_raw input (去掉#,并且该行顶格)
我编辑时没有“#”
启动Micro2440运行 /usr/local/bin/ts_calibrate 校正触摸屏。
到此Qt4.6.2的移植暂告一段落,移植还没有完,此时如果在开发板上运行Qt4.6.2-arm编译的程序,则会出现“relocation error: /usr/local/Trolltech/QtEmbedded-4.6.2-arm/lib/libQtGui.so.4: symbol powf, version GLIBCXX_3.4 not defined in file libstdc++.so.6 with link time reference”错误。
今天晚了,明天继续奉上……
Fedora12下搭建Qt Creator的ARM开发环境 并 移植Qt4.6.2到Micro2440(二)
管理提醒: 本帖被 kasim 执行加亮操作(2010-04-11)
Fedora12下搭建Qt Creator的ARM开发环境 并 移植Qt4.6.2到Micro2440(二)
继续……
5、安装Qt-creator-1.3.1
把下载的qt-creator-linux-x86-opensource-1.3.1.bin文件拷到一个目录(如前面的/root/tmp目录),进入目录:
设置qt-creator-linux-x86-opensource-1.3.1.bin文件为可执行
#chmod +x qt-creator-linux-x86-opensource-1.3.1.bin
安装:
# ./ qt-creator-linux-x86-opensource-1.3.1.bin
启动安装界面,默认一路Next即可。
*如果我们下载的是Qt的SDK(qt-sdk-linux-x86-opensource-2010.02.bin),这里可以选择安装Qt的开发环境,这样,在前面安装pc版Qt那步就可以省了,关键是可以省出很多时间的。
6、Qt-creator开发环境的配置
启动Qt-creator。
在Qt-creator菜单栏Tools—〉Options…打开Options窗口。
在Options界面左侧,点击Qt4—〉Qt Versions右侧显示Qt Versions设置界面。
在Qt Versions界面中点击那个蓝色的大“╋”号图标
在下方Version Name:文本框内输入Qt的版本名,可以随便填,能区分各个版本即可(如pc版取Qt4.6.2-pc、x86版取QtE4.6.2-x86、arm版取QtE4.6.2-arm)。
单击Qmake Location:右侧Browse…按钮,在弹出的“Select QMake Executable”窗口中找到对应版本的qmake程序(按照我们前面安转的,pc版路径:/usr/local/Trolltech/Qt-4.6.2/bin/qmake,x86版路径:/usr/local/Trolltech/QtEmbedded-4.6.2/bin/qmake,arm版路径:/usr/local/Trolltech/QtEmbedded-4.6.2-arm/bin/qmake),单击打开,回到Qt Versions界面。
回到Qt Versions界面,单击Debugging Helper:右侧Rebuild按钮,等待片刻,看到Debugging Helper:后出现一个绿色的“√”即可。
同理完成其他版本的添加。
添加完毕,单击OK按钮关闭Options窗口。
到此,Qt-creator配置完毕(我暂时就配置了这些)。
7、一个例子
从usr/local/Trolltech/QtEmbedded-4.6.2/demos下复制books例程到root/tmp文件夹下。
启动Qt-creator,File—〉Open File or Project…,打开root/tmp/books/books.pro。
这里我们分两部分,首先编译x86下的,并运行在qvfb下,再编译arm下的,移到开发板下运行。
7.1、x86下的编译与调试
在Qt-creator界面左侧点击Projects图标,打开工程设置界面。
从上往下,
在Edit Project Settings for Project books——〉Build Settings——〉Edit Build Configuration:单击Add,在下拉列表中选择Using Qt Version “QtE4.6.2-x86”弹出对话框单击Ok按钮,在Edit Build Configuration:下会出现蓝色的Make QtE4.6.3-x86 Release active.字符,单击激活QtE4.6.3-x86 Release。
在Run Settings——〉Edit run configuration:右侧单击Show Details按钮,在打开的下拉列表中Arguments:文本框中添加参数“-qws”。
设置完毕,点击Edit图标,回到编辑界面。
编译:在Build菜单下,先Clean Project “books”,然后Build Project “books”,在右下角Compile Output窗口能看到编译信息(按我们上面这样走来,到此编译不会出问题的)。
运行:
启动终端,# /usr/local/Trolltech/QtEmbedded-4.6.2/bin/qvfb -width 800 -height 480 &,启动Qvfb。
回到Qt-creator,Build——〉Run,运行程序。
切换我们的Qvfb窗口中,是不是看到Books运行的界面了。
调试:Debug——〉Start Debugging——〉Start Debugging,即可启动调试(请保证books路径中没有中文名,即不要把books工程放在了某个含有中文字符的文件夹下,不然无法启动调试)。
此时感觉如果前面编译选项Edit Project Settings for Project books——〉Build Settings——〉Edit Build Configuration:选择Debug项,则调试启动速度比Release时的要快很多。
7.2、arm编译并移植
编译:在Projects设置界面下,选择Using Qt Version “QtE4.6.2-arm”项,余下参数不变,build。
复制编译好的文件(也许还有images文件夹)到2440的NFS文件系统的某个目录下,我直接把books文件夹复制过去了(在Fedora12 文件系统下是/opt/FriendlyARM/mini2440/root_qtopia/home/plg文件夹下)。
运行及错误处理:
在minicom下面,ps一下,找到qpe进程对应的PID,比如1234,然后通过kill 1234杀死Qtopia。
进入books目录,执行./books –qws,此时就会出现前面讲到的“relocation error: /usr/local/Trolltech/QtEmbedded-4.6.2-arm/lib/libQtGui.so.4: symbol powf, version GLIBCXX_3.4 not defined in file libstdc++.so.6 with link time reference”错误。
我的解决办法是进入主机/opt/toolchains/arm920t-eabi/arm-angstrom-linux-gnueabi/lib目录下找到libstdc++.so.6链接的文件libstdc++.so.6.0.8(通过右键属性——〉基本,可以看到链接的文件),复制并重命名为libstdc++.so.6到/opt/FriendlyARM/mini2440/root_qtopia/lib文件夹下,之前别忘了将该文件夹下的libstdc++.so.6移到其它地方或重命名,如libstdc++.so.6.old。
*重命名其实是比较野蛮的方法,可以用ln命令的,参照下面这篇文章……
http://hi.baidu.com/a263238386/blog/item/362f01ce7b11a10a93457eae.html
然后再运行./books –qws,看问题是不是解决了!
这里有个新的问题还没解决,就是在开发版上运行时字非常小,留着以后处理吧。
OK!至此,Fedora12下搭建Qt Creator的ARM开发环境 并 移植Qt4.6.2到Micro2440算告一段落了,留下两个问题:字体非常小的问题、开发板上的远程调试,留待下次解决。
像风一样沐浴自由,等待木棉花开
离别多时,猛然看到他的文字,迎面而来的是清新和洒脱,放飞了自己,开阔了心境。从心里面为他高兴,又隐隐的疼惜自己,因为一个人还没有放下。
多伤感,多惆怅,多很多的是逃避。
有时候突然豪言壮语,突然壮志凌云,突然觉得一切都可能。但是有时又发现那些东西可有可无,无非是名利,是物质满足,是填补欲望,
没有真正的追求
package com.example.hoteltest;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.net.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.json.JSONArray;
import org.json.JSONObject;
import android.util.Log;
public class JSON {
/**
* 获取"数组形式"的JSON数据,
* 数据形式:[{"id":1,"name":"小猪"},{"id":2,"name":"小猫"}]
* @param path 网页路径
* @return 返回List
* @throws Exception
*/
public static List<Map<String, String>> getJSONArray(String path) throws Exception {
String json = null;
List<Map<String, String>> list = new ArrayList<Map<String, String>>();
Map<String, String> map = null;
URL url = new URL(path);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();// 利用HttpURLConnection对象,我们可以从网络中获取网页数据.
conn.setConnectTimeout(5 * 1000); // 单位是毫秒,设置超时时间为5秒
conn.setRequestMethod("GET"); // HttpURLConnection是通过HTTP协议请求path路径的,所以需要设置请求方式,可以不设置,因为默认为GET
if (conn.getResponseCode() == 200) {// 判断请求码是否是200码,否则失败
InputStream is = conn.getInputStream(); // 获取输入流
byte[] data = readStream(is); // 把输入流转换成字符数组
json = new String(data); // 把字符数组转换成字符串
//数据形式:[{"id":1,"name":"小猪","age":22},{"id":2,"name":"小猫","age":23}]
JSONArray jsonArray = new JSONArray(json); //数据直接为一个数组形式,所以可以直接 用android提供的框架JSONArray读取JSON数据,转换成Array
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject item = jsonArray.getJSONObject(i); //每条记录又由几个Object对象组成
int id = item.getInt("id"); // 获取对象对应的值
String name = item.getString("name");
map = new HashMap<String, String>(); // 存放到MAP里面
map.put("id", id + "");
map.put("name", name);
list.add(map);
}
}
// ***********测试数据******************
for (Map<String, String> list2 : list) {
String id = list2.get("id");
String name = list2.get("name");
Log.i("abc", "id:" + id + " | name:" + name);
}
return list;
}
/**
* 获取"对象形式"的JSON数据,
* 数据形式:{"total":2,"success":true,"arrayData":[{"id":1,"name":"小猪"},{"id":2,"name":"小猫"}]}
* @param path 网页路径
* @return 返回List
* @throws Exception
*/
public static List<Map<String, String>> getJSONObject(String path) throws Exception {
List<Map<String, String>> list = new ArrayList<Map<String, String>>();
Map<String, String> map = null;
URL url = new URL(path);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();// 利用HttpURLConnection对象,我们可以从网络中获取网页数据.
conn.setConnectTimeout(5 * 1000); // 单位是毫秒,设置超时时间为5秒
conn.setRequestMethod("GET"); // HttpURLConnection是通过HTTP协议请求path路径的,所以需要设置请求方式,可以不设置,因为默认为GET
if (conn.getResponseCode() == 200) {// 判断请求码是否是200码,否则失败
InputStream is = conn.getInputStream(); // 获取输入流
byte[] data = readStream(is); // 把输入流转换成字符数组
String json = new String(data); // 把字符数组转换成字符串
//数据形式:{"total":2,"success":true,"arrayData":[{"id":1,"name":"小猪"},{"id":2,"name":"小猫"}]}
JSONObject jsonObject=new JSONObject(json); //返回的数据形式是一个Object类型,所以可以直接转换成一个Object
int page=jsonObject.getInt("page");
String type=jsonObject.getString("type");
Log.i("abc", "type:" + type + " |page:" + page); //测试数据
JSONArray jsonArray = jsonObject.getJSONArray("hotels");//里面有一个数组数据,可以用getJSONArray获取数组
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject item = jsonArray.getJSONObject(i); // 得到每个对象
double distance=item.getDouble("distance");
String direction=item.getString("direction");
int star_rating=item.getInt("star_rating");
String name=item.getString("name");
double nightly_rate=item.getDouble("nightly_rate");
double promoted_nightly_rate=item.getDouble("promoted_nightly_rate");
double total_rate=item.getDouble("total_rate");
double longitude=item.getDouble("longitude");
String key=item.getString("key");
double promoted_total_rate=item.getDouble("promoted_total_rate");
String latitude=item.getString("latitude");
long master_id=item.getLong("master_id");
String thumbnail=item.getString("thumbnail");
String street_address=item.getString("street_address");
double review_score=item.getDouble("review_score");
map = new HashMap<String, String>(); // 存放到MAP里面
map.put("distance", distance + "");
map.put("direction", direction + "");
map.put("star_rating", star_rating + "");
map.put("name", name + "");
map.put("nightly_rate", nightly_rate + "");
map.put("promoted_nightly_rate", promoted_nightly_rate + "");
map.put("total_rate", total_rate + "");
map.put("key", key + "");
map.put("promoted_total_rate", promoted_total_rate + "");
map.put("latitude", latitude + "");
map.put("master_id", master_id + "");
map.put("thumbnail", thumbnail + "");
map.put("street_address", street_address + "");
map.put("review_score", review_score + "");
list.add(map);
}
}
// ***********测试数据******************
for (Map<String, String> list2 : list) {
String distance = list2.get("distance");
String direction = list2.get("direction");
String star_rating = list2.get("star_rating");
String name = list2.get("name");
String nightly_rate = list2.get("nightly_rate");
String promoted_nightly_rate = list2.get("promoted_nightly_rate");
String total_rate = list2.get("total_rate");
String key = list2.get("key");
String promoted_total_rate = list2.get("promoted_total_rate");
String latitude = list2.get("latitude");
String master_id = list2.get("master_id");
String thumbnail = list2.get("thumbnail");
String street_address = list2.get("street_address");
String review_score = list2.get("review_score");
System.out.println(distance);
System.out.println(direction);
System.out.println(star_rating);
System.out.println(name);
System.out.println(nightly_rate);
System.out.println(promoted_nightly_rate);
System.out.println(total_rate);
System.out.println(key);
System.out.println(promoted_total_rate);
System.out.println(latitude);
System.out.println(master_id);
System.out.println(thumbnail);
System.out.println(street_address);
System.out.println(review_score);
}
return list;
}
/**
* 获取类型复杂的JSON数据
*数据形式:
{"name":"小猪",
"age":23,
"content":{"questionsTotal":2,
"questions": [ { "question": "what's your name?", "answer": "小猪"},{"question": "what's your age", "answer": "23"}]
}
}
* @param path 网页路径
* @return 返回List
* @throws Exception
*/
public static List<Map<String, String>> getJSON(String path) throws Exception {
List<Map<String, String>> list = new ArrayList<Map<String, String>>();
Map<String, String> map = null;
URL url = new URL(path);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();// 利用HttpURLConnection对象,我们可以从网络中获取网页数据.
conn.setConnectTimeout(5 * 1000); // 单位是毫秒,设置超时时间为5秒
conn.setRequestMethod("GET"); // HttpURLConnection是通过HTTP协议请求path路径的,所以需要设置请求方式,可以不设置,因为默认为GET
if (conn.getResponseCode() == 200) {// 判断请求码是否是200码,否则失败
InputStream is = conn.getInputStream(); // 获取输入流
byte[] data = readStream(is); // 把输入流转换成字符数组
String json = new String(data); // 把字符数组转换成字符串
/*数据形式:
{"name":"小猪",
"age":23,
"content":{"questionsTotal":2,
"questions": [ { "question": "what's your name?", "answer": "小猪"},{"question": "what's your age", "answer": "23"}]
}
}
*/
JSONObject jsonObject=new JSONObject(json); //返回的数据形式是一个Object类型,所以可以直接转换成一个Object
String name=jsonObject.getString("name");
int age=jsonObject.getInt("age");
Log.i("abc", "name:" + name + " | age:" + age); //测试数据
JSONObject contentObject=jsonObject.getJSONObject("content"); //获取对象中的对象
String questionsTotal=contentObject.getString("questionsTotal"); //获取对象中的一个值
Log.i("abc", "questionsTotal:" + questionsTotal); //测试数据
JSONArray contentArray=contentObject.getJSONArray("questions"); //获取对象中的数组
for (int i = 0; i < contentArray.length(); i++) {
JSONObject item = contentArray.getJSONObject(i); // 得到每个对象
String question = item.getString("question"); // 获取对象对应的值
String answer = item.getString("answer");
map = new HashMap<String, String>(); // 存放到MAP里面
map.put("question", question);
map.put("answer", answer);
list.add(map);
}
}
// ***********测试数据******************
for (Map<String, String> list2 : list) {
String question = list2.get("question");
String answer = list2.get("answer");
Log.i("abc", "question:" + question + " | answer:" + answer);
}
return list;
}
/**
* 把输入流转换成字符数组
* @param inputStream 输入流
* @return 字符数组
* @throws Exception
*/
public static byte[] readStream(InputStream inputStream) throws Exception {
ByteArrayOutputStream bout = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len = 0;
while ((len = inputStream.read(buffer)) != -1) {
bout.write(buffer, 0, len);
}
bout.close();
inputStream.close();
return bout.toByteArray();
}
}
首先说一下Json数据的最基本的特点,Json数据是一系列的键值对的集合,和XML数据来比,Json数据的体积更加小,传输效率高,易解析,不过可读性不高;
因为这次要从服务器端得到Json数据,并且通过解析之后把解析后的数据显示在Android客户端中,首先部署服务器端代码(直接使用Jsp/Servlet):
构造的Json数据如下:
[{"name":"张三","address":"北京","age":20},{"name":"李四","address":"上海","age":30},{"name":"王五","address":"深圳","age":35}]
[一]服务器端(Person.java省略):
①:数据构造JsonService.java
- <span style="font-size: 16px; ">public class JsonService {
- public static List<Person> getListPerson() {
- List<Person> mLists = new ArrayList<Person>();
- mLists.add(new Person("张三", "北京", 20));
- mLists.add(new Person("李四", "上海", 30));
- mLists.add(new Person("王五", "深圳", 35));
- return mLists;
- }</span>
复制代码 ②:Servlet的代码(包括构造Json数据,没有使用Json数据转换方法)JsonServlet.java
- <span style="font-size: 16px; ">public void doGet(HttpServletRequest request, HttpServletResponse response)
- throws ServletException, IOException {
- response.setContentType("text/html");
- response.setCharacterEncoding("UTF-8");
- PrintWriter out = response.getWriter();
- List<Person> persons = JsonService.getListPerson();
- StringBuffer sb = new StringBuffer();
- sb.append('[');
- for (Person person : persons) {
- sb.append('{').append("\"name\":").append("\""+person.getName()+"\"").append(
- ",");
- sb.append("\"address\":").append("\""+person.getAddress()+"\"").append(",");
- sb.append("\"age\":").append(person.getAge());
- sb.append('}').append(",");
- }
- sb.deleteCharAt(sb.length() - 1);
- sb.append(']');
- out.write(new String(sb));
- out.flush();
- out.close();
- }</span>
复制代码- <span style="font-size: 16px; ">
- </span>
复制代码 ③:部署到Tomact 浏览器输入
http://localhost/JsonWeb/JsonServlet直接访问结果如下:
至此服务器端代码编码完成,下面进行客户端代码编写; (二)客户端(Person类,和展示数据的布局文件因为简单省去)
①:获取服务器端的Json数据并且解析的工具类JsonParse.java
必要的需要导入的包省去
- <span style="font-size:18px;">public class JsonParse {
- /**
- * 解析Json数据
- *
- * @param urlPath
- * @return mlists
- * @throws Exception
- */
- public static List<Person> getListPerson(String urlPath) throws Exception {
- List<Person> mlists = new ArrayList<Person>();
- byte[] data = readParse(urlPath);
- JSONArray array = new JSONArray(new String(data));
- for (int i = 0; i < array.length(); i++) {
- JSONObject item = array.getJSONObject(i);
- String name = item.getString("name");
- String address = item.getString("address");
- int age = item.getInt("age");
- mlists.add(new Person(name, address, age));
- }
- return mlists;
- }
- /**
- * 从指定的url中获取字节数组
- *
- * @param urlPath
- * @return 字节数组
- * @throws Exception
- */
- public static byte[] readParse(String urlPath) throws Exception {
- ByteArrayOutputStream outStream = new ByteArrayOutputStream();
- byte[] data = new byte[1024];
- int len = 0;
- URL url = new URL(urlPath);
- HttpURLConnection conn = (HttpURLConnection) url.openConnection();
- InputStream inStream = conn.getInputStream();
- while ((len = inStream.read(data)) != -1) {
- outStream.write(data, 0, len);
- }
- inStream.close();
- return outStream.toByteArray();
- }
- }</span>
复制代码②:主Activity类
- <pre name="code" class="java">public class MainActivity extends Activity {
- private Button mButton;
- private ListView mListView;
- //使用IP不能使用localhost或者127.0.0.1,因为android模拟器默认绑定这个IP,这里应该访问局域网IP
- private static final String urlPath = "http://10.16.31.207/JsonWeb/JsonServlet";
- private static final String TAG = "MainActivity";
- private List<Person> persons;
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- mButton = (Button) findViewById(R.id.button1);
- mListView = (ListView) findViewById(R.id.listView1);
- mButton.setOnClickListener(new MyOnClickListener());
- }
- private class MyOnClickListener implements OnClickListener {
- @Override
- public void onClick(View v) {
- try {
- // 得到Json解析成功之后数据
- persons = JsonParse.getListPerson(urlPath);
- List<HashMap<String, Object>> data = new ArrayList<HashMap<String, Object>>();
- for (int i = 0; i < persons.size(); i++) {
- HashMap<String, Object> map = new HashMap<String, Object>();
- map.put("name", persons.get(i).getName());
- map.put("address", persons.get(i).getAddress());
- map.put("age", persons.get(i).getAge());
- data.add(map);
- }
- //初始化适配器,并且绑定数据
- SimpleAdapter _Adapter = new SimpleAdapter(MainActivity.this,
- data, R.layout.listview_item, new String[] { "name",
- "address", "age" }, new int[] { R.id.textView1,
- R.id.textView2, R.id.textView3 });
- mListView.setAdapter(_Adapter);
- } catch (Exception e) {
- Toast.makeText(MainActivity.this, "解析失败", 2000).show();
- Log.i(TAG, e.toString());
- }
- }
- }
复制代码至此服务器端和客户端编码介绍,运行android应用结果截图:
Json数据解析服务器端加客户端代码.zip (75.08 KB, 下载次数: 1309) - 1
查看全部评分
-
摘要: 、利用HttpUrlConnection 1 /** 2 * 从指定的URL中获取数组 3 * @param urlPath 4 * @return 5 * @throws Exception 6 */ 7 public static String readParse(String urlPath) throws Excep...
阅读全文
例子1:android加载自己文件夹的图片,使用R类
main.xml文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<ImageView
android:id="@+id/iv1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:src="@drawable/longshuai" <!-- longshuai.png为图片的名称,记在资源文件里头,不用文件名后缀-->
/>
</LinearLayout>
注意:强调一下,资源文件的图片命名规则比较严格,由[a-z]和数字和“_”组成,而且不能数字开头,我就常犯傻,命名老是数字或者大写字母开头,这种错误——囧。。
我们要把longshuai.png导入到res中,最简单的方式就是直接找到这个文件夹,复制进去
之后右键更新,我们就可以在res中看到自己的图片了
不用写代码。。直接用自动生成的代码。。
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
效果如下:
2、加载本地图片(其实主要是SdCard中图片)
关于SdCard的使用,可以参见 http://longshuai2007.blog.163.com/blog/static/1420944142011611103950500/
xml文件同上面的是一样的,并不需要修改
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
ImageView image1 = (ImageView) findViewById(R.id.iv1); //获得ImageView对象
/*为什么图片一定要转化为 Bitmap格式的!! */
Bitmap bitmap = getLoacalBitmap("/sdcard/tubiao.jpg"); //从本地取图片(在cdcard中获取) //
image1 .setImageBitmap(bitmap); //设置Bitmap
}
/**
* 加载本地图片
* @param url
* @return
*/
public static Bitmap getLoacalBitmap(String url) {
try {
FileInputStream fis = new FileInputStream(url);
return BitmapFactory.decodeStream(fis); ///把流转化为Bitmap图片
} catch (FileNotFoundException e) {
e.printStackTrace();
return null;
}
}
显示效果如下:
3、获取网络上的图片
mian.xml文件和1中一样,并不需要修改!
代码:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
ImageView image1 = (ImageView) findViewById(R.id.iv1);
//从网上取图片
image1 .setImageBitmap(bitmap); //设置Bitmap
}
/**
* 从服务器取图片
* @param url
* @return
*/
public static Bitmap getHttpBitmap(String url) {
URL myFileUrl = null;
Bitmap bitmap = null;
try {
myFileUrl = new URL(url);
} catch (MalformedURLException e) {
e.printStackTrace();
}
try {
HttpURLConnection conn = (HttpURLConnection) myFileUrl.openConnection();
conn.setConnectTimeout(0);
conn.setDoInput(true);
conn.connect();
InputStream is = conn.getInputStream();
bitmap = BitmapFactory.decodeStream(is);
is.close();
} catch (IOException e) {
e.printStackTrace();
}
return bitmap;
}
注意:由于需要使用网络,所以 AndroidManfest.xml 文件需要添加使用网络权限!!!
<uses-permission android:name="android.permission.INTERNET" />
这也是我为什么一直错,而且一直找不到原因,它就是不显示图片,什么错误都没有,坑爹啊!!
ackage shenmixiaozhu;
import java.sql.Date;
public class TypeChange {
public TypeChange() {
}
//change the string type to the int type
public static int stringToInt(String intstr)
{
Integer integer;
integer = Integer.valueOf(intstr);
return integer.intValue();
}
//change int type to the string type
public static String intToString(int value)
{
Integer integer = new Integer(value);
return integer.toString();
}
//change the string type to the float type
public static float stringToFloat(String floatstr)
{
Float floatee;
floatee = Float.valueOf(floatstr);
return floatee.floatValue();
}
//change the float type to the string type
public static String floatToString(float value)
{
Float floatee = new Float(value);
return floatee.toString();
}
//change the string type to the sqlDate type
public static java.sql.Date stringToDate(String dateStr)
{
return java.sql.Date.valueOf(dateStr);
}
//change the sqlDate type to the string type
public static String dateToString(java.sql.Date datee)
{
return datee.toString();
}
public static void main(String[] args)
{
java.sql.Date day ;
day = TypeChange.stringToDate("2003-11-3");
String strday = TypeChange.dateToString(day);
System.out.println(strday);
}
}
android 完全退出应用程序
android android 退出应用程序, 单例模式管理Activity
引自:http://www.yoyong.com/archives/199
android 退出应用程序会调用android.os.Process.killProcess(android.os.Process.myPid())
或是System.exit(0),这只是针对第一个Activity(也就是入口的Activity)时生效。如果有A,B,C
三个Activity,而想在B 或C 中Activity 退出,调用上面的方法,往往会销毁当前的Activity 返回上
一个Activity。当然也可以逐个返回上一个Activity,直到跳转到入口的Activity,最后退出应用程
序。但这样比较麻烦,而且逐个返回的体验并不友好。
网上比较流行的方法是定义栈,写一个ExitApplication 类,利用单例模式管理Activity,在每个在
Activity 的onCreate()方法中调用ExitApplication.getInstance().addActivity(this)方法,在退
出时调用ExitApplication.getInstance().exit()方法,就可以完全退出应用程序了。
ExitApplication 类
代码如下:
view plaincopy to clipboardprint?
1 import java.util.LinkedList;
2 import java.util.List;
3
4 import android.app.Activity;
5 import android.app.Application;
6
7 public class ExitApplication extends Application {
9 private List<Activity> activityList=new LinkedList<Activity>();
10 private static ExitApplication instance;
11
12 private ExitApplication()
13 {
14 }
15 //单例模式中获取唯一的ExitApplication 实例
16 public static ExitApplication getInstance()
17 {
18 if(null == instance)
19 {
20 instance = new ExitApplication();
21 }
22 return instance;
23
24 }
25 //添加Activity 到容器中
26 public void addActivity(Activity activity)
27 {
28 activityList.add(activity);
29 }
30 //遍历所有Activity 并finish
31
32 public void exit()
33 {
34
35 for(Activity activity:activityList)
36 {
37 activity.finish();
38 }
39
40 System.exit(0);
41
42 }
43 }
下面的三个类IndexActivity, BActivity,CActivity 是简单的例子, 分别是
IndexActivity–>BActivity–>CActivity 的跳转顺序。在每个Activity 类中onCreate()方法中调
用ExitApplication.getInstance().addActivity(Activity activity)方法。在任何一个Activity 界面退
出应用程序时,只要调用ExitApplication.getInstance().exit()方法,就可以在任何一个Activity
中完全退出应用程序。
IndexActivity 类源代码:
view plaincopy to clipboardprint?
44 import android.app.Activity;
45 import android.content.Intent;
46 import android.os.Bundle;
47 import android.view.View;
48 import android.view.View.OnClickListener;
49 import android.widget.Button;
50
51 public class IndexActivity extends Activity {
52 /** Called when the activity is first created. */
53 @Override
54 public void onCreate(Bundle savedInstanceState) {
55 super.onCreate(savedInstanceState);
56 setContentView(R.layout.main);
57
58 Button next=(Button)findViewById(R.id.next_to_b);
59 next.setOnClickListener(nextClick);
60
61 Button exit=(Button)findViewById(R.id.exit_main);
62 exit.setOnClickListener(exitClick);
63 ExitApplication.getInstance().addActivity(this);
64
65 }
66
67 OnClickListener nextClick=new OnClickListener() {
68
69 @Override
70 public void onClick(View v) {
71 // TODO Auto-generated method stub
72
73 Intent intent=new Intent(IndexActivity.this,BActivity.class);
74 startActivity(intent);
75
76 }
77 };
78
79 OnClickListener exitClick=new OnClickListener() {
80
81 @Override
82 public void onClick(View v) {
83 // TODO Auto-generated method stub
84 ExitApplication.getInstance().exit();
85 }
86 };
87 }
BActivity 类源代码:
view plaincopy to clipboardprint?
88 import android.app.Activity;
89 import android.content.Intent;
90 import android.os.Bundle;
91 import android.view.View;
92 import android.view.View.OnClickListener;
93 import android.widget.Button;
94
95 public class BActivity extends Activity {
96
97 @Override
98 protected void onCreate(Bundle savedInstanceState) {
99 // TODO Auto-generated method stub
100 super.onCreate(savedInstanceState);
101
102 setContentView(R.layout.b);
103 Button next_to_c=(Button)findViewById(R.id.next_to_c);
104 next_to_c.setOnClickListener(next_to_cClick);
105
106 Button exit_b=(Button)findViewById(R.id.exit_b);
107 exit_b.setOnClickListener(exitClick);
108 ExitApplication.getInstance().addActivity(this);
109
110 }
111
112 OnClickListener next_to_cClick=new OnClickListener() {
113
114 @Override
115 public void onClick(View v) {
116 // TODO Auto-generated method stub
117
118 Intent intent=new Intent(BActivity.this,CActivity.class);
119 startActivity(intent);
120
121 }
122 };
123
124 OnClickListener exitClick=new OnClickListener() {
125
126 @Override
127 public void onClick(View v) {
128 // TODO Auto-generated method stub
129 ExitApplication.getInstance().exit();
130 }
131 };
132 }
CActivity 类源代码:
view plaincopy to clipboardprint?
133 import android.app.Activity;
134 import android.os.Bundle;
135 import android.view.View;
136 import android.view.View.OnClickListener;
137 import android.widget.Button;
138
139 public class CActivity extends Activity{
140
141 @Override
142 protected void onCreate(Bundle savedInstanceState) {
143 // TODO Auto-generated method stub
144 super.onCreate(savedInstanceState);
145
146 setContentView(R.layout.c);
147
148 Button exit_c=(Button)findViewById(R.id.exit_c);
149 exit_c.setOnClickListener(exitClick);
150 ExitApplication.getInstance().addActivity(this);
151
152 }
153
154 OnClickListener exitClick=new OnClickListener() {
155
156 @Override
157 public void onClick(View v) {
158 // TODO Auto-generated method stub
159 ExitApplication.getInstance().exit();
160 //如果只是调用以下其中的一个方法,并不会完全退出应用
161 //android.os.Process.killProcess(android.os.Process.myPid());
162 //System.exit(0);
163 }
164 };
165
166 }
1、Listview简述
A view that shows items in a vertically scrolling list. The items come from theListAdapter
associated with this view.
简单来说就是,创建Listview,然后给数值就行了。
而这些数值来源有三种方式:ArrayAdapter、SimpleAdapter、SimpleCursorAdapter
第一种是最简单的一种Adapter,是字符串数值,只能在ListView显示出文本信息。
第二种是一种自定义的数据来源,要自定义布局方式,可以放置图片,按钮,文本之类的。
第三种数据来源于数据库。
本文为第一种方式,ArrayAdapter,其他两项的方法都差不多,主要是adapter不同。
2、使用ListView步骤
首先创建Listview组件,然后调用Listview.ArrayAdapter()方法,设置Adapter。
通过调用setOnItemClickListener
()接口方法,设置“点击”listview某一项的监听事件。
通过调用setOnItemLongClickListener
()接口方法,设置“长按”listview某一项的监听事件。
需要说明的是,当设置匿名内部类new OnItemClickListener()时,eclipse不会自动载入复写函数,要点击左边的错误提示,然后Add unimplemented methods,才能载入复写函数onItemClick()。
- mylistview.setOnItemClickListener(new OnItemClickListener() {
-
- @Override
- public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
- // TODO Auto-generated method stub
-
- }
- });
关于onItemClick方法,下面详细说说。(
以下是官方的说明,参数命名不同而已,类型都是一样的。arg0=parent,arg1=view,arg2=position,arg3=id)
public abstract void onItemClick(AdapterView<?> parent,View view, int position, long id)
Callback method to be invoked when an item in this AdapterView has been clicked.
Implementers can call getItemAtPosition(position) if they need to access the data associated with the selected item.
//当点击listview某一项时,这个回调方法就会被调用。
Parameters
parent | The AdapterView where the click happened. |
view | The view within the AdapterView that was clicked (this will be a view provided by the adapter) |
position | The position of the view in the adapter. |
id | The row id of the item that was clicked. |
主要说说最后三个参数,
view——————是你点击的Listview的某一项的内容,来源于adapter。如用((TextView)arg1).getText(),可以取出点击的这一项的内容,转为string类型。
position————是adapter的某一项,如点击了listview第2项,而第2项对应的是adapter的第2个数值,那此时position的值就为1了。
如对应adapter的第3个数值,那此时position的值就为2了。
id———————id的值为点击了Listview的哪一项对应的数值,点击了listview第2项,那id就等于1。
注:这些数值都是从0开始的。
- /*author:conowen
- * date:2012.2.26
- */
- package com.conowen.listview;
-
- import android.app.Activity;
- import android.os.Bundle;
- import android.view.View;
- import android.widget.AdapterView;
- import android.widget.AdapterView.OnItemClickListener;
- import android.widget.AdapterView.OnItemLongClickListener;
- import android.widget.ArrayAdapter;
- import android.widget.ListView;
- import android.widget.TextView;
- import android.widget.Toast;
-
- public class ListviewActivity extends Activity {
- /** Called when the activity is first created. */
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- ListView lv = (ListView) findViewById(R.id.lv);
- String[] data = { "windows", "linux", "ios", "android", "wp7",
- "Symbian" };// 定义adapter
- lv.setAdapter(new ArrayAdapter<String>(this,// 把adapter绑定到listview里面
- android.R.layout.simple_expandable_list_item_1, data));
- // 点击事件
- lv.setOnItemClickListener(new OnItemClickListener() {
-
- @Override
- public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,
- long arg3) {
- // TODO Auto-generated method stub
- Toast.makeText(ListviewActivity.this, "你点击的是第" + arg3 + "项",
- Toast.LENGTH_SHORT).show();
- // 取出所点击的那一项的id
-
- }
-
- });
- // 长按事件
- lv.setOnItemLongClickListener(new OnItemLongClickListener() {
-
- @Override
- public boolean onItemLongClick(AdapterView<?> arg0, View arg1,
- int arg2, long arg3) {
- // TODO Auto-generated method stub
- Toast.makeText(ListviewActivity.this,
- ((TextView) arg1).getText(), Toast.LENGTH_LONG).show();
- // 取出点击listview某一项的内容
- return false;
- }
-
- });
- }
- }
for(String s:v)
s是遍历后赋值的变量,v是要遍历的list。
可以通过以下语句进行测试:
List<String> v=new ArrayList();
v.add("one");
v.add("two");
for(String s:v){
System.out.println(s);
}
注意s要跟前面的类型匹配。
s表示的其实就是v中得任意一个元素,v可以是数组,也可以是集合,如list或set。这种语句叫做foreach语句。其实就是Iterator迭代器的简化,意思就是循环的从v中拿出一个元素s进行操作
2008-06-01 16:35:46| 分类: mysql |字号 订阅
1.response.setContentType("text/html;charset=gb2312");
在做servlet的时候,在doGet中已经设定了response.setContentType("text/html;charset=gb2312");
pw.println("姓名");
pw.println("性别");
pw.println("邮箱");
pw.println("地址");
pw.println("权限");
这些汉字的可以正确显示,但是从数据库中查询返回的汉字显示为乱码:
姓名 | 性别 | 邮箱 | 地址 | 权限 |
admin | 0 | admin@163.com | ???????? | 1 |
user1 | 0 | user1@163.com | ???????? | 5 |
user2 | 0 | user2@163.com | ???????? | 5 |
user3 | 0 | user3@163.com | ?????à?? | 3 |
user4 | 0 | user4@163.com | ???????¨ | 3 |
user5 | 0 | user5@163.com | ???????¨ | 5 |
user6 | 0 | user6@163.com | ???????¨ | 5 |
最近几天一直都在学JSP,我用的数据库是Mysql。在连接数据库的过程中,刚开始我只是简单的执行了查询命令,发现从数据库取出的中文数据全部显示成了乱码,查了一些资料之后,我先用了下面的一个转换函数,值得高兴的是,读出的中文显示正常:
将从Mysql数据库中得到的中文数据,通过以下转换函数 String trans(String chi)进行处理,即可正常显示中文:
String trans(String chi) {
String result = null;
byte temp[];
try {
temp = chi.getBytes("iso-8859-1");
result = new String(temp);
} catch(UnsupportedEncodingException e) {
System.out.println(e.toString());
}
return result;
}
但很快,我意识到这种方法只是治标不治本,因为在插入中文数据时,又没法在Mysql中正常显示中文。而真正治本的方法是,将Mysql的编码格式由默认的latin1改成gb2312.
改的步骤如下:
1. 设置Mysql的编码格式(注意是在创建数据库之前就要设置)
找到Mysql安装目录下的 myini文件,用记事本打开,找到以下两句:
[mysql]
default-character-set=latin1
--------------------------------------------------------------------------------------------------
[mysqld]
# The TCP/IP Port the MySQL Server will listen on
port=3306
#Path to installation directory. All paths are usually resolved relative to this.
basedir="C:/Program Files/MySQL/MySQL Server 5.0/"
#Path to the database root
datadir="C:/Program Files/MySQL/MySQL Server 5.0/Data/"
# The default character set that will be used when a new schema or table is
# created and no character set is defined
default-character-set=latin1
我们需要做的是将这两处的默认编码格式由“latin1”改成“gb2312”。
改好之后,重启Mysql 。
2. 在Mysql中开始创建数据库
用相关命令创建数据库,表等
注意: 在创建表时要加上一句 TYPE=MyISAM, default character set gb2312;
如以下示例:
create table student
-> (sno varchar(20),
-> sname varchar(10),
-> sex char(2),
-> age numeric(2),
-> dept varchar(20),
-> primary key(sno))
-> type=myisam,default character set gb2312;
3. 在Java文件或者JSP文件中连接数据库
在Java代码中:
str = "com.mysql.jdbc.Driver";
url="jdbc:mysql://localhost:3306/example?useUnicode=true&characterEncoding=gb2312";
user = "root";
password = "123456";
Class.forName(str).newInstance();
conn = DriverManager.getConnection(url,user,password);
在JSP中需要注意的有:
<%@page contentType="text/html"%>
<%@page pageEncoding="gb2312" %>
<%@ page import="java.sql.*,java.io.*" %>
gb2312">
OK,经过上述一些设置之后,JAVA连Mysql将不会再出现中文显示乱码!
在android中,有很多功能是不能放在onCreate或者onStart方法里面,因为这些功能相对
来说费时比较长,比如说下载一个文件,下载的过程比较长,但是如果写在Activity中,
那么这段时间Activity是完全没有响应的,那么就可以将这种处理大量数据或者耗时比较
长的东西放在一个单独的线程中来完成,即Activity是一个线程,而下载的是在另外一个
线程,那么这样就可以使得下载跟Activity之间互不影响,从而得到了良好的用户体验
这里有两种队列,一种是线程队列,就是用postXX方法或者removeCallbacks方法对线程对象的操作。另一种是消息队列,用sendMessage和handleMessage方法来对消息对象进行处理
handler采用的是一个消息队列的方式,每一个handler都有一个与之关联的消息队列,而且是先进先出的方式执行,即:每次加入一个handler,然后拿出来,对其进行处理,然后再拿出另一个,再进行处理
例子一:这个例子仅仅是对线程对象进行操作的测试
Java代码
- package org.hualang.handler;
-
- import android.app.Activity;
- import android.os.Bundle;
- import android.os.Handler;
- import android.view.View;
- import android.widget.Button;
-
- public class HandlerTest extends Activity {
-
- private Button mybutton1;
- private Button mybutton2;
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
-
- mybutton1 = (Button)findViewById(R.id.mybutton1);
- mybutton2 = (Button)findViewById(R.id.mybutton2);
-
- mybutton1.setOnClickListener(new Button.OnClickListener()
- {
-
- @Override
- public void onClick(View arg0) {
- /**
- * 调用Handler的post方法,将要执行的线程对象添加到
- * 线程队列中
- */
- handler.post(updateThread);
- }
-
- });
- mybutton2.setOnClickListener(new Button.OnClickListener()
- {
-
- @Override
- public void onClick(View v) {
- // TODO Auto-generated method stub
- handler.removeCallbacks(updateThread);
- }
-
- });
-
- }
- //创建Handler对象
- Handler handler = new Handler();
- /**
- * 将要执行的操作卸载写入线程对象的run()方法当中
- */
- Runnable updateThread = new Runnable()
- {
- public void run()
- {
- System.out.println("更新线程");
- //在run方法内部,执行postXX的方法,每隔3秒会执行一次
- handler.postDelayed(updateThread, 3000);
- }
- };
- }
运行结果如下:
程序解释:首先创建一个Handler对象,然后创建一个继承自Runnable接口的线程
程序首先点击按钮“开始”,于是会马上执行post方法,将执行的线程对象添加到线程队列中,这时会马上执行
Java代码
- public void run()
- {
- System.out.println("更新线程");
- //在run方法内部,执行postXX的方法,每隔3秒会执行一次
- handler.postDelayed(updateThread, 3000);
- }
然后,执行postDelayed方法,由于里面设置的间隔时间,所以每3秒会调价一个handler对象到线程队列中,并且一直执行,直到点击“结束”按钮,调用removeCallbacks方法将其从线程队列中移除
例子2:下面的例子将简单的对线程对象和消息对象进行处理
Java代码
- package org.hualang.handlertest2;
-
- import android.app.Activity;
- import android.os.Bundle;
- import android.os.Handler;
- import android.os.Message;
- import android.view.View;
- import android.widget.Button;
- import android.widget.ProgressBar;
-
- public class HandlerTest2 extends Activity {
- private ProgressBar bar = null;
- private Button start = null;
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- bar = (ProgressBar)findViewById(R.id.progress1);
- start = (Button)findViewById(R.id.start);
- start.setOnClickListener(new Button.OnClickListener()
- {
-
- @Override
- public void onClick(View v) {
- bar.setVisibility(View.VISIBLE);
- handler.post(handlerThread);
- }
-
- });
- }
- /**
- * 使用匿名内部类来复写hanlder当中的hanldrMessage方法
- * 这里的msg对象就是从线程部分发送过来的对象
- */
- Handler handler = new Handler()
- {
- public void handleMessage(Message msg)
- {
- bar.setProgress(msg.arg1);
- handler.post(handlerThread);
- }
- };
- //线程类,该类使用的是匿名内部类的方式进行声明
- Runnable handlerThread = new Runnable()
- {
- int i = 0;
- public void run()
- {
- System.out.println("开始线程");
- i = i + 10;
- /**
- * 得到一个消息对象,Message类是由android操作系统提供
- * obtainMessage方法用来得到Message对象
- */
- Message msg = handler.obtainMessage();
- /**
- * Message中有个成员变量,即msg独享的arg1参数
- * 将其值设置为i。用arg1或arg2这两个成员变量传递
- * 消息,优点是系统性能消耗较少
- */
- msg.arg1 = i;
- try {
- //当前线程休眠1秒
- Thread.sleep(5000);
- } catch (InterruptedException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- /**
- * 发送一个消息,用sendMessage是将msg加入到消息
- * 队列中。而post是将线程加入到线程队列中
- */
- handler.sendMessage(msg);
- if( i == 100)
- {
- /**
- * 如果i=100的时候,就将线程对象
- * 从handler当中移除
- */
- handler.removeCallbacks(handlerThread);
- bar.setVisibility(View.GONE);
- }
- }
- };
- }
main.xml
Xml代码
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- >
- <ProgressBar
- android:id="@+id/progress1"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:visibility="gone"
- style="?android:attr/progressBarStyleHorizontal"
- />
- <Button
- android:id="@+id/start"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:gravity="center"
- android:text="点击我"
- />
- </LinearLayout>
运行结果:
程序说明:
1、当点击按钮后,会执行按钮的onClick方法中的
Java代码
- bar.setVisibility(View.VISIBLE);
- handler.post(handlerThread);
将进度条显示出来,并且将线程对象加入到线程队列中
2、线程对象对先打印出一个“开始线程”,然后i的值增加10,然后从系统中获取一个Message对象
3、将i赋给Message对象的参数arg1
4、当前线程休眠5秒,然后通过sendMessage方法发送一个Message对象发送到消息队列中
5、然后再执行,通过handleMessage方法设置进度条的值,并且将其加入到进程队列中
Java代码
- Handler handler = new Handler()
- {
- public void handleMessage(Message msg)
- {
- bar.setProgress(msg.arg1);
- handler.post(handlerThread);
- }
- };
6、循环执行,直到i=100,进度条隐藏,并将线程对象从线程队列中取出
对于Handler来说,它和与它调用它的Activity是出于同一线程的,上一篇并没有调用线程
的start方法,而是直接执行的run方法。而启动一个线程是调用的start方法
上一篇博客里的对Handler的调用时通过Runnable接口来实现的,并且是通过run()方法来启动那个线程的,而且是Activity和 Handler是两个线程独立运行的,互补干扰,但是实际情况确实,Activity所在的线程和Handler的线程是同一个线程,下面进行一下实验
Java代码
- package org.hualang.handlertest3;
-
- import android.app.Activity;
- import android.os.Bundle;
- import android.os.Handler;
- import android.util.Log;
-
- public class HandlerTest3 extends Activity {
- private Handler handler = new Handler();
- private String TAG = "System.out";
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- handler.post(r);
- setContentView(R.layout.main);
- //Thread t = new Thread(r);
- //t.start();
-
- Log.d(TAG,"Activity id:"+Thread.currentThread().getId());
- Log.d(TAG,"Activity name:"+Thread.currentThread().getName());
-
- }
- Runnable r = new Runnable()
- {
- public void run()
- {
- Log.d(TAG,"Handler id:"+Thread.currentThread().getId());
- Log.d(TAG,"Handler name:"+Thread.currentThread().getName());
- try {
- Thread.sleep(5000);
- } catch (InterruptedException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- };
- }
运行结果:
证明是同一个线程的两个依据:
①Activity的id或name和Handler的id或name是同样的
②我设置了
handler.post(r);
setContentView(R.layout.main);
也就是,如果执行后马上显示文本信息,那么可以证明它们不在同一个线程,但是实际情况是要先执行了handler后5秒,才显示文本信息,说明它们在同一线程
如果将代码改为
Java代码
- //handler.post(r);
- setContentView(R.layout.main);
- Thread t = new Thread(r);
- t.start();
再次执行,运行结果如下,通过start启动线程,它们不在同一个线程中
----------------------------------------------------------------------------------------------------------------
Looper即循环的从队列当中取得消息的功能,如果在线程中使用Looper
那么,就会循环的从线程队列当中取得消息并处理,如果队列当中没有消息的话
,线程就进入了休眠状态
Looper很少自己创建,在Android中给出了HandlerThread类,并且具有循环取得并处理消息的功能
下面来实现这种Activity和Handler分别在两个线程中执行,实现真正的异步处理
Java代码
- package org.hualang.handlertest;
-
- import android.app.Activity;
- import android.os.Bundle;
- import android.os.Handler;
- import android.os.HandlerThread;
- import android.os.Looper;
- import android.os.Message;
- import android.util.Log;
-
- public class HandlerTest4 extends Activity {
- /** Called when the activity is first created. */
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- Log.d("System.out","Activity所在线程的id:"+Thread.currentThread().getId());
- /**
- * 生成一个HandlerThread对象,实现了使用Looper来处理消息队列的功能
- * 这个类由Android应用程序框架提供
- */
- HandlerThread handlerThread = new HandlerThread("handlerThread");
- handlerThread.start();
- MyHandler handler = new MyHandler(handlerThread.getLooper());
- Message msg = handler.obtainMessage();
- /**
- * 将Message对象发送到目标对象
- * 所谓的目标对象,就是生成该msg对象的handler对象
- */
- msg.sendToTarget();
- }
- class MyHandler extends Handler
- {
- public MyHandler()
- {
- }
- public MyHandler(Looper looper)
- {
- super(looper);
- }
- public void handleMessage(Message msg)
- {
- Log.d("System.out", "handler所在线程的id:"+Thread.currentThread().getId());
- }
- }
- }
运行结果:
可以看到,Activity和Handler是在两个不同的线程中执行的,这样就是实现了真正的异步处理
1、首先创建一个HandlerThread对象,这个HandlerThread类实现了循环的取得消息并处理
2、用start方法启动一个新线程
3、创建MyHandler类,里面传递的参数即Looper方法所获得的可以循环在队列中取得的消息
4、MyHandler类调用的是带参数Looper的构造方法,并且实现了handlerMessage方法
5、获取一个Message对象
6、将这个对象发送到生成该msg对象的handler对象,从而执行了handleMessage方法
-----------------------------------------------------------------------------------------------------
最后,将说一下Message里传送的数据的使用,这里的msg对象可以使用arg1,arg2或者obj
arg1 and arg2 are lower-cost alternatives to using setData()
if you only need to store a few integer values. 也就是相对于setData()方法,如果你仅仅保存一些简单的整形数的话,arg1,arg2对资源的要求较低,而setData()方法一般用于传递 大量数据的时候会用到
如果是msg.obj,那么可以这样用
msg.obj = "Welcome to china";
然后在handleMessage()方法中用
String str = (String)msg.obj;来获得传递的值
如果使用getData()方法的话,需要用到Bundle对象来传递,下面用个例子来说明
Java代码
- Bundle b = new Bundle();
- b.putInt("age", 22);
- b.putString("name", "loulijun");
- msg.setData(b);
- msg.sendToTarget();
上面的代码用来设置要传递的数据
下面的代码用来获取Bundle传递过来的数据并且用Toast来显示
Java代码
- Bundle b = msg.getData();
- int age = b.getInt("age");
- String name = b.getString("name");
- Toast toast = Toast.makeText(getApplicationContext(), "age="+age+"name="+name, Toast.LENGTH_LONG);
- toast.show();
package org.hualang.handlertest;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
import android.util.Log;
import android.widget.Toast;
public class HandlerTest4 extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Log.d("System.out","Activity所在线程的id:"+Thread.currentThread().getId());
/**
* 生成一个HandlerThread对象,实现了使用Looper来处理消息队列的功能
* 这个类由Android应用程序框架提供
*/
HandlerThread handlerThread = new HandlerThread("handlerThread");
/**
* 使用HandlerThread的getLooper()方法之前,必须先调用该类的start()方法,否则是个null,会报错
*/
handlerThread.start();
MyHandler handler = new MyHandler(handlerThread.getLooper());
Message msg = handler.obtainMessage();
/**
* 将Message对象发送到目标对象
* 所谓的目标对象,就是生成该msg对象的handler对象
*/
//msg.obj = "Hello world";
Bundle b = new Bundle();
b.putInt("age", 22);
b.putString("name", "loulijun");
msg.setData(b);
msg.sendToTarget();
}
class MyHandler extends Handler
{
public MyHandler()
{
}
public MyHandler(Looper looper)
{
super(looper);
}
public void handleMessage(Message msg)
{
//String str = (String)msg.obj
Bundle b = msg.getData();
int age = b.getInt("age");
String name = b.getString("name");
Toast toast = Toast.makeText(getApplicationContext(), "age="+age+"name="+name, Toast.LENGTH_LONG);
toast.show();
Log.d("System.out", "handler所在线程的id:"+Thread.currentThread().getId());
}
}
}
运行结果:
创建HttpServlet的步骤
0人收藏此文章, 我要收藏 发表于3年前(2009-05-31 15:58) , 已有
955次阅读 ,共
0个评论
创建用户自己的HttpServlet类。通常涉及下列4个步骤
- 扩展HttpServlet抽象类
- 覆盖HttpServlet的部分方法,例如覆盖doGet()和doPost()方法
- 获取HTTP请求信息。例如通过HttpServletRequest对象来检索HTML表单所提交的数据或URL上的查询字符串。无论是 HTML表单数据还是URL上的查询字符串,在HttpServletRequest对象中都以参数名/参数值的形式存放,可以通过以下方法检索参数信 息:
- getParameterNames(): 返回一个Enumeration对象。它包含了所有的参数名信息
- getParameter(String name): 返回参数名name对应的参数值
- getParamaterValues(): 返回一个Enumeration对象,它包含了所有的参数值信息
4.生成HTTP响应结果。通过HttpServletResponse对象可以生成响应结果。HttpServletResponse对象有一个 getWriter()方法,该方法返回一个PrintWriter对象。使用PrintWriter的print()或println()方法可以向客 户端发送字符串数据流。
例子: 提供一个Servlet样例(HelloServlet.java)
package com.myServlet
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
public class HelloServlet extends HttpServlet // 第一步:扩展HttpServlet抽象类
{
// 第二步: 覆盖doGet()方法
public void doGet(HttpServletRequest request,HttpServletResponse response) throws IOException ,ServletException{
// 第三步: 获取HTTP请求中的参数信息
String clientName=request.getParameter("clientName");
if(clientName!=null)
clientName=new String(clientName.getBytes("ISO-8859-1"),"GB2312");
else
clientName="你好"
// 第四步
PrintWriter out;
String title="HelloServlet";
String heading1="This is output from HelloServlet by doGet:";
response.setContentType("text/html;charset=GB2312");
out=response.getWriter();
out.print("<HTML><HEAD><TITLE>"+title+"</TITLE>);
out.print("</HEAD><BODY>")
out.print(heading1);
out.println("<h1><P>"+clientName+":你好</h1>"+);
out.print("</BODY></HTML>");
out.close();
}
}
上述HelloServlet类扩展HttpServlet抽象类,覆盖了doGet方法。在重写的doGet方法中,通过 getParameter方法读取HTTP请求中的一个参数ClientName。在上述代码中,为了解决汉化问题,做了必要的转码工作。客户提交的查询 数据采用默认的ISO-8859-1编码,应该把它转换为中文编码GB2312:
// 字符编码转换
clientName=new String(clientName.getBytes(“ISO-8859-1”),"GB2312");
// 设置输出响应数据的字符编码
response.setContentType("text/html;charset=GB2312");
HellowServlet.class 的存放位置为:
<CATALINA_HOME>/webapps/helloapp/WEB-INF/classes/mypack/HelloServlet.class
在Web.xml中位HelloServlet类加上如下<servlet>和<servlet-mapping>元素:
<servlet>
<servlet-name>HelloServlet</servlet-name>
<servlet-class>mypackCounterServlet</servlet-class>
</servlet>
<servlet-mapping>HelloServlet</servlet-mapping>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
然后通过如下URL访问HelloServlet:
有些网友不知道怎么才能运行自己的JSP文件,我在这里简单介绍一下,给大家提供一点参考:
1. 下载并安装tomcat。下载地址:http://jakarta.apache.org/tomcat
2. 编写自己的JSP网页和Java对象。
3. 配置自己的Web应用。配置方法:
在TOMCAT_HOME/conf/server.xml文件中加入一行:
<Content path="/appName" docBase="webapps/appName" debug="0" reloadable="true"/>
其中,TOMCAT_HOME是tomcat的主目录,appName是你的Web应用的名称。
4. 将你的jsp文件、html文件、image文件拷贝到TOMCAT_HOME/webapps/appName目录下。
5. 编译你的java文件。
6. 将编译好的class文件拷贝到TOMCAT_HOME/webapps/WEB-INF/classes目录下。也可将class文件打包成jar文件放到TOMCAT_HOME/webapps/WEB-INF/lib目录下。
7. ALL IS OK! 你可以在你的浏览器上看到你的成果了:
http://localhost:8080/appName/youjsp.jsp
其中,appName是你配的Web应用名称,youjsp.jsp是你编写的jsp文件名。
1.输入密码:******
2.ues mysql;使用Mysql
3.show databases;显示数据库
4.use register;使用数据库名为register
5.show tables;显示register数据库中的表
6.describe user;对表user进行操作:
insert into user(username,password) values("xiaoyan","123456");插入数据
insert into user(username,password) values("ff","123456");插入数据
delete from user where username="xiaoyan";删除数据
update user set username="xiaoyan" where username="ff";更新数据
select * from user;查询数据
7.quit;推出
1、显示当前数据库服务器中的数据库列表:
mysql> SHOW DATABASES;
注意:mysql库里面有MYSQL的系统信息,我们改密码和新增用户,实际上就是用这个库进行操作。
2、显示数据库中的数据表:
mysql> USE 库名;
mysql> SHOW TABLES;
3、显示数据表的结构:
mysql> DESCRIBE 表名;
4、建立数据库:
mysql> CREATE DATABASE 库名;
5、建立数据表:
mysql> USE 库名;
mysql> CREATE TABLE 表名 (字段名 VARCHAR(20), 字段名 CHAR(1));
6、删除数据库:
mysql> DROP DATABASE 库名;
7、删除数据表:
mysql> DROP TABLE 表名;
8、将表中记录清空:
mysql> DELETE FROM 表名;
9、显示表中的记录:
mysql> SELECT * FROM 表名;
10、往表中插入记录:
mysql> INSERT INTO 表名 VALUES (”hyq”,”M”);
11、更新表中数据:
mysql-> UPDATE 表名 SET 字段名 1=’a',字段名2=’b’ WHERE 字段名3=’c';
12、用文本方式将数据装入数据表中:
mysql> LOAD DATA LOCAL INFILE “D:/mysql.txt” INTO TABLE 表名;
13、导入.sql文件命令:
mysql> USE 数据库名;
mysql> SOURCE d:/mysql.sql;
14、命令行修改root密码:
mysql> UPDATE mysql.user SET password=PASSWORD(’新密码’) WHERE User=’root’;
mysql> FLUSH PRIVILEGES;
15、显示use的数据库名:
mysql> SELECT DATABASE();
16、显示当前的user:
mysql> SELECT USER();
一、启动与退出
1、进入MySQL:启动MySQL Command Line Client(MySQL的DOS界面),直接输入安装时的密码即可。此时的提示符是:mysql>
2、退出MySQL:quit 或 exit
二、库操作
1、创建数据库
命令:create database
例如:建立一个名为xhkdb的数据库
mysql> create database xhkdb;
2、显示所有的数据库
命令:show databases (注意:最后有个s)
mysql> show databases;
3、删除数据库
命令:drop database
例如:删除名为 xhkdb的数据库
mysql> drop database xhkdb;
4、连接数据库
命令: use
例如:如果xhkdb数据库存在,尝试存取它:
mysql> use xhkdb;
屏幕提示:Database changed
5、当前选择(连接)的数据库
mysql> select database();
6、当前数据库包含的表信息:
mysql> show tables; (注意:最后有个s)
三、表操作,操作之前应连接某个数据库
1、建表
命令:create table ( [,.. ]);
mysql> CREATE TABLE `testa` (
-> `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
-> `name` varchar(20) DEFAULT NULL ,
-> PRIMARY KEY (`id`)
-> ) ENGINE=MyISAM AUTO_INCREMENT=65 DEFAULT CHARSET=utf8;
2、获取表结构
命令: desc 表名,或者show columns from 表名
mysql> DESCRIBE MyClass
mysql> desc MyClass;
mysql> show columns from MyClass;
3、删除表
命令:drop table
例如:删除表名为 MyClass 的表
mysql> drop table MyClass;
4、插入数据
命令:insert into [( [,.. ])] values ( 值1 )[, ( 值n )]
5、查询表中的数据
1)、查询所有行
mysql> select * from MyClass;
2)、查询前几行数据
mysql> select * from MyClass order by id limit 0,2;
6、删除表中数据
命令:delete from 表名 where 表达式
例如:删除表 MyClass中编号为1 的记录
mysql> delete from MyClass where id=1;
7、修改表中数据:update 表名 set 字段=新值,… where 条件
mysql> update MyClass set name=”Mary” where id=1;
8、在表中增加字段:
命令:alter table 表名 add字段 类型其他;
例如:在表MyClass中添加了一个字段passtest,类型为int(4),默认值为0
mysql> alter table MyClass add passtest int(4) default ”0”
9、更改表名:
命令:rename table 原表名 to 新表名;
例如:在表MyClass名字更改为YouClass
mysql> rename table MyClass to YouClass;
2011年05月9日
在Android中,如果需要改变控件默认的颜色,包括值的颜色,需要预先在strings.xml中设置,类似字符串,可以反复调用。Android中颜色可以使用drawable或是color来定义。
本例中strings.xml内容:
1 2 3 4 5 6 7 8 9 | <?xml version="1.0" encoding="utf-8"?> <resources> <string name="hello">Hello World, Main!</string> <string name="app_name">Color</string> <drawable name="red">#ff0000</drawable> <color name="gray">#999999</color> <color name="blue">#0000ff</color> <color name="background">#ffffff</color> </resources> |
上面定义了几个颜色值,下面是在布局文件中的调用,main.xml内容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" android:background="@color/background" > <TextView android:id="@+id/tv1" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/hello" android:textColor="@drawable/red" /> <TextView android:id="@+id/tv2" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/hello" android:textColor="@color/gray" /> <TextView android:id="@+id/tv3" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/hello" /> </LinearLayout> |
在Java程序中使用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | package com.pocketdigi.color; import android.app.Activity; import android.graphics.Color; import android.os.Bundle; import android.widget.TextView; public class Main extends Activity { /** Called when the activity is first created. */ TextView tv1,tv2,tv3; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); tv1=(TextView)findViewById(R.id.tv1); tv2=(TextView)findViewById(R.id.tv2); tv3=(TextView)findViewById(R.id.tv3); tv3.setTextColor(Color.BLUE);//直接使用android.graphics.Color的静态变量 tv2.setTextColor(this.getResources().getColor(R.color.blue));//使用预先设置的颜色值 } } |
这里以TextView为例,其他控件类似.
提示Android requires compiler compliance level 5.0 or 6.0. Found '1.7' instead. Please use Android Tools > Fix Project Properties.
解决方法:
1.项目右键 ->android tools->Fix Project
2.如果不可以,检查Project->Properties->Java Compiler
确认Compiler compliance level被设置为1.7,并且enable specific seetings.
经过这两步问题基本解决。
Eclipse中Compiler compliance level的含义说明
设置编译级别既 Eclipse compiler compliance level为较低版本,只是让编译器相信你的代码是兼容较低版本的,在编译时生成的bytecode(class)兼容较低版本。
这样设置与你写代码时引用的JDK是没关系的,也就是说你在写代码时仍可以引用较高版本的API.(这样就可能导 致错误)设置compiler compliance level为较低版本,这样的好处是当别人使用了较低版本的Jdk时也可以引用你写的编译后的代码。它可以保证编译后的class文件的版本一致性。但 是,如果你的代码里面(java source)里面调用了较高版本jdk的API.那么即使设置了compiler compliance level为较低版本,在较低版本的JDK上运行你的代码也会报错。
所以建议在写代码时引用的JDK,要跟你compiler compliance level设置的版本,是一致。不然会报上面的错误。
环境:主机Win7、VMware Workstation 6.5.3、虚拟机Ubuntu10.04。
一、桥接的基本原理
配置成桥接网络连接模式的虚拟机就当作主机所在以太网的一部分,虚拟系统和宿主机器的关系,就像连接在同一个Hub上的两台 电脑,可以像主机一样可以访问以太网中的所有共享资源和网络连接,可以直接共享主机网络的互联网接入线路访问互联网。主机与虚拟机之间,以及各虚拟机之间 都可以互访。对应虚拟机就被当成主机所在以太网上的一个独立物理机来看待,各虚拟机通过默认的VMnet0网卡与主机以太网连接,虚拟机间的虚拟网络为 VMnet0。这时你的虚拟机就像局域网中的一个独立的物理机一样。虚拟机中的操作系统可以PING通别的主机,反过来别的主机也可以PING虚拟机。想 让它们相互通讯,你就需要为虚拟系统配置IP地址和子网掩码,否则就无法通信。
二、配置步骤
1、首先判断VMware Bridge Protocol协议是否已经安装。在本地连接的属性中可以查看。如果是精简版的VMware就很可能没有安装。
如果没有安装,通过以下方法安装:本地连接-属性-安装-服务-添加-从磁盘安装,选择VMware安装目录下的netbridge.inf,确定 安装,过程如果提示vmnetBridge.dll和vmnetBridge.sys文件找不到,可以在下一级目录中找到,拷贝到安装目录根路径。
2、虚拟机中的Ubuntu10.04系统设置为bridged方式联网。虚拟机-设置-选择NetWork Adapter-网络连接-桥接。
3、网络设置。编辑-编辑虚拟网络-摘要。查看是否已经有一个默认的桥接网卡,如下面的VMnet0。如果是精简版的VMware,可能没有默认的 桥接方式,我之前就安装的7.01就是这种情况。如果没有桥接方式,建议重装一个完整版的虚拟机。自己选择桥接方式的话,可能出现“不能更改网络为桥接: 已没有未桥接的主机网络适配器”错误。
选择主机虚拟网络映射。其中因为是桥接方式联网,所以VMnet0 要设为物理网卡。
4、查看Win7主机本地连接的设置。
5、启动Ubuntu10.04虚拟机。设置IP,网关路由及DNS。选择 系统-管理-网络。
在弹出的网络连接对话框中,选择有线,编辑已经存在的网络连接Wired connection 1,选择IPv4设置,方法-自动,添加地址,输入IP、掩码、网关和DNS。IP地址最后一个字段可随意(不要相同),其余与本地连接相同。
至此,桥接方式连网设置完毕。重启网络。左上角网络连接图标,点击右键-关闭网络,然后重新启动网络。
6、尝试连网。
假设你已经正确编译和安装了Sqlite,写个测试程序来测试:
#include <stdlib.h>
#include <stdio.h>
#include "sqlite3.h"
int main(void)
{
sqlite3 *db=NULL;
char *zErrMsg = 0;
int rc;
rc=sqlite3_open("test1.db",&db);
if(rc)
{
fprintf(stderr,"Can't open database: %s\n",sqlite3_errmsg(db));
sqlite3_close(db);
exit(1);
}
else printf("open mydata successfully!\n");
sqlite3_close(db);
return 0;
}
用GCC来编译的时候总是会出现错误,编译的命令如下
gcc -static -o hello -lsqlite3 -L /usr/local/lib -I/usr/local/include hello.c
错误信息如下
/tmp/ccKeKpX9.o(.text+0x37): In function `main':
: undefined reference to `sqlite3_open'
/tmp/ccKeKpX9.o(.text+0x51): In function `main':
: undefined reference to `sqlite3_errmsg'
/tmp/ccKeKpX9.o(.text+0x73): In function `main':
: undefined reference to `sqlite3_close'
/tmp/ccKeKpX9.o(.text+0x9b): In function `main':
: undefined reference to `sqlite3_close'
collect2: ld returned 1 exit status
那么,恭喜你中招了。错误根本不在SQLITE也不在你的程序,而在GCC。Gcc的编译参数是有顺序的。正确的编译命令是:
gcc -o hello -L /usr/local/lib -I/usr/local/include -static hello.c -lsqlite3
说实话,这么的一个小问题困扰了我一天的时间!真是菜啊~~~~~~
QSqlQuery绑定查询 |
|
来源: ChinaUnix博客 日期: 2009.05.27 08:40 (共有条评论) 我要评论 |
|
Approaches to Binding Values Below we present the same example using each of the four different binding approaches, as well as one example of binding values to a stored procedure. Named binding using named placeholders: QSqlQuery query; query.prepare("INSERT INTO person (id, forename, surname) " "VALUES (:id, :forename, :surname)"); query.bindValue(":id", 1001); query.bindValue(":forename", "Bart"); query.bindValue(":surname", "Simpson"); query.exec(); Positional binding using named placeholders: QSqlQuery query; query.prepare("INSERT INTO person (id, forename, surname) " "VALUES (:id, :forename, :surname)"); query.bindValue(0, 1001); query.bindValue(1, "Bart"); query.bindValue(2, "Simpson"); query.exec(); Binding values using positional placeholders (version 1): QSqlQuery query; query.prepare("INSERT INTO person (id, forename, surname) " "VALUES (?, ?, ?)"); query.bindValue(0, 1001); query.bindValue(1, "Bart"); query.bindValue(2, "Simpson"); query.exec(); Binding values using positional placeholders (version 2): QSqlQuery query; query.prepare("INSERT INTO person (id, forename, surname) " "VALUES (?, ?, ?)"); query.addBindValue(1001); query.addBindValue("Bart"); query.addBindValue("Simpson"); query.exec(); Binding values to a stored procedure: This code calls a stored procedure called AsciiToInt(), passing it a character through its in parameter, and taking its result in the out parameter. QSqlQuery query; query.prepare("CALL AsciiToInt(?, ?)"); query.bindValue(0, "A"); query.bindValue(1, 0, QSql::Out); query.exec(); int i = query.boundValue(1).toInt(); // i is 65 Note that unbound parameters will retain their values. More information to see QT Help. 本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u2/86708/showart_1945836.html |
发表评论 查看评论(共有条评论) |
|
编译完成qt以后,发现qt的字体太小了
原因是qt的dpi计算错误,这样的情况会导致qt在不同的平台上大小不一
解决的方法就是设置好qt的dpi,
qt是根据显示器的物理长度或者宽度于分辨率的关系来计算dpi的, 所以我们设置export QWS_DISPLAY="LinuxFB:mmWidth95:0" export QWS_SIZE="480x272" 这样qt在所有的平台上显示的字体都一样大了 就好了,
还有其他的选项,可以参考http://doc.qt.nokia.com/4.6/qt-embedded-displaymanagement.html
IA32 : 32 bits Intel Architecture (32位带宽Intel构架)
IA64 : 64 bits Intel Architecture (64位带宽Intel构架)
i386 : Intel 386 ( 老的386机器,也泛指IA32体系的CPU)
i486 : Intel 486
i586 : Intel 586 ( Pentium ,K6 级别CPU )
i686 : Intel 686 ( Pentium II, Pentium III , Pentim 4, K7 级别CPU )
以上的86 也可以叫做 x86, 通称说 x86也是指 IA32构架CPU
x86 包含 i386 ,i386 仅仅是 x86 的一部分。
x86 这里的 x 本来就是一个未知数性质的,他可以是 3、4、5、6、7 。
x86 是 Intel 建立起来的 CPU 架构。
他的 8086、8088、80286、80386、80486、Pentium 、Pentium Pro 、Pentium MMX ,Pentium 2 ,还有后面的 P3、P4 、PD 、Core 全系列,Xeon 的 x86 系列。以及 AMD 的 Intel 架构兼容全系列.当然还有最近重新崛起的 VIA 的 C7 系列。
他们都是 x86 架构。
更多的 x86 代表的是 32 位的 Intel CPU 架构体系。
但其中分成很多代。i386 就是 80386 的那代 CPU 的标准,主要是支持 32 位的保护模式和实模式两种工作环境。这个功能很好很强大,一直沿用至今,而且系统对于这个功能是必须支持的。386 之后的 cpu 是完全兼容 i386 体系的。
i486 加入了新的一个功能,i586 (奔腾 1 代系列)又加入了新功能,i686 (奔腾 Pro 系列以后)又加入了新的功能体系。
i386 的软件可以运行在 i686 系统,但是 i686 的软件不能运行在之前的架构上。
旧 CPU 不能运行新软件主要是不能使用新的特性导致不能运行,但是旧的架构软件在新的架构上运行,仅仅是不能用新的功能体系,运行效率是没有减少的。
而且这个功能架构主要是 Linux 内核在使用。
只要看到 i 什么 86 ,基本都能用。
如果有 i686 ,CPU 只要不是 K6 系列,而是 Athlon 系列,最好选择 i686 ,但如果只有 i386 的,注意安装后看看你的内核是不是 i686 体系的,如果是,性能不受影响。
题外:
i786 是一个隐藏的新体系,听说只能用在 P4 以后的 Intel CPU 上面。但是很多软件没有针对这个架构编写,所以除非自己基于 i786 编译,不然网上没有 i786 的软件。
这里还要说 x86_64 体系,这个是 AMD 提出并且最先使用的 x86 新的架构体系。他把 32 位的 i686 架构体系,扩展为 64 位。
但是因为变动很x86 包含 i386 ,i386 仅仅是 x86 的一部分。
这里还要说 x86_64 体系,这个是 AMD 提出并且最先使用的 x86 新的架构体系。他把 32 位的 i686 架构体系,扩展为 64 位。
但是因为变动很大的原因,64 位的系统软件要兼容 32 位的软件,需要在内核里打开支持,并且安装 32 位的兼容库才行。其实如果你有源代码,32位系统的源代码基本上可以直接在 64 位的系统上面编译成为 64 位架构可运行的软件(新的技术还是用不上)。
同样 64 位的 CPU 兼容上一代的 i686 架构,i686 CPU 不支持 x86_64 的
在侠客岛电脑知识博客中分享了UltraEdit v18 简体中文版下载:详情点击此处
UltraEdit是一款收费软件,强烈建议您购买正版UltraEdit软件,享受优质的售后服务!如果你经济能力可以使用以下方法对UltraEdit破解激活:
1,UltraEdit注册机 :点击下载
2,断掉网络,安装完成后,进入UltraEdit软件,点击,注册,输入以下许可证ID和密码:
许可证:blog.itful.com
密码:www.finduu.com
会提示你进行脱机激活,点击脱机激活后,运行注册机,将用户码1和用户码2 分别输入注册机的user code位置
3,点击注册机中的Generate,会分别生成Authorization code (验证码)1和2,将其复制粘贴到注册界面的验证码处,同时再次输入以上许可证和密码。
4,点击激活,即可成功完成对UltraEdit的破解激活。
以上激活方法适合于UltraEdit v17.00.0 至今的所有版本.其他版本不能保住完全适用!
IBM/DW 发表于 11-27 08:10 11天前,
20回/4746阅, 最后回答: 3天前
【厦门】 12月22日(周六下午)OSC 源创会 我要报名»
本文由浅入深地介绍了如何使用 Java 类库,判断两台机器之间网络是否可达。本文介绍了 Java 中三种不同的网络可达的判断方法以及针对 IPv4 和 IPv6 混合网络的编程方法。同时也介绍了这些方法的使用场景和优缺点,基本涵盖了在实际应用中可能碰到的各种情况。
在网络编程中,有时我们需要判断两台机器之间的连通性,或者说是一台机器到另一台机器的网络可达性。在系统层面的测试中,我们常常用 Ping 命令来做验证。尽管 Java 提供了比较丰富的网络编程类库(包括在应用层的基于 URL 的网络资源读取,基于 TCP/IP 层的 Socket 编程,以及一些辅助的类库),但是没有直接提供类似 Ping 命令来测试网络连通性的方法。本文将介绍如何通过 Java 已有的 API,编程实现各种场景下两台机器之间的网络可达性判断。在下面的章节中,我们会使用 Java 网络编程的一些类库 java.net.InetAddress 和 java.net.Socket,通过例子解释如何模拟 Ping 命令。
一般情况下,我们仅仅需要判断从一台机器是否可以访问(Ping)到另一台机器,此时,可以简单的使用 Java 类库中 java.net.InetAddress 类来实现,这个类提供了两个方法探测远程机器是否可达
1 | boolean isReachable( int timeout) // 测试地址是否可达 |
2 | boolean isReachable(NetworkInterface netif, int ttl, int timeout) |
简单说来,上述方法就是通过远端机器的 IP 地址构造 InetAddress 对象,然后调用其 isReachable 方法,测试调用机器和远端机器的网络可达性。注意到远端机器可能有多个 IP 地址,因而可能要迭代的测试所有的情况。
01 | void isAddressAvailable(String ip){ |
03 | InetAddress address = InetAddress.getByName(ip); //ping this IP |
05 | if (address instanceof java.net.Inet4Address){ |
06 | System.out.println(ip + " is ipv4 address" ); |
08 | if (address instanceof java.net.Inet6Address){ |
09 | System.out.println(ip + " is ipv6 address" ); |
11 | System.out.println(ip + " is unrecongized" ); |
14 | if (address.isReachable( 5000 )){ |
15 | System.out.println( "SUCCESS - ping " + IP + " with no interface specified" ); |
17 | System.out.println( "FAILURE - ping " + IP + " with no interface specified" ); |
20 | System.out.println( "\n-------Trying different interfaces--------\n" ); |
22 | Enumeration<NetworkInterface> netInterfaces = |
23 | NetworkInterface.getNetworkInterfaces(); |
24 | while (netInterfaces.hasMoreElements()) { |
25 | NetworkInterface ni = netInterfaces.nextElement(); |
27 | "Checking interface, DisplayName:" + ni.getDisplayName() + ", Name:" + ni.getName()); |
28 | if (address.isReachable(ni, 0 , 5000 )){ |
29 | System.out.println( "SUCCESS - ping " + ip); |
31 | System.out.println( "FAILURE - ping " + ip); |
34 | Enumeration<InetAddress> ips = ni.getInetAddresses(); |
35 | while (ips.hasMoreElements()) { |
36 | System.out.println( "IP: " + ips.nextElement().getHostAddress()); |
38 | System.out.println( "-------------------------------------------" ); |
41 | System.out.println( "error occurs." ); |
程序输出:
01 | --------------START-------------- |
03 | 10.13 . 20.70 is ipv4 address |
04 | SUCCESS - ping 10.13 . 20.70 with no interface specified |
06 | -------Trying different interfaces-------- |
08 | Checking interface , DisplayName:MS TCP Loopback interface , Name:lo |
09 | FAILURE - ping 10.13 . 20.70 |
11 | ------------------------------------------- |
12 | Checking interface , DisplayName:Intel(R) Centrino(R) Advanced-N 6200 AGN - |
13 | Teefer2 Miniport, Name:eth0 |
14 | FAILURE - ping 10.13 . 20.70 |
16 | ------------------------------------------- |
17 | Checking interface , DisplayName:Intel(R) 82577LM Gigabit Network Connection - |
18 | Teefer2 Miniport, Name:eth1 |
19 | SUCCESS - ping 10.13 . 20.70 |
20 | ------------------------------------------- |
21 | Checking interface , DisplayName:WAN (PPP/SLIP) Interface, Name:ppp0 |
22 | SUCCESS - ping 10.13 . 20.70 |
24 | ------------------------------------------- |
26 | --------------END-------------- |
从上可以看出 isReachable 的用法,可以不指定任何接口来判断远端网络的可达性,但这不能区分出数据包是从那个网络接口发出去的 ( 如果本地有多个网络接口的话 );而高级版本的 isReachable 则可以指定从本地的哪个网络接口测试,这样可以准确的知道远端网络可以连通本地的哪个网络接口。
但是,Java 本身没有提供任何方法来判断本地的哪个 IP 地址可以连通远端网络,Java 网络编程接口也没有提供方法来访问 ICMP 协议数据包,因而通过 ICMP 的网络不可达数据包实现这一点也是不可能的 ( 当然可以用 JNI 来实现,但就和系统平台相关了 ), 此时可以考虑本文下一节提出的方法。
在某些情况下,我们可能要确定本地的哪个网络地址可以连通远程网络,以便远程网络可以回连到本地使用某些服务或发出某些通知。一个典型的应用场景 是,本地启动了文件传输服务 ( 如 FTP),需要将本地的某个 IP 地址发送到远端机器,以便远端机器可以通过该地址下载文件;或者远端机器提供某些服务,在某些事件发生时通知注册了获取这些事件的机器 ( 常见于系统管理领域 ),因而在注册时需要提供本地的某个可达 ( 从远端 ) 地址。
虽然我们可以用 InetAddress.isReachabl 方法判断出本地的哪个网络接口可连通远程玩过,但是由于单个网络接口是可以配置多个 IP 地址的,因而在此并不合适。我们可以使用 Socket 建立可能的 TCP 连接,进而判断某个本地 IP 地址是否可达远程网络。我们使用 java.net.Socket 类中的 connect 方法
1 | void connect(SocketAddress endpoint, int timeout) //使用Socket连接服务器,指定超时的时间 |
这种方法需要远程的某个端口,该端口可以是任何基于 TCP 协议的开放服务的端口(如一般都会开放的 ECHO 服务端口 7, Linux 的 SSH 服务端口 22 等)。实际上,建立的 TCP 连接被协议栈放置在连接队列,进而分发到真正处理数据的各个应用服务,由于 UDP 没有连接的过程,因而基于 UDP 的服务(如 SNMP)无法在此方法中应用。
具体过程是,枚举本地的每个网络地址,建立本地 Socket,在某个端口上尝试连接远程地址,如果可以连接上,则说明该本地地址可达远程网络。
01 | void printReachableIP(InetAddress remoteAddr, int port){ |
04 | Enumeration<NetworkInterface> netInterfaces; |
06 | netInterfaces = NetworkInterface.getNetworkInterfaces(); |
07 | while (netInterfaces.hasMoreElements()) { |
08 | NetworkInterface ni = netInterfaces.nextElement(); |
09 | Enumeration<InetAddress> localAddrs = ni.getInetAddresses(); |
10 | while (localAddrs.hasMoreElements()){ |
11 | InetAddress localAddr = localAddrs.nextElement(); |
12 | if (isReachable(localAddr, remoteAddr, port, 5000 )){ |
13 | retIP = localAddr.getHostAddress(); |
18 | } catch (SocketException e) { |
20 | "Error occurred while listing all the local network addresses." ); |
23 | System.out.println( "NULL reachable local IP is found!" ); |
25 | System.out.println( "Reachable local IP is found, it is " + retIP); |
29 | boolean isReachable(InetAddress localInetAddr, InetAddress remoteInetAddr, |
30 | int port, int timeout) { |
32 | booleanisReachable = false ; |
36 | // 端口号设置为 0 表示在本地挑选一个可用端口进行连接 |
37 | SocketAddress localSocketAddr = new InetSocketAddress(localInetAddr, 0 ); |
38 | socket.bind(localSocketAddr); |
39 | InetSocketAddress endpointSocketAddr = |
40 | new InetSocketAddress(remoteInetAddr, port); |
41 | socket.connect(endpointSocketAddr, timeout); |
42 | System.out.println( "SUCCESS - connection established! Local: " + |
43 | localInetAddr.getHostAddress() + " remote: " + |
44 | remoteInetAddr.getHostAddress() + " port" + port); |
46 | } catch (IOException e) { |
47 | System.out.println( "FAILRE - CAN not connect! Local: " + |
48 | localInetAddr.getHostAddress() + " remote: " + |
49 | remoteInetAddr.getHostAddress() + " port" + port); |
54 | } catch (IOException e) { |
55 | System.out.println( "Error occurred while closing socket.." ); |
运行结果
1 | --------------START-------------- |
3 | FAILRE - CAN not connect! Local: 127.0 . 0.1 remote: 10.8 . 1.50 port22 |
4 | FAILRE - CAN not connect! Local: 9.123 . 231.40 remote: 10.8 . 1.50 port22 |
5 | SUCCESS - connection established! Local: 10.0 . 50.189 remote: 10.8 . 1.50 port22 |
6 | Reachable local IP is found, it is 10.0 . 50.189 |
8 | --------------END-------------- |
当网络环境中存在 IPv4 和 IPv6,即机器既有 IPv4 地址,又有 IPv6 地址的时候,我们可以对程序进行一些优化,比如
- 由于 IPv4 和 IPv6 地址之间是无法互相访问的,因此仅需要判断 IPv4 地址之间和 IPv6 地址之间的可达性。
- 对于 IPv4 的换回地址可以不做判断,对于 IPv6 的 Linklocal 地址也可以跳过测试
- 根据实际的需要,我们可以优先考虑选择使用 IPv4 或者 IPv6,提高判断的效率
判断本地地址和远程地址是否同为 IPv4 或者 IPv6
2 | if (!((localInetAddr instanceofInet4Address) && (remoteInetAddr instanceofInet4Address) |
3 | || (localInetAddr instanceofInet6Address) && (remoteInetAddr instanceofInet6Address))){ |
4 | // 本地和远程不是同时是 IPv4 或者 IPv6,跳过这种情况,不作检测 |
跳过本地地址和 LinkLocal 地址
1 | if ( localAddr.isLoopbackAddress() || |
2 | localAddr.isAnyLocalAddress() || |
3 | localAddr.isLinkLocalAddress() ){ |
本文列举集中典型的场景,介绍了通过 Java 网络编程接口判断机器之间可达性的几种方式。在实际应用中,可以根据不同的需要选择相应的方法稍加修改即可。对于更加特殊的需求,还可以考虑通过 JNI 的方法直接调用系统 API 来实现,能提供更加强大和灵活的功能,这里就不再赘述了。
文章出处:IBM DW
Fedora12下搭建Qt Creator的ARM开发环境 并 移植Qt4.6.2到Micro2440(一)
参考:
环境:虚拟机Fedora12(建议安装Vmware Tools,详细安装方法参照Vmware帮助文档),USB串口,minicom终端。(minicom经常打不开ttyUSB0设备,我的解决方法是,打不开时就将USB串口移除,运行minicom,然后再接上USB串口,此时运行minicom一般都能打开设备)
软件准备:
到http://qt.nokia.com/downloads-cn下载最新版的软件包,当前是:
用于 Linux/X11 32位 的 Qt Creator 1.3.1 二进制软件包qt-creator-linux-x86-opensource-1.3.1.bin(http://qt.nokia.com/downloads/qt-creator-binary-for-linux-x11-32-bit)
用于嵌入式 Linux 的 Qt 库 4.6.2包qt-everywhere-opensource-src-4.6.2.tar.gz(http://qt.nokia.com/downloads/embedded-linux-cpp)
到http://hi.baidu.com/jiyeqian/blog/item/f46d26a2ff3f7da6caefd0d6.html下载arm920t-eabi.tgz(即arm-linux-gcc-4.1.2)(http://qtextended.org/downloads/toolchains/arm920t-eabi.tgz)
到http://www.arm9.net/download.asp下载Root_Qtopia,我用的是友善光盘里的root_qtopia-20100108.tar.gz(http://www.arm123.com.cn/linux/root_qtopia-20100108.tar.gz)
下载tslib1.4,这个忘了在哪下载的了,网上有很多,有些不能用,大家自己找个能用的吧。
将 qt-everywhere-opensource-src-4.6.2.tar.gz 压缩包解压为3份,分别编译 PC ,嵌入式 x86 和 arm 三个版本。
我在root目录下建立tmp文件夹,将qt-everywhere-opensource-src-4.6.2.tar.gz直接解压后复制2分,分别命名为pc、x86、arm。
1. 编译 PC 版:
进入pc目录
#./configure
# gmake
# gmake install
安装过程比较长,没有碰到过错误。
2. 编译嵌入式x86版:
进入x86目录
# ./configure -embedded x86 -qt-gfx-qvfb -qt-kbd-qvfb -qt-mouse-qvfb
# gmake
# gmake install
安装过程比较长,没有碰到过错误。
编译安装PC版中的 qvfb:
进入pc/tools/qvfb/目录
#make
编译完毕,将pc/bin目录下的qvfb文件复制到/usr/local/Trolltech/QtEmbedded-4.6.2/bin目录。
3. 编译嵌入式arm版(需要 arm-linux-gcc 的支持):
使用友善自带的ARM-Linux GCC 4.3.2编译完了,程序移植到开发板上后,出现Segmentation Fault错误,按原文,使用4.1.2正常。
直接将arm920t-eabi.tgz解压缩到根目录,不可以像文章中说的那样“我把它放在:/usr/local/arm/4.1.2/ ”,最起码我放过去后出错了。
把编译器路径加入系统环境变量,运行命令:
#gedit /root/.bashrc
编辑/root/.bashrc文件,在最后一行加上 export PATH=/opt/toolchains/arm920t-eabi/bin:$PATH
编译tslib对触摸屏支持:
下载,tslib1.4.tar.gz,解压后:
# ./configure --prefix=/usr/local/tslib/ --host=arm-linux ac_cv_func_malloc_0_nonnull=yes
# make
# make install
我下载的包解压后没有configure文件,需要运行autogen.sh后才能生成。
设置环境变量,以便编译时找到相关的库:
# export CPLUS_INCLUDE_PATH=/opt/toolchains/arm920t-eabi/arm-angstrom-linux-gnueabi/include/c++:/opt/toolchains/arm920t-eabi/arm-angstrom-linux-gnueabi/include/c++/arm-none-linux-gnueabi
# export PATH=/opt/toolchains/arm920t-eabi/bin:$PATH
修改qt-everywhere-opensource-src-4.6.2/mkspecs/qws/linux-arm-g++/qmake.conf 文件(添加lts参数):
QMAKE_CC = arm-linux-gcc -lts
QMAKE_CXX = arm-linux-g++ -lts
QMAKE_LINK = arm-linux-g++ -lts
QMAKE_LINK_SHLIB = arm-linux-g++ -lts
这一步必须有,不然肯定出错。
配置:
必须加上“-prefix /usr/local/Trolltech/QtEmbedded-4.6.2-arm ”参数, 不然安装后不在QtEmbedded-4.6.2-arm文件夹下,而是覆盖了QtEmbedded-4.6.2。
# ./configure \
-prefix /usr/local/Trolltech/QtEmbedded-4.6.2-arm \
-opensource \
-confirm-license \
-release -shared \
-embedded arm \
-xplatform qws/linux-arm-g++ \
-depths 16,18,24 \
-fast \
-optimized-qmake \
-pch \
-qt-sql-sqlite \
-qt-libjpeg \
-qt-zlib \
-qt-libpng \
-qt-freetype \
-little-endian -host-little-endian \
-no-qt3support \
-no-libtiff -no-libmng \
-no-opengl \
-no-mmx -no-sse -no-sse2 \
-no-3dnow \
-no-openssl \
-no-webkit \
-no-qvfb \
-no-phonon \
-no-nis \
-no-opengl \
-no-cups \
-no-glib \
-no-xcursor -no-xfixes -no-xrandr -no-xrender \
-no-separate-debug-info \
-nomake examples -nomake tools -nomake docs \
-qt-mouse-tslib -I/usr/local/tslib/include -L/usr/local/tslib/lib
上面划掉的蓝色内容,可以不要的,这样编辑也不会出错(虚拟机搞坏了,不得已重装,配置参数时忘了干上面的工作了,结果发现没出错)。
关于配置参数,参照一下这篇文章吧,可以用configure -embedded –help查看。
http://www.cuteqt.com/blog/?p=582
如果你放弃配置,则使用命令:# gmake confclean
编译:# gmake
安装:# gmake install
安装完成后,在 /usr/local/Trolltech 目录中有三个文件夹:Qt-4.6.2、QtEmbedded-4.6.2、QtEmbedded-4.6.2-arm。
4、移植
我是通过NFS启动的系统,具体操作可以参照友善的手册,在http://www.arm9.net/download.asp有下载,在第5.5.3节通过NFS启动系统。
将Fedora12上 /usr/local/Trolltech/QtEmbedded-4.6.2-arm/lib 中的所有文件复制到/opt/FriendlyARM/mini2440/root_qtopia/usr/local/Trolltech/QtEmbedded-4.6.2-arm/lib目录中(对应目录复制,相当于复制到了开发板对应目录中),其实需要的时候可以裁剪,看原文吧。
将Fedora12上 /usr/local/tslib 中的库复制到/opt/FriendlyARM/mini2440/root_qtopia/usr/local中。即将/usr/local/tslib下的所有文件复制到/opt/FriendlyARM/mini2440/root_qtopia/usr/local文件夹下。
如果运行时还缺少其他的库,复制方法相同。也可以使用arm-angstrom-linux-gnueabi-readelf -a 程序名 | grep "Share",命令查看需要哪些共享库,一起复制过去。
为支持触摸屏,开机自动设置环境变量,在2440的 /etc/profile中追加:
export LD_LIBRARY_PATH=/usr/local/lib:$QTDIR/lib:$LD_LIBRARY_PATH
export TSLIB_ROOT=/usr/local/lib
export TSLIB_TSDEVICE=/dev/input/event0
export TSLIB_FBDEVICE=/dev/fb0
export TSLIB_PLUGINDIR=/usr/local/lib/ts
export TSLIB_CONSOLEDEVICE=none
export TSLIB_CONFFILE=/usr/local/etc/ts.conf
export POINTERCAL_FILE=/etc/pointercal
export TSLIB_CALIBFILE=/etc/pointercal
export QWS_MOUSE_PROTO=Tslib:/dev/input/event0
取消/usr/local/etc/ts.conf中的第一个注释:
# module_raw input (去掉#,并且该行顶格)
我编辑时没有“#”
启动Micro2440运行 /usr/local/bin/ts_calibrate 校正触摸屏。
到此Qt4.6.2的移植暂告一段落,移植还没有完,此时如果在开发板上运行Qt4.6.2-arm编译的程序,则会出现“relocation error: /usr/local/Trolltech/QtEmbedded-4.6.2-arm/lib/libQtGui.so.4: symbol powf, version GLIBCXX_3.4 not defined in file libstdc++.so.6 with link time reference”错误。
今天晚了,明天继续奉上……
tslib-1.4.part1.rar (900 K) 下载次数:985 tslib-1.4.part2.rar
Fedora12下搭建Qt Creator的ARM开发环境 并 移植Qt4.6.2到Micro2440(二)
继续……
5、安装Qt-creator-1.3.1
把下载的qt-creator-linux-x86-opensource-1.3.1.bin文件拷到一个目录(如前面的/root/tmp目录),进入目录:
设置qt-creator-linux-x86-opensource-1.3.1.bin文件为可执行
#chmod +x qt-creator-linux-x86-opensource-1.3.1.bin
安装:
# ./ qt-creator-linux-x86-opensource-1.3.1.bin
启动安装界面,默认一路Next即可。
*如果我们下载的是Qt的SDK(qt-sdk-linux-x86-opensource-2010.02.bin),这里可以选择安装Qt的开发环境,这样,在前面安装pc版Qt那步就可以省了,关键是可以省出很多时间的。
6、Qt-creator开发环境的配置
启动Qt-creator。
在Qt-creator菜单栏Tools—〉Options…打开Options窗口。
在Options界面左侧,点击Qt4—〉Qt Versions右侧显示Qt Versions设置界面。
在Qt Versions界面中点击那个蓝色的大“╋”号图标
在下方Version Name:文本框内输入Qt的版本名,可以随便填,能区分各个版本即可(如pc版取Qt4.6.2-pc、x86版取QtE4.6.2-x86、arm版取QtE4.6.2-arm)。
单击Qmake Location:右侧Browse…按钮,在弹出的“Select QMake Executable”窗口中找到对应版本的qmake程序(按照我们前面安转的,pc版路径:/usr/local/Trolltech/Qt-4.6.2/bin/qmake,x86版路径:/usr/local/Trolltech/QtEmbedded-4.6.2/bin/qmake,arm版路径:/usr/local/Trolltech/QtEmbedded-4.6.2-arm/bin/qmake),单击打开,回到Qt Versions界面。
回到Qt Versions界面,单击Debugging Helper:右侧Rebuild按钮,等待片刻,看到Debugging Helper:后出现一个绿色的“√”即可。
同理完成其他版本的添加。
添加完毕,单击OK按钮关闭Options窗口。
到此,Qt-creator配置完毕(我暂时就配置了这些)。
7、一个例子
从usr/local/Trolltech/QtEmbedded-4.6.2/demos下复制books例程到root/tmp文件夹下。
启动Qt-creator,File—〉Open File or Project…,打开root/tmp/books/books.pro。
这里我们分两部分,首先编译x86下的,并运行在qvfb下,再编译arm下的,移到开发板下运行。
7.1、x86下的编译与调试
在Qt-creator界面左侧点击Projects图标,打开工程设置界面。
从上往下,
在Edit Project Settings for Project books——〉Build Settings——〉Edit Build Configuration:单击Add,在下拉列表中选择Using Qt Version “QtE4.6.2-x86”弹出对话框单击Ok按钮,在Edit Build Configuration:下会出现蓝色的Make QtE4.6.3-x86 Release active.字符,单击激活QtE4.6.3-x86 Release。
在Run Settings——〉Edit run configuration:右侧单击Show Details按钮,在打开的下拉列表中Arguments:文本框中添加参数“-qws”。
设置完毕,点击Edit图标,回到编辑界面。
编译:在Build菜单下,先Clean Project “books”,然后Build Project “books”,在右下角Compile Output窗口能看到编译信息(按我们上面这样走来,到此编译不会出问题的)。
运行:
启动终端,# /usr/local/Trolltech/QtEmbedded-4.6.2/bin/qvfb -width 800 -height 480 &,启动Qvfb。
回到Qt-creator,Build——〉Run,运行程序。
切换我们的Qvfb窗口中,是不是看到Books运行的界面了。
调试:Debug——〉Start Debugging——〉Start Debugging,即可启动调试(请保证books路径中没有中文名,即不要把books工程放在了某个含有中文字符的文件夹下,不然无法启动调试)。
此时感觉如果前面编译选项Edit Project Settings for Project books——〉Build Settings——〉Edit Build Configuration:选择Debug项,则调试启动速度比Release时的要快很多。
7.2、arm编译并移植
编译:在Projects设置界面下,选择Using Qt Version “QtE4.6.2-arm”项,余下参数不变,build。
复制编译好的文件(也许还有images文件夹)到2440的NFS文件系统的某个目录下,我直接把books文件夹复制过去了(在Fedora12 文件系统下是/opt/FriendlyARM/mini2440/root_qtopia/home/plg文件夹下)。
运行及错误处理:
在minicom下面,ps一下,找到qpe进程对应的PID,比如1234,然后通过kill 1234杀死Qtopia。
进入books目录,执行./books –qws,此时就会出现前面讲到的“relocation error: /usr/local/Trolltech/QtEmbedded-4.6.2-arm/lib/libQtGui.so.4: symbol powf, version GLIBCXX_3.4 not defined in file libstdc++.so.6 with link time reference”错误。
我的解决办法是进入主机/opt/toolchains/arm920t-eabi/arm-angstrom-linux-gnueabi/lib目录下找到libstdc++.so.6链接的文件libstdc++.so.6.0.8(通过右键属性——〉基本,可以看到链接的文件),复制并重命名为libstdc++.so.6到/opt/FriendlyARM/mini2440/root_qtopia/lib文件夹下,之前别忘了将该文件夹下的libstdc++.so.6移到其它地方或重命名,如libstdc++.so.6.old。
*重命名其实是比较野蛮的方法,可以用ln命令的,参照下面这篇文章……
http://hi.baidu.com/a263238386/blog/item/362f01ce7b11a10a93457eae.html
然后再运行./books –qws,看问题是不是解决了!
这里有个新的问题还没解决,就是在开发版上运行时字非常小,留着以后处理吧。
OK!至此,Fedora12下搭建Qt Creator的ARM开发环境 并 移植Qt4.6.2到Micro2440算告一段落了,留下两个问题:字体非常小的问题、开发板上的远程调试,留待下次解决。
Qt GUI API中使用Unicode类型的字符串类QString。使用Unicode的好处是可以支持更多的地区语言,ASCII是Uncode的子集。
QByteArray和QString的方法和属性相似,可以参考QString。另外有一些与QByteArray相关的非成员函数:
- //Related Non-Members
-
- //计算CRC16校验和
- quint16 qChecksum ( const char * data, uint len )
- //压缩data,并返回新的值,参数compressionLevel的值是0~9
- QByteArray qCompress ( const QByteArray & data, int compressionLevel = -1 )
- QByteArray qCompress ( const uchar * data, int nbytes, int compressionLevel = -1 )
- //解压缩
- QByteArray qUncompress ( const QByteArray & data )
- QByteArray qUncompress ( const uchar * data, int nbytes )
- //格式化字符串
- int qsnprintf ( char * str, size_t n, const char * fmt, ... )
- int qvsnprintf ( char * str, size_t n, const char * fmt, va_list ap )
- //比较字符串
- int qstrcmp ( const char * str1, const char * str2 )
- //复制字符串
- char * qstrcpy ( char * dst, const char * src )
- char * qstrncpy ( char * dst, const char * src, uint len )
- //分配空间复制字符串返回
- char * qstrdup ( const char * src )
- //忽略大小写的字符串比较
- int qstricmp ( const char * str1, const char * str2 )
- int qstrnicmp ( const char * str1, const char * str2, uint len )
- //返回字符串的长度
- uint qstrlen ( const char * str )
- uint qstrnlen ( const char * str, uint maxlen )
- //固定长度内的字符串比较
- int qstrncmp ( const char * str1, const char * str2, uint len )
- //相关QByteArray和const char *的运算符
- bool operator!= ( const QByteArray & a1, const QByteArray & a2 )
- bool operator!= ( const QByteArray & a1, const char * a2 )
- bool operator!= ( const char * a1, const QByteArray & a2 )
- const QByteArray operator+ ( const QByteArray & a1, const QByteArray & a2 )
- const QByteArray operator+ ( const QByteArray & a1, const char * a2 )
- const QByteArray operator+ ( const QByteArray & a1, char a2 )
- const QByteArray operator+ ( const char * a1, const QByteArray & a2 )
- const QByteArray operator+ ( char a1, const QByteArray & a2 )
- bool operator< ( const QByteArray & a1, const QByteArray & a2 )
- bool operator< ( const QByteArray & a1, const char * a2 )
- bool operator< ( const char * a1, const QByteArray & a2 )
- QDataStream & operator<< ( QDataStream & out, const QByteArray & ba )
- bool operator<= ( const QByteArray & a1, const QByteArray & a2 )
- bool operator<= ( const QByteArray & a1, const char * a2 )
- bool operator<= ( const char * a1, const QByteArray & a2 )
- bool operator== ( const QByteArray & a1, const QByteArray & a2 )
- bool operator== ( const QByteArray & a1, const char * a2 )
- bool operator== ( const char * a1, const QByteArray & a2 )
- bool operator> ( const QByteArray & a1, const QByteArray & a2 )
- bool operator> ( const QByteArray & a1, const char * a2 )
- bool operator> ( const char * a1, const QByteArray & a2 )
- bool operator>= ( const QByteArray & a1, const QByteArray & a2 )
- bool operator>= ( const QByteArray & a1, const char * a2 )
- bool operator>= ( const char * a1, const QByteArray & a2 )
- QDataStream & operator>> ( QDataStream & in, QByteArray & ba )
QByteArray与QString之间的转换:
示例:
QByteArray cstr("abcd");
QString s = cstr;
QByteArray cstr("abcd");
QString s;
s.prepend(cstr);
QString s("hello");
QByteArray cstr = s.toAscii();
QString s("hello");
QByteArray cstr = s.toLatin1();
QByteArray类同样不以'\0'为结尾:如
- QByteArray s;
- s.resize(5);
- s[0] = '1';
- s[1] = '2';
- s[2] = '3';
- s[3] = '\0';
- s[4] = 'a';
-
- cout << s << endl;
屏幕打印的是:“123 a”
运行程序的时候加-fn SIMHEI 看看,这个是黑体
例如./hello -qws -fn SIMHEI &
这样字体就大了!
Step 1:
首先设置宿主机上的环境变量(依你自己的情况而定):
export QTDIR=/usr/local/arm-linux/qt_toolchain/qt-2.3.7
export QPEDIR=/usr/local/arm-linux/qt_toolchain/qtopia-free-1.7.0
export LD_LIBRARY_PATH=/usr/local/arm-linux/qt_toolchain/qt-2.3.7/lib:$LD_LIBRARY_PATH
export LD_LIBRARY_PATH=/usr/local/arm-linux/qt_toolchain/qt-2.3.2/lib:$LD_LIBRARY_PATH
export TMAKEDIR=/usr/local/arm-linux/qt_toolchain/tmake-1.11
export TMAKEPATH=/usr/local/arm-linux/qt_toolchain/tmake-1.11/lib/qws/linux-arm-g++
export PATH=/usr/local/arm-linux/qt_toolchain/tmake-1.11/bin:$PATH
Step 2:
利用designer来设计界面,生成okform.ui;(注意:如果用qt-3.3的designer来设计界面,则以下步骤生成的okform.cpp和okform.h需要修改)
Step 3:
由okform.ui生成okform.h和okform.cpp:
#uic -o okform.h okform.ui
#uic -o okform.cpp -impl okform.h okform.ui
Step 4:
为工程编写一个主程序:
#include <qapplication.h>
#include "okform.h"
int main(int argc ,char **argv)
{
QApplication a(argc,argv);
okForm ok;
a.setMainWidget(&ok);
ok.show();
return a.exec();
}
Step 5:
修改tmake配置文件,以生成合适的Makefile:(只要第一次改好即可,不需每次都改)
在$TMAKEDIR/lib/qws/linux-arm-g++/tmake.conf文件里需要修改的地方如下:
TMAKE_LINK = arm-linux-g++
TMAKE_LINK_SHLIB = arm-linux-g++
TMAKE_LIBS_QT = -lqpe -lts
Step 6:
移除okform.ui这个文件,然后利用qmake 生成project文件:
#qmake -project
这样便生成了qt_test.pro(由当前目录名决定工程的名称)
也可以通过以下命令来生成:
#progen -t app.t -o qt_test.pro
Step 7:
用tmake来生成Makefile
#tmake -o Makefile qt_test.pro
Step 8:
#make
到此就生成了arm平台上的Qt 程序,通过NFS或其他手段拷贝到开发板上运行即可.
1.Linux链接概念
Linux链接分两种,一种被称为硬链接(Hard Link),另一种被称为符号链接(Symbolic Link)。默认情况下,ln命令产生硬链接。
【硬连接】
硬连接指通过索引节点来进行连接。在Linux的文件系统中,保存在磁盘分区中的文件不管是什么类型都给它分配一个编号,称为索 引节点号(Inode Index)。在Linux中,多个文件名指向同一索引节点是存在的。一般这种连接就是硬连接。硬连接的作用是允许一个文件拥有多个有效路径名,这样用户 就可以建立硬连接到重要文件,以防止“误删”的功能。其原因如上所述,因为对应该目录的索引节点有一个以上的连接。只删除一个连接并不影响索引节点本身和 其它的连接,只有当最后一个连接被删除后,文件的数据块及目录的连接才会被释放。也就是说,文件真正删除的条件是与之相关的所有硬连接文件均被删除。
【软连接】
另外一种连接称之为符号连接(Symbolic Link),也叫软连接。软链接文件有类似于Windows的快捷方式。它实际上是一个特殊的文件。在符号连接中,文件实际上是一个文本文件,其中包含的有另一文件的位置信息。
2.通过实验加深理解
[oracle@Linux]$ touch f1 #创建一个测试文件f1
[oracle@Linux]$ ln f1 f2 #创建f1的一个硬连接文件f2
[oracle@Linux]$ ln -s f1 f3 #创建f1的一个符号连接文件f3
[oracle@Linux]$ ls -li # -i参数显示文件的inode节点信息
total 0
9797648 -rw-r--r-- 2 oracle oinstall 0 Apr 21 08:11 f1
9797648 -rw-r--r-- 2 oracle oinstall 0 Apr 21 08:11 f2
9797649 lrwxrwxrwx 1 oracle oinstall 2 Apr 21 08:11 f3 -> f1
从上面的结果中可以看出,硬连接文件f2与原文件f1的inode节点相同,均为9797648,然而符号连接文件的inode节点不同。
[oracle@Linux]$ echo "I am f1 file" >>f1
[oracle@Linux]$ cat f1
I am f1 file
[oracle@Linux]$ cat f2
I am f1 file
[oracle@Linux]$ cat f3
I am f1 file
[oracle@Linux]$ rm -f f1
[oracle@Linux]$ cat f2
I am f1 file
[oracle@Linux]$ cat f3
cat: f3: No such file or directory
通过上面的测试可以看出:当删除原始文件f1后,硬连接f2不受影响,但是符号连接f1文件无效
3.总结
依此您可以做一些相关的测试,可以得到以下全部结论:
1).删除符号连接f3,对f1,f2无影响;
2).删除硬连接f2,对f1,f3也无影响;
3).删除原文件f1,对硬连接f2没有影响,导致符号连接f3失效;
4).同时删除原文件f1,硬连接f2,整个文件会真正的被删除。
这里简单说一下使用的区别
qt 2.x和qte 2.x都是使用tmake产生makefile的
qt 3.x和qte 3.x及以上都是使用qmake产生makefile的
对于qtopia,没有仔细检验,大致是这样的
qtopia 1.7.0及以下是使用tmake的
qtopia 1.7.0以上(不含qtopia 1.7.0)是使用qmake的
在qte3以前,还分qmake和tmake,它们都是用来生成makefile的,它们的区别是:
qmake一般用于生成本地makefile。
例如:hello目录下有main.cpp hello.cpp hello.h
cd hello
qmake -project // 将生成hello.pro
qmake hello.pro -o makefile // 将生成makefile
tmake既可用于生成本地的makefile,也可用于生成用于交叉编译的makefile,区别在于设置TMAKEPATH路径的不同,一个用于x86,一个用于arm或别的处理器。
例如:hello目录下有main.cpp hello.cpp hello.h
export TMAKE=...../tmake-*.** // tmake的安装目录
export PATH=$TMAKE/bin:$PATH
export TMAKEPATH=$TMAKE/lib/qws/linux-arm-g++
cd hello
qmake -project // 将生成hello.pro
tmake hellp.pro -o makefile // 将生成交叉编译的makefile
如果export TMAKEPATH=$TMAKE/lib/qws/linux-x86-g++
tmake hellp.pro -o makefile // 将生成本地的makefile
但是好像在qte3之后,qmake也可以生成交叉编译的makefile了,我装qte4的时候,弄了两个版本,一个x86,一个是arm的,里面对应 的qmake也就是一个对应x86,一个对应arm,要生成makefile的时候,只要到对应的文件夹下用对应的qmake就行了,连环境变量都不用 设。
、//////////////////////////////////////////////////////////////////////////////////////////////
网上摘抄,特此说明!!!
一级题目:
Qt Designer — 所见即所得的界面设计工具, 可以用拖拽的方式将控件排布在界面上,支持layout, 支持signal/slot编辑。 生成的文件保存为ui格式, ui是xml格式的普通文本文件, 默认编码为utf8, 所以界面上还可以直接写中文(但是不推荐这么做哦,还是应该用标准的Qt国际化的方法来翻译界面。).
Qt Assistant — 类似MSDN的文档查看工具, 支持html的子集(图片、超链、文本着色), 支持目录结构、关键字索引和全文搜索, 可以很方便的查找Qt的API帮助文档,所以是编程必备、使用率最高的工具。
qmake – 用于生成Makefile(编译的规则和命令行)的命令行工具。 它是Qt跨平台编译系统的基础。 它的主要特点是可以读取Qt本身的配置, 为程序生成与库一致的Makefile。
Qt Linguist — 被称为Qt语言家的Linguist是用于界面国际化的重要工具, 但其实它并不能帮你翻译,它的主要任务只是读取翻译文件、为翻译人员提供友好的翻译界面。 听起来这个功能好像不太够, 没错! Linguist必须要和其他工具一起用才能完成Qt国际化。 关于国际化可以参考bug写的Qt国际化和本地化。 另外,大家可能还不知道, Linguist工具从4.5开始可以支持Gettext的PO文件格式了哦~
tmake – 和qmake功能一致,是qmake的前身。从Qt3开始tmake全面被qmake替代。
qtdemo – Qt例子和演示程序的加载器, 也可以看作是Qt提供的一个有用的工具。 有了这个工具, 用户可以很方便的查看Qt提供的多姿多彩的例子程序,从中选择自己需要的, 不仅可以看到程序运行的情况,还可以查看源码和文档。
二级题目:
lupdate – Qt国际化的重要命令行工具之一, 它的功能是从源码文件或其他资源文件中提取需要翻译的字符串,并将之用正确的编码和格式存入ts文件中。 这个ts文件是xml格式的普通文本文件, 但不建议用普通的文本编辑工具来编辑, 最好的方法是用Linguist来处理这个文件。
lrelease – Qt国际化的重要命令行工具之一, 它负责将ts文件转化为程序使用的qm文件。 转化过程最大的变化是去掉了原始文件中所有的空白和未翻译的内容, 并将存储格式压缩, 所以qm文件是保留所有有效信息但占用硬盘最少的格式。
uic – UI Compiler, 顾名思义,这个命令行工具是用来编译ui文件的, 它能把ui文件转化为编译器可以识别的标准C++文件, 生成的文件是一个.h。 这个工具通常情况下不需要用户去手动调用, qmake会帮你管理ui文件和调用uic工具。 具体的可以参考笔者的另外一篇帖子 Qt4中ui文件的使用方法。
moc – Meta Object Compiler, 直译过来是元对象编译器, 简单的说这是个预编译工具, 用来生成一些与信号和槽相关的底层代码。 该工具处理带有Q_OBJECT宏的头文件, 生成形如moc_xxx.h, moc_xxx.cpp的C++代码,之后再与程序的代码一同编译。 同样,这个命令行工具也不需要用户手动调用, qmake会在适当的时候调用这个工具的。
三级题目:
后面的题目越来越难了哦~~
rcc – Resource Compiler资源文件编译工具。 Qt的资源系统是自己一套特别的设计, 工程中可以包含后缀为qrc的资源文件, 由rcc工具根据qrc的内容将相关的文件编译为二进制,并与源码编译在一起,保存在应用程序的二进制文件中。 这个命令行工具同样不需要手动调用,由qmake调用。
qconfig – QtEmbedded feature配置工具。 众所周知,嵌入式版本的Qt可以自己定义一个feature定义文件叫qconfig-xxx.h,里面定义一些预定义的宏, 通过这个文件可以在编译阶段去掉一些feature, 以减少Qt库的footprint。 这个qconfig工具就是用来编辑feature定义文件的。 具体的参考笔者的帖子简单Qt裁剪。
qt3to4 – 用于Qt3程序升级为Qt4程序的移植工具。 它的原理是根据xml文件里定义的一系列文本替换的规则去做文本替换, 所以…怎么说呢,这个工具的功能比较有限, 不可避免的需要很多人工干预才能解决编译和运行的错误。 故而笔者的建议还是重头写程序比较靠谱。
qvfb – 一般做嵌入式开发的用户对这个工具应该不陌生。 这是个有几分神奇色彩的模拟器, 它可以模拟framebuffer设备(尺寸、色深),还可以通过skin文件模拟硬件键盘的布局(包括特殊键值的按键), 是在x86环境下调试嵌入式程序必不可少的有效工具。 无怪乎minigui也比较无耻的偷窃了这个工具…实在是诱惑力太大了
四级题目:
qtconfig – X11系统下用于配置Qt环境的工具。 可以设定字体、Style、Palette、打印机等。 设定信息会保存在用户家目录,所以可以按不同用户的喜好来设定不同的值。
qcop – 嵌入式环境qtopia带的进程间通讯的工具, 用于进程间的通讯和进程间API的相互调用。
pixeltool – 类似放大镜的工具,可以看清鼠标滑过的每个像素。
findtr – 从源码提出翻译字串,保存为Linux的po格式。 po是Linux系统下国际化方法gettext使用的标准格式, 所以这个工具是为了和Linux本身的国际化方法兼容而提供的。
uic3 – Qt4中提供的处理Qt3 ui文件的工具,生成的代码是Qt4的代码,可以放在Qt4的工程里使用。 值得注意的是,uic3生成的代码有一部分会使用Qt3Support库的API, 不是纯的Qt4代码。
phonesim – Qtopia里带的奇妙工具, 用于调试手机环境。 可以模拟提供AT命令接口的modem设备。 有了这个工具就可以在桌面环境下调试应用和modem之间的交互逻辑, 简单的说Qtopia里像接打电话、收发短信、STK程序等功能都是靠这个工具来调试的。
makeqpf – Qt为了嵌入式环境的需要自创了一种字体格式叫qpf, 这个格式是个位图字体, 它把已经预渲染的文字直接保存成二进制内容, 使用的时候可以用内存映射加载, 从加载到绘制的过程不需要计算,所以速度非常快。 makeqpf工具就是用来创建qpf格式的字体的,它可以读取系统中的字体格式, 根据用户的设定生成特定字号规格的qpf文件供用户使用。
五级题目:
这些工具我也不熟。。就不多说了。。
lconvert – 4.5版本新引入的工具, 用于翻译文件之间的格式转换, 将ts格式转换为其他工具可读取的XLIFF格式。
qdbusxml2cpp – QtDBus XML编译器, 用于将xml格式的DBus远程调用的对象和函数API的描述文件翻译为C++代码。 这个工具创建的是个代码的框架,里面的API具体实现要用户自己来填充。
D-Bus Viewer — 可以用来查看D-Bus对象及其对外提供的API, 可以通过双击API的方式调用某个方法, 还可以注册信号, 这样所有发出的信号都会显示在窗体中。
IDC – ActiveQt模块提供的命令行工具,用于将Qt二进制转化为COM server。 该工具由qmake调用,不需要手工执行。
dumpcpp – ActiveQt模块的命令行工具, 可以为一个类型库创建C++的命名空间。
dumpdoc – ActiveQt模块的命令行工具,可以为COM对象创建Qt风格的文档。
testcon – ActiveQt模块的命令行工具, 全称为ActiveX Test Container, 也就是可以作为ActiveX控件的容器, 这样可以把控件安装到系统中再测试。 该工具会提供详细的事件和属性变化的log信息。
Qt Script Debugger — 用于调试Qt Script的工具,可以单步运行,查看输出等。 Qt文档里有很详细的一篇专门讲这个的,有兴趣的来看下: Qt Script Debugger Manual
摘要: lz安在ubuntu上安装好qtopia后,乐得屁颠屁颠的,一个礼拜工作终于看到成果了,常言道乐极生悲,果然是这样,关机时就有一种不祥的感觉,果然,再开机时发现ubuntu居然崩溃了,东流水,不回头,什么都没有了,关键是,我特别喜欢这个ubuntu,用了很久,感情深厚,然后就失落了一整天!  ...
阅读全文
一句话解决!
摘要: 安装 qtopia1.准备安装包 注意: qt-x11xx qt-emxx qtopiaxxx 版本之间要相互对应, http://www.360 doc.com/content/12/0601/10/10102389_215143511.shtml推荐你看看这位的qt总结2.解压tar -zxvf x...
阅读全文
安装 libX11-dev libXext-dev libXtst-dev
于是
yum install libXau-devel
接着执行
rpm -ivh libXext-devel-1.0.4-1.fc9.i386.rpm
最后,./configura果然,错误解决了。
最后我们来总结一下,要解决这个问题只需要几个库就可以了呢,
实际上只要两个:
yum install libXau-devel
执行完上面这条语句后,我在执行
yum install ibX11-devel
打印信息显示,该package已经安装
最后在安装
libXext-devel就可以了
centos中安装g++
是沒有作用的。
yum install gcc-c++
這行命令才能正確的安裝g++
小发现:在IE中使用margin:0 auto页面不能居中的问题
1、更改DOCTYPE为 xhtml 1.0 tranditional (html 4.01 下无效)
2、在块外边添加div,并对此div应用text-align:center
总结:IE6跟火狐的区别,IE的text-align:center能使其包含的块状元素和行内元素以及文本内容居中.
而在火狐下面text-align:center只能使其包含的行内元素和文本内容居中.
margin:0 auto能使块状元素居中,但不能使行内元素居中,这个在火狐和IE6下都是一样的.对于IE6以前版本的浏览器需要配合其父元素的text- align:center才能居中,您还为IE下使用margin:0 auto页面不能居中的问题头痛吗?Have a try ……
到目前为止接触了一些c语言编程的知识,这里对c语言实现页面的跳转稍微了归纳一下1
1:csp/eybuild
这是一个工具 c语言脚本开发的工具,适合嵌入式c语言web开发!它的出现使c语言脚本的编程就像php一样简单! 有兴趣可以去下一个自己玩一下,但是它使用起来有点繁琐,只能是小的网站才适用!
页面的跳动这里面是有函数可直接调用的,具体是什么函数,读者自己学的时候应该就会知道了!
2: cgic 函数库 封装了c语言的函数,使的函数调用更加的简单,而且在实现功能方面更加的面向功能!很大程度上简单化的c语言脚本编程,而且减小的c语言内存错误出现的概率!
它只是一个很小的函数库,一些头问价,库文件,组成,无需安装,使用起来非常简单,基本功能实现很容易,但是个人认为,一些复杂的功能实现起来与c语言直接编辑的程序要繁琐,而且就效率也要低,不过初学者或者不是c专家 要考虑代码的质量 是一个很困难的事情!
这里面页面的跳转也只是一句话的功夫!简单吧!想试试就去看看!
3:不借助这些函数库何工具 ,也不难哦,适才用了一个
其实就是一句话:如下
printf("<script>window.location.href='/login_err.html';</script>");//实现页面的自动跳转放在你想跳转的地方就行了!我行哦~~
4.还有几个类似的
printf("<script>\n");
printf("location.href=\"/cgi-bin/timeindex.cgi\"\n");
printf("</script>\n");
改http头,类似这句的功能cgiHeaderContentType("text/html");
在HTTP头部加上“Location”字段,并且应答码必须为3xx的重定向状态。
请参见
RFC2616的10.3和14.30这两个章节。 (要看的话给我留言qq 我发给你!)
在<body>中间输出
<meta http-equiv="Refresh" content="0;URL=./cgi-bin/cgictest.cgi">
post和get的区别
post 地址栏不会出现一大串?bjnghfgreygt这样的东西
如果是get,就会出现了
1、Get 方法通过 URL 请求来传递用户的数据,将表单内各字段名称与其内容,以成对的字符串连接,置于 action 属性所指程序的 url 后,如[url]http://www.mdm.com/test.asp?name=asd&password=sad[/url],数据都会 直接显示在 url 上,就像用户点击一个链接一样;Post 方法通过 HTTP post 机制,将表单内各字段名称与其内容放置在 HTML 表头(header)内一起传送给服务器端交由 action 属性能所指的程序处理,该程序会通过标准输入(stdin)方式,将表单的数据读出并加以处理
2、 Get 方式需要使用 Request.QueryString 来取得变量的值;而 Post 方式通过 Request.Form 来访问提交的内容
3、Get 方式传输的数据量非常小,一般限制在 2 KB 左右,但是执行效率却比 Post 方法好;而 Post 方式传递的数据量相对较大,它是等待服务器来读取数据,不过也有字节限制,这是为了避免对服务器用大量数据进行恶意攻击,根据微软方面的说法,微软对用 Request.Form() 可接收的最大数据有限制,IIS 4 中为 80 KB 字节,IIS 5 中为 100 KB 字节
建议:除非你肯定你提交的数据可以一次性提交,否则请尽量用 Post 方法
4、Get 方式提交数据,会带来安全问题,比如一个登陆页面,通过 Get 方式提交数据时,用户名和密码将出现在 URL 上,如果页面可以被缓存或者其他人可以访问客户这台机器,就可以从历史记录获得该用户的帐号和密码,所以表单提交建议使用 Post 方法;Post 方法提交的表单页面常见的问题是,该页面如果刷新的时候,会弹出一个对话框
建议:出于安全性考虑,建议最好使用 Post 提交数据 |
post和get的不同之处
GET与POST的区别在于:(对于CGI)
如果以GET方式传输,所带参数附加在CGI程式的URL后直接传给server,并可从server端的QUERY_STRING这个环境变量中读取;
如果以POST方式传输,则参数会被打包在数据报中传送给server,并可从CONTENT_LENGTH这个环境变量中读取出来。
还有一种情况是,你用的是GET方式,但传送的参数是路径,如:
----< ahref="/cgi-bin/a.pl/usr/local/bin/pine" >CGI< /a >
----这时所传递的参数"/usr/local/bin/pine"存放在PATH_INFO这个环境变量中。环境变量的读取方式为$str=$ENV{'QUERY_STRING'};
理论上说,GET是从服务器上请求数据,POST是发送数据到服务器。事实上,GET方法是把数据参数队列(query string)加到一个URL上,值和表单是一一对应的。比如说,name=John。在队列里,值和表单用一个&符号分开,空格用 号替换,特殊的符号转换成十六进制的代码。因为这一队列在URL里边,这样队列的参数就能看得到,可以被记录下来,或更改。通常GET方法还限制字符的大小。事实上POST方法可以没有时间限制的传递数据到服务器,用户在浏览器端是看不到这一过程的,所以POST方法比较适合用于发送一个保密的(比如信用卡号)或者比较大量的数据到服务器。
Post是允许传输大量数据的方法,而Get方法会将所要传输的数据附在网址后面,然后一起送达服务器,因此传送的数据量就会受到限制,但是执行效率却比Post方法好。
对于GET提交的数据,WWW服务器将把数据放在环境变量QUERY_STRING中;对于POST方法,数据被送到WWW服务器的STDOUT中,然后CGI从自己的STDIN中读取。使用传统的CGI方法,用户必须自己编程来处理这些数据。
GET与POST的区别在于,如果以GET方式传输,所带参数附加在CGI程式的URL后直接传给server,并可从server端的QUERY_STRING这个环境变量中读取;如果以POST方式传输,则参数会被打包在数据报中传送给server,并可从CONTENT_LENGTH这个环境变量中读取出来。还有一种情况是,你用的是GET方式,但传送的参数是路径,如:
----< ahref="/cgi-bin/a.pl/usr/local/bin/pine" >CGI< /a >
----这时所传递的参数"/usr/local/bin/pine"存放在PATH_INFO这个环境变量中。环境变量的读取方式为$str=$ENV{'QUERY_STRING'};
总结起来:
get方式:以URL字串本身传递数据参数,在服务器端可以从'QUERY_STRING'这个变量中直接读取,效率较高,但缺乏安全性,也无法来处理复杂的数据(只能是字符串,比如在servlet/jsp中就无法处理发挥java的比如vector之类的功能);
post方式:就传输方式讲参数会被打包在数据报中传输,从CONTENT_LENGTH这个环境变量中读取,便于传送较大一些的数据,同时因为不暴露数据在浏览器的地址栏中,安全性相对较高,但这样的处理效率会受到影响。
-------------------
GET 和 POST 请求的区别
// --TCP/IP 协议详解卷3
13.3.1 报文类型:请求与响应
HTTP / 1 . 0报文有两种类型:请求和响应。HTTP / 1 . 0请求的格式是:
reqe t - l i n e
headers ( 0或有多个)
body (只对POST请求有效) request - l i n e的格式是:
request request-URI HTTP版本号
支持以下三种请求:
1) G E T请求,返回re q u e s t - U R I所指出的任意信息。
2) H E A D请求,类似于G E T请求,但服务器程序只返回指定文档的首部信息,而不包含实际的文档内容。该请求通常被用来测试超文本链接的正确性、可访问性和最近的修改。
3) P O S T请求用来发送电子邮件、新闻或发送能由交互用户填写的表格。这是唯一需要在请求中发送b o d y的请求。使用P O S T请求时需要在报文首部C o n t e n t - L e n g t h字段中
指出b o d y的长度。
// --TCP/IP 协议详解卷3
明白?get 请求表示客户端请求一个uri,服务器返回客户端请求的uri,post请求表示客户端请求的时候还要提交数据,比喻提交form表单,要提交的数据会放到请求报文的body部分。服务器收到后这样的请求后通常需要来处理这些数据。
应聘j2ee开发时问这个问题说明提问着的重点是服务器对这两种请求的处理有什么不同,而不是这两种请求的报文有什么不同。当然作为一个jsp servlet的开发者一般你是不会感觉到着两种请求有什么不同的,因为web服务器已经对这些请求进行处理了,web服务器调用相应的 jsp/servlet来响应客户端请求的时候,对于post的请求,web服务器已经把客户端提交的数据取出来,添到request对象中去了。不过,对于get、post的请求servlet 的 doGet、 doPost方法会被响应调用。也就是说如果客户端送来的是一个get的请求,那么你写到servlet中的dopost()方法中的代码是不会执行的,反之如果是post的请求,写在doget()中代码是不会被调用的(对于所有方式的请求,写在doservice的代码是会被调用的,因为在HttpServlet类中doGet doPost的请求都是由doService来分发的,具体的看关于servlet的生命周期介绍)。
HTTP请求:GET与POST方法的区别
HTTP 定义了与服务器交互的不同方法,最基本的方法是 GET 和 POST。事实上 GET 适用于多数请求,而保留 POST 仅用于更新站点。根据 HTTP 规范,GET 用于信息获取,而且应该是 安全的和 幂等的。所谓安全的意味着该操作用于获取信息而非修改信息。换句话说,GET 请求一般不应产生副作用。幂等的意味着对同一 URL 的多个请求应该返回同样的结果。完整的定义并不像看起来那样严格。从根本上讲,其目标是当用户打开一个链接时,她可以确信从自身的角度来看没有改变资源。比如,新闻站点的头版不断更新。虽然第二次请求会返回不同的一批新闻,该操作仍然被认为是安全的和幂等的,因为它总是返回当前的新闻。反之亦然。POST 请求就不那么轻松了。POST 表示可能改变服务器上的资源的请求。仍然以新闻站点为例,读者对文章的注解应该通过 POST 请求实现,因为在注解提交之后站点已经不同了(比方说文章下面出现一条注解);
在FORM提交的时候,如果不指定Method,则默认为GET请求,Form中提交的数据将会附加在url之后,以?分开与url分开。字母数字字符原样发送,但空格转换为“ “号,其它符号转换为%XX,其中XX为该符号以16进制表示的ASCII(或ISO Latin-1)值。GET请求请提交的数据放置在HTTP请求协议头中,而POST提交的数据则放在实体数据中;
GET方式提交的数据最多只能有1024字节,而POST则没有此限制。
get和post方法的不同 在B/S应用程序中,前台与后台的数据交互,都是通过HTML中Form表单完成的。Form提供了两种数据传输的方式——get和post。虽然它们都是数据的提交方式,但是在实际传输时确有很大的不同,并且可能会对数据产生严重的影响。虽然为了方便的得到变量值,Web容器已经屏蔽了二者的一些差异,但是了解二者的差异在以后的编程也会很有帮助的。
? Form中的get和post方法,在数据传输过程中分别对应了HTTP协议中的GET和POST方法。二者主要区别如下:
? 1、Get是用来从服务器上获得数据,而Post是用来向服务器上传递数据。
? 2、Get将表单中数据的按照variable=value的形式,添加到action所指向的URL后面,并且两者使用“?”连接,而各个变量之间使用“&”连接;Post是将表单中的数据放在form的数据体中,按照变量和值相对应的方式,传递到action所指向URL。
? 3、Get是不安全的,因为在传输过程,数据被放在请求的URL中,而如今现有的很多服务器、代理服务器或者用户代理都会将请求URL记录到日志文件中,然后放在某个地方,这样就可能会有一些隐私的信息被第三方看到。另外,用户也可以在浏览器上直接看到提交的数据,一些系统内部消息将会一同显示在用户面前。Post的所有操作对用户来说都是不可见的。
? 4、Get传输的数据量小,这主要是因为受URL长度限制;而Post可以传输大量的数据,所以在上传文件只能使用Post(当然还有一个原因,将在后面的提到)。
? 5、Get限制Form表单的数据集的值必须为ASCII字符;而Post支持整个ISO10646字符集。
? 6、Get是Form的默认方法。 ?
GET 和 POST 的数据格式都是一样的:
GET 支持的最大字节限制是 2048 Bytes
POST 支持的最大字节限制是 2GB
在表单里使用”post”和”get”有什么区别
在Form里面,可以使用post也可以使用get。它们都是method的合法取值。但是,post和get方法在使用上至少有两点不同: 1、Get方法通过URL请求来传递用户的输入。Post方法通过另外的形式。 2、Get方式的提交你需要用Request.QueryString来取得变量的值,而Post方式提交时,你必须通过Request.Form来访问提交的内容。
仔细研究下面的代码。你可以运行之来感受一下:
代码 <!--两个Form只有Method属性不同--> <FORM ACTION=“getpost.asp” METHOD=“get”> <INPUT TYPE=“text” NAME=“Text” VALUE=“Hello World”></INPUT> <INPUT TYPE=“submit” VALUE=“Method=Get”></INPUT> </FORM> <BR> <FORM ACTION=“getpost.asp” METHOD=“post”> <INPUT TYPE=“text” NAME=“Text” VALUE=“Hello World”></INPUT> <INPUT TYPE=“submit” VALUE=“Method=Post”></INPUT> </FORM>
<BR> <BR>
<% If Request.QueryString(“Text”) <> ““ Then %> 通过get方法传递来的字符串是: “<B><%= Request.QueryString(“Text”) %></B>“<BR> <% End If %>
<% If Request.Form(“Text”) <> ““ Then %> 通过Post方法传递来的字符串是: “<B><%= Request.Form(“Text”) %></B>“<BR> <% End If %>
说明 把上面的代码保存为getpost.asp,然后运行,首先测试post方法,这时候,浏览器的url并没有什么变化,返回的结果是: 通过Post方法传递来的字符串是: "Hello World" 然后测试用get方法提交,请注意,浏览器的url变成了: http://localhost/general/form/getpost.asp?Text=Hello+World 而返回的结果是: 通过get方法传递来的字符串是: "Hello World" 最后再通过post方法提交,浏览器的url还是: http://localhost/general/form/getpost.asp?Text=Hello+World 而返回的结果变成: 通过get方法传递来的字符串是: "Hello World" 通过Post方法传递来的字符串是: "Hello World"
提示 通过get方法提交数据,可能会带来安全性的问题。比如一个登陆页面。当通过get方法提交数据时,用户名和密码将出现在URL上。如果: 1、登陆页面可以被浏览器缓存; 2、其他人可以访问客户的这台机器。 那么,别人即可以从浏览器的历史记录中,读取到此客户的账号和密码。所以,在某些情况下,get方法会带来严重的安全性问题。 建议 在Form中,建议使用post方法。 |
LP 你是最棒的!我相信你,你要坚强,要坚定你的步伐,一如既往的走下去,走出一条自己的道路,好好的学习,好好的做事,做好自己!
应该看两遍!
- #include <sys/types.h>
- #include <unistd.h>
-
-
-
-
-
-
-
- pid_t fork(void);
由fork创建的新进程被称为子进程(child process)。该函数被调用一次,但返回两次。两次返回的区别是子进程的返回值是0,而父进程的返回值则是新进程(子进程)的进程 id。将子进程id返回给父进程的理由是:因为一个进程的子进程可以多于一个,没有一个函数使一个进程可以获得其所有子进程的进程id。对子进程来说,之所以fork返回0给它,是因为它随时可以调用getpid()来获取自己的pid;也可以调用getppid()来获取父进程的id。(进程id 0总是由交换进程使用,所以一个子进程的进程id不可能为0 )。
fork之后,操作系统会复制一个与父进程完全相同的子进程,虽说是父子关系,但是在操作系统看来,他们更像兄弟关系,这2个进程共享代码空间,但是数据空间是互相独立的,子进程数据空间中的内容是父进程的完整拷贝,指令指针也完全相同,子进程拥有父进程当前运行到的位置(两进程的程序计数器pc值相同,也就是说,子进程是从fork返回处开始执行的),但有一点不同,如果fork成功,子进程中fork的返回值是0,父进程中fork的返回值是子进程的进程号,如果fork不成功,父进程会返回错误。
可以这样想象,2个进程一直同时运行,而且步调一致,在fork之后,他们分别作不同的工作,也就是分岔了。这也是fork为什么叫fork的原因
至于那一个最先运行,可能与操作系统(调度算法)有关,而且这个问题在实际应用中并不重要,如果需要父子进程协同,可以通过原语的办法解决。
一个fork例子
- #include <unistd.h>
- #include <sys/types.h>
- #include <stdio.h>
- int main(void)
- {
- pid_t pid;
- pid=fork();
- switch (pid)
- {
- case -1:
- perror("fork error");
- exit(1);
- case 0:
- printf("I am the child process, my process id is %d/n", getpid());
- break;
- default:
- printf("I am the parent process, my process id is %d/n", getpid());
- break;
- }
- return 0;
- }
要搞清楚fork的执行过程,就必须先弄清楚操作系统中的“进程(process)”概念。一个进程,主要包含三个元素:
o. 一个可以执行的程序;
o. 和该进程相关联的全部数据(包括变量,内存空间,缓冲区等等);
o. 程序的执行上下文(execution context)。
不妨简单理解为,一个进程表示的,就是一个可执行程序的一次执行过程中的一个状态。操作系统对进程的管理,典型的情况,是通过进程表完成的。进程表中的每一个表项,记录的是当前操作系统中一个进程的情况。对于单 CPU的情况而言,每一特定时刻只有一个进程占用 CPU,但是系统中可能同时存在多个活动的(等待执行或继续执行的)进程。
一个称为“程序计数器(program counter, pc)”的寄存器,指出当前占用 CPU的进程要执行的下一条指令的位置。
当分给某个进程的 CPU时间已经用完,操作系统将该进程相关的寄存器的值,保存到该进程在进程表中对应的表项里面;把将要接替这个进程占用 CPU的那个进程的上下文,从进程表中读出,并更新相应的寄存器(这个过程称为“上下文交换(process context switch)”,实际的上下文交换需要涉及到更多的数据,那和fork无关,不再多说,主要要记住程序寄存器pc记录了程序当前已经执行到哪里,是进程上下文的重要内容,换出 CPU的进程要保存这个寄存器的值,换入CPU的进程,也要根据进程表中保存的本进程执行上下文信息,更新这个寄存器)。
好了,有这些概念打底,可以说fork了。当你的程序执行到下面的语句:pid=fork();
操作系统创建一个新的进程(子进程),并且在进程表中相应为它建立一个新的表项。新进程和原有进程的可执行程序是同一个程序;上下文和数据,绝大部分 就是原进程(父进程)的拷贝,但它们是两个相互独立的进程!此时程序寄存器pc,在父、子进程的上下文中都声称,这个进程目前执行到fork调用即将返回(此时子进程不占有CPU,子进程的pc不是真正保存在寄存器中,而是作为进程上下文保存在进程表中的对应表项内)。问题是怎么返回,在父子进程中就分道扬镳。
(假设父进程一直占据CPU,实际情况很可能不一样)父进程继续执行,操作系统对fork的实现,使这个调用在父进程中返回刚刚创建的子进程的pid(一个正整数),所以下面的swtich语句中执行了default分支(case -1,case 0分支都不满足)。所以输出I am the parent process...
子进程在之后的某个时候得到调度,它的上下文被换入,占据 CPU,操作系统对fork的实现,使得子进程中fork调用返回0,所以在这个进程(注意这不是父进程了哦,虽然是同一个程序,但是这是同一个程序的另外一次执行,在操作系统中这次执行是由另外一个进程表示的,从执行的角度说和父进程相互独立)中pid=0。这个进程继续执行的过程中,switch语句中 case -1不满足,但是case 0是满足。所以输出I am the child process..
程序的运行结果(先输出I am the parent process...,还是I am the parent process...)不可预见,与操作系统实际运行情况有关!
-
疲惫的一天又过去了,时间很快很快,我却一直在恐惧着,我想证明自己的实力,但是现实好像
不是这样的,我感觉自己好累,有很新奇,很想学习那些东西,很想把东西做出来,但是现在还是无果
我缺少什么了?到底哪里不行了?是决心不够,还是细心不够,还是我根本就没有用脑子,没有思考!
时间停停吧,让我这个可怜的人反省反省自己,问题到底在哪里???
是不是自己没有静下心来? 太浮躁了吗? 还是太急功近利了?心有余而力不从,我太高估自己
了吗?
我想改变,改变自己,改变环境,重生的欲望喷涌而出,给我一点曙光,一丝希望,让我坚定的
走下去,让路越走越宽敞!
2009-04-29 10:03
linux c语言 select函数用法
Select在Socket编程中还是比较重要的,可是对于初学Socket的人来说都不太爱用Select写程序,他们只是习惯写诸如
connect、accept、recv或recvfrom这样的阻塞程序(所谓阻塞方式block,顾名思义,就是进程或是线程执行到这些函数时必须等
待某个事件的发生,如果事件没有发生,进程或线程就被阻塞,函数不能立即返回)。
可是使用Select就可以完成非阻塞(所谓非阻塞方式non-
block,就是进程或线程执行此函数时不必非要等待事件的发生,一旦执行肯定返回,以返回值的不同来反映函数的执行情况,如果事件发生则与阻塞方式相同,若事件没有发生则返回一个代码来告知事件未发生,而进程或线程继续执行,所以效率较高)方式工作的程序,它能够监视我们需要监视的文件描述符的变化情况——读写或是异常。
下面详细介绍一下!
Select的函数格式(我所说的是Unix系统下的伯克利socket编程,和windows下的有区别,一会儿说明):
int select(int maxfdp,fd_set *readfds,fd_set *writefds,fd_set *errorfds,struct timeval *timeout);
先说明两个结构体:第一,struct fd_set可以理解为一个集合,这个集合中存放的是文件描述符(filedescriptor),即文件句柄,这可以是我们所说的普通意义的文件,当然Unix下任何设备、管道、FIFO等都是文件形式,全部包括在内,所以毫无疑问一个socket就是一个文件,socket句柄就是一个文件描述符。
fd_set集合可以通过一些宏由人为来操作,比如
清空集合FD_ZERO(fd_set *);
将一个给定的文件描述符加入集合之中FD_SET(int ,fd_set
*);
将一个给定的文件描述符从集合中删除FD_CLR(int
,fd_set*);
检查集合中指定的文件描述符是否可以读写FD_ISSET(int ,fd_set* )。一会儿举例说明。
第二,struct timeval是一个大家常用的结构,用来代表时间值,有两个成员,一个是秒数,另一个是毫秒数。
具体解释select的参数:
int maxfdp是一个整数值,是指集合中所有文件描述符的范围,即所有文件描述符的最大值加1,不能错!在Windows中这个参数的值无所谓,可以设置不正确。
fd_set*readfds是指向fd_set结构的指针,这个集合中应该包括文件描述符,我们是要监视这些文件描述符的读变化的,即我们关心是否可以从这些文件中读取数据了,如果这个集合中有一个文件可读,select就会返回一个大于0的值,表示有文件可读,如果没有可读的文件,则根据timeout参数再判断是否超时,若超出timeout的时间,select返回0,若发生错误返回负值。可以传入NULL值,表示不关心任何文件的读变化。
fd_set*writefds是指向fd_set结构的指针,这个集合中应该包括文件描述符,我们是要监视这些文件描述符的写变化的,即我们关心是否可以向这些文件中写入数据了,如果这个集合中有一个文件可写,select就会返回一个大于0的值,表示有文件可写,如果没有可写的文件,则根据timeout参数再判断是否超时,若超出timeout的时间,select返回0,若发生错误返回负值。可以传入NULL值,表示不关心任何文件的写变化。
fd_set *errorfds同上面两个参数的意图,用来监视文件错误异常。
struct timeval *timeout是select的超时时间,这个参数至关重要,它可以使select处于三种状态,第一,若将NULL以形参传入,即不传入时间结构,就是将select置于阻塞状态,一定等到监视文件描述符集合中某个文件描述符发生变化为止;第二,若将时间值设为0秒0毫秒,就变成一个纯粹的非阻塞函数,不管文件描述符是否有变化,都立刻返回继续执行,文件无变化返回0,有变化返回一个正值;第三,timeout的值大于0,这就是等待的超时时间,即select在timeout时间内阻塞,超时时间之内有事件到来就返回了,否则在超时后不管怎样一定返回,返回值同上述。
返回值:
负值:select错误 正值:某些文件可读写或出错 0:等待超时,没有可读写或错误的文件
在有了select后可以写出像样的网络程序来!举个简单的例子,就是从网络上接受数据写入一个文件中。
例子:
main()
{
int sock;
FILE *fp;
struct fd_set fds;
struct timeval timeout={3,0}; //select等待3秒,3秒轮询,要非阻塞就置0
char buffer[256]={0}; //256字节的接收缓冲区
/* 假定已经建立UDP连接,具体过程不写,简单,当然TCP也同理,主机ip和port都已经给定,要写的文件已经打开
sock=socket(...);
bind(...);
fp=fopen(...); */
while(1)
{
FD_ZERO(&fds); //每次循环都要清空集合,否则不能检测描述符变化
FD_SET(sock,&fds); //添加描述符
FD_SET(fp,&fds); //同上
maxfdp=sock>fp?sock+1:fp+1; //描述符最大值加1
switch(select(maxfdp,&fds,&fds,NULL,&timeout)) //select使用
{
case -1: exit(-1);break; //select错误,退出程序
case 0:break; //再次轮询
default:
if(FD_ISSET(sock,&fds)) //测试sock是否可读,即是否网络上有数据
{
recvfrom(sock,buffer,256,.....);//接受网络数据
if(FD_ISSET(fp,&fds)) //测试文件是否可写
fwrite(fp,buffer...);//写入文件
buffer清空;
}// end if break;
}// end switch
}//end while
}//end main文章出处:DIY部落(
http://www.diybl.com/course/6_system/linux/Linuxjs/20090308/159832.html)linux c语言 select函数用法 表头文件 #i nclude<sys/time.h>
#i nclude<sys/types.h>
#i nclude<unistd.h> 定义函数 int select(int n,fd_set * readfds,fd_set * writefds,fd_set * exceptfds,struct timeval * timeout); 函数说明 select()用来等待文件描述词状态的改变。参数n代表最大的文件描述词加1,参数readfds、writefds 和exceptfds 称为描述词组,是用来回传该描述词的读,写或例外的状况。底下的宏提供了处理这三种描述词组的方式:
FD_CLR(inr fd,fd_set* set);用来清除描述词组set中相关fd 的位
FD_ISSET(int fd,fd_set *set);用来测试描述词组set中相关fd 的位是否为真
FD_SET(int fd,fd_set*set);用来设置描述词组set中相关fd的位
FD_ZERO(fd_set *set); 用来清除描述词组set的全部位 参数 timeout为结构timeval,用来设置select()的等待时间,其结构定义如下
struct timeval
{
time_t tv_sec;
time_t tv_usec;
}; 返回值 如果参数timeout设为NULL则表示select()没有timeout。 错误代码 执行成功则返回文件描述词状态已改变的个数,如果返回0代表在描述词状态改变前已超过timeout时间,当有错误发生时则返回-1,错误原因存于errno,此时参数readfds,writefds,exceptfds和timeout的值变成不可预测。
EBADF 文件描述词为无效的或该文件已关闭
EINTR 此调用被信号所中断
EINVAL 参数n 为负值。
ENOMEM 核心内存不足 范例 常见的程序片段:fs_set readset;
FD_ZERO(&readset);
FD_SET(fd,&readset);
select(fd+1,&readset,NULL,NULL,NULL);
if(FD_ISSET(fd,readset){……}
下面是linux环境下select的一个简单用法
#i nclude <sys/time.h>
#i nclude <stdio.h>
#i nclude <sys/types.h>
#i nclude <sys/stat.h>
#i nclude <fcntl.h>
#i nclude <assert.h>
int main ()
{
int keyboard;
int ret,i;
char c;
fd_set readfd;
struct timeval timeout;
keyboard = open("/dev/tty",O_RDONLY | O_NONBLOCK);
assert(keyboard>0);
while(1)
{
timeout.tv_sec=1;
timeout.tv_usec=0;
FD_ZERO(&readfd);
FD_SET(keyboard,&readfd);
ret=select(keyboard+1,&readfd,NULL,NULL,&timeout);
if(FD_ISSET(keyboard,&readfd))
{
i=read(keyboard,&c,1);
if('\n'==c)
continue;
printf("hehethe input is %c\n",c);
if ('q'==c)
break;
}
}
}
用来循环读取键盘输入
2007年9月17日,将例子程序作一修改,加上了time out,并且考虑了select得所有的情况:
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <assert.h>
int main ()
{
int keyboard;
int ret,i;
char c;
fd_set readfd;
struct timeval timeout;
keyboard = open("/dev/tty",O_RDONLY | O_NONBLOCK);
assert(keyboard>0);
while(1)
{
timeout.tv_sec=5;
timeout.tv_usec=0;
FD_ZERO(&readfd);
FD_SET(keyboard,&readfd);
ret=select(keyboard+1,&readfd,NULL,NULL,&timeout);
//select error when ret = -1
if (ret == -1)
perror("select error");
//data coming when ret>0
else if (ret)
{
if(FD_ISSET(keyboard,&readfd))
{
i=read(keyboard,&c,1);
if('\n'==c)
continue;
printf("hehethe input is %c\n",c);
if ('q'==c)
break;
}
}
//time out when ret = 0
else if (ret == 0)
printf("time out\n");
}
}
#include <string.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/types.h>
下面是我写的一个例程:
在标准输入读取9个字节数据。
用select函数实现超时判断!
int main(int argc, char ** argv)
{
char buf[10] = "";
fd_set rdfds;//
struct timeval tv; //store timeout
int ret; // return val
FD_ZERO(&rdfds); //clear rdfds
FD_SET(1, &rdfds); //add stdin handle into rdfds
tv.tv_sec = 3;
tv.tv_usec = 500;
ret = select(1 + 1, &rdfds, NULL, NULL, &tv);
if(ret < 0)
perror("\nselect");
else if(ret == 0)
printf("\ntimeout");
else
{
printf("\nret=%d", ret);
}
if(FD_ISSET(1, &rdfds))
{
printf("\nreading");
fread(buf, 9, 1, stdin); // read form stdin
}
// read(0, buf, 9); /* read from stdin */
// fprintf(stdout, "%s\n", buf); /* write to stdout */
write(1, buf, strlen(buf)); //write to stdout
printf("\n%d\n", strlen(buf));
return 0;
}
mount: RPC: Timed out解决办法
2010-12-05 11:36
[root@localhost /]# mount -t nfs 192.168.1.202:/home/share /mnt mount: RPC: Timed out [root@localhost /]# cd /mnt/ [root@localhost mnt]# ls cdrom floppy (注意:这里没有nfs这个目录!) [root@localhost mnt]# mkdir nfs [root@localhost mnt]# ls cdrom floppy nfs [root@localhost mnt]# cd / [root@localhost /]# mount -t nfs 192.168.1.202:/home/share /mnt/nfs/ [root@localhost /]# cd /mnt/nfs/ [root@localhost nfs]# ls hello linux-2.6.30 ............. 我的NFS配置都没有问题,但是还是出现RPC的问题 通过我的尝试发现: 要挂载nfs格式的文件,就必须要挂载到nfs这个文件夹中。要不然就出现了mount: RPC: Timed out这样的错误。
我尝试挂载到别的目录下,看看能不能挂,结果能挂 [root@localhost nfs]# cd / [root@localhost /]# umount mnt/nfs/ [root@localhost /]# mount -t nfs 192.168.1.202:/home/share /mnt/cdrom/ [root@localhost /]# cd /mnt/cdrom/ [root@localhost cdrom]# ls hello linux-2.6.30 .................. 这个说明nfs格式的文件不能直接挂到/mnt这个文件夹中!(不解啊!!!!!!) |
一、Linux中的硬件设备号
设 备 设 备 号
IDE硬盘 /dev/hd[a-d] (并行硬盘)
SCSI硬盘 /dev/sd[a-p] (串行硬盘)
U盘 /dev/sd[a-p]
光驱 /dev/cdrom
软驱 /dev/fd[0-1]
打印机 /dev/lp[0-2]
鼠标 /dev/mouse
LCD /dev/fb0
系统终端 /dev/tty0
例如:
<1>当插入第一个U盘时,它的设备号为sda1
当插入第二个U盘时,它的设备号为sdb1
<2>当插入第一个硬盘时,它的设备号为hda1
当插入第二个硬盘时,它的设备号为hdb1
二、设备的挂载
例程:将U盘插入ARM开发板
在Linux系统中,设备在上层都被映射为设备文件,比如IDE硬盘被映射为设备文件/dev/hda1,U盘被映射为设备文件/dev/sda1.如果用户直接访问这些设备文件,则得到的一堆二进制代码.所以,为了方便用户的使用,Linux规定,必须将该设备文件挂载到某一目录下(常用的是/mnt目录),用户对该目录(比如/mnt目录)的操作(读/写)就是对设备文件的操作,也就是对设备的操作.当然,在实际应用中,常在/mnt目录下新建一子目录,比如hdisk(IDE硬盘)、udisk(U盘),然后将设备文件挂载到该子目录下.
步骤1:将相应的文件系统烧入ARM开发板,以支持USB设备等.
步骤2:插入U盘,此时在ARM开发板的终端(putty软件或超级终端)上会显示该U盘的相应信息,最重要的是U盘的设备文件名.
当插入第一个U盘时,该U盘的设备文件名为/dev/sda1.
当插入第二个U盘时,该U盘的设备文件名为/dev/sdb1.
步骤3:在putty软件(或超级终端)下输入命令:
[root@localhost /]#cd /mnt
[root@localhost mnt]#mkdir udisk
这样,就在/mnt目录下新建一子目录udisk.
注意,在putty软件(或超级终端)下输入命令是对ARM开发板进行操作,也就是操作ARM开发板内的文件系统.切记不要再Linux虚拟机下操作.因为现在是将U盘挂载到ARM开发板上,而不是Linux虚拟机,所以,必须对ARM开发板进行操作.
步骤4:在putty软件(或超级终端)下输入命令:
[root@localhost /]#mount -t -vfat /dev/sda1 /mnt/udisk
这样,就成功的将U盘的设备文件/dev/sda1挂载到了ARM开发板的/mnt/udisk目录下,且以fat格式进行挂载.当用户需要访问U盘时,可以通过对文件/mnt/udisk而实现.
注意,U盘多采用fat格式的文件系统.
步骤5:在putty软件(或超级终端)下输入命令:
[root@localhost udisk]#cd ..
这样就退出了udisk目录.
[root@localhost udisk]#umount /mnt/udisk
这样就成功的卸载了U盘(卸载U盘前,需要先退出/mnt/udisk目录).
三、文件的挂载
例程:将Linux虚拟机的/home/lishuai目录挂载到ARM系统的/mnt/arm_linux文件下
步骤1:将相应的文件系统烧入ARM开发板.
步骤2:在Linux虚拟机上建立NFS服务器,并将/home/lishuai目录作为共享目录,且设置的主机IP地址为192.168.0.*.
步骤3:<1>在Linux虚拟机终端上通过ifconfig命令设置IP地址为:192.168.0.20,并通过ifconfig命令查询IP地址.
<2>在Windows的网上邻居设置IP地址为:192.168.0.40,并通过"运行>cmd>ipconfig"命令查询IP地址.
<3>在putty软件或超级终端上通过ifconfig命令设置ARM开发板IP地址为:192.168.0.60,子网掩码为255.255.255.0(#ifconfig eth0 192.168.0.60 netmask 255.255.255.0)并通过ifconfig eth0命令查询IP地址.
这样,Windows、Linux虚拟机、ARM开发板就在同一网段上了.
步骤4:在putty软件或超级终端上输入命令:
#ping 192.168.0.20 //查看ARM开发板能否ping通Linux主机
#ping 192.168.0.40 //查看ARM开发板能否ping通Windows
步骤5:在putty软件或超级终端上输入命令:
[root@localhost /]#cd /mnt
[root@localhost mnt]#mkdir arm_linux
这样,就在ARM开发板的文件系统中/mnt下新建了一子目录arm_linux.
步骤6:在putty软件或超级终端上输入命令:
#mount -o nolock,wsize=1024,rsize=1024 192.168.0.20:/home/lishuai /mnt/arm_linux
这样就将IP地址为192.168.0.20(Linux虚拟机)下的/home/lishuai挂载到(ARM系统)的/mnt/arm_linux目录下.
注释:
<1>若在putty软件或超级终端上输入上面的挂载命令,表示用户对ARM系统进行操作.由于ARM内已烧入了文件系统,故/mnt/arm_linux是ARM内文件系统的一个目录.因此,当用户执行该命令时,表示是将IP地址为192.168.0.20的/home/lishuai挂载到(ARM系统)的/mnt/arm_linux目录下.因此,当用户需要在ARM系统下对Linux虚拟机的/home/lishuai目录进行操作时,直接对/mnt/arm_linux目录操作便可以了.
此时,在putty软件或超级终端上输入命令:#cd /home,但却找不到lishuai这个目录,这是因为在在putty软件或超级终端上执行cd命令时,是对ARM系统的访问.而不是对Linux主机进行访问,虽然ARM系统已烧入了文件系统,但/home目录下未必有lishuai这个目录.
<2>若在Linux虚拟机的终端上输入上面的挂载命令,表示用户对Linux主机进行操作.当然在Linux主机内已有相应的文件系统.故/mnt/arm_linux是Linux主机的一个目录.因此,当用户执行该命令时,表示将IP地址为192.168.0.20的/home/lishuai挂载到Linux主机的/mnt/arm_linux目录下.因此,当用户需要在Linux主机下对IP地址为192.168.0.20的设备的/home/lishuai目录进行操作时,直接对/mnt/arm_linux目录操作便可以了.
从上面的描述可以看出,执行的对象不同,实现的挂载目的也不同.
四、对设备挂载、文件挂载的综合实现
例程:将Windows下的某个文件通过ARM开发板放入U盘
步骤1:通过Samba服务器将Windows下的文件hehe.txt放入(linux与Windows的)共享目录/home/lishuai内.
步骤2:通过NFS服务器将Linux主机的/home/lishuai目录挂载到ARM开发板的/mnt/arm_linux目录下.
在putty软件或超级终端上输入命令:
#mount -o nolock,wsize=1024,rsize=1024 192.168.0.20:/home/lishuai /mnt/arm_linux
步骤3:将U盘挂载到ARM开发板的/mnt/udisk目录下.
在putty软件或超级终端上输入命令:
#mount -t -vfat /dev/sda1 /mnt/udisk
步骤4:在putty软件或超级终端上输入命令:
#cd /mnt/udisk
#cp ../arm_linux/hehe.txt ./
这样就实现了将Windows下的某个文件通过ARM开发板放入U盘的目的.
步骤5:卸载U盘和Linux虚拟机的/home/lishuai目录.
在putty软件或超级终端上输入命令:
[root@localhost udisk]#cd ..
[root@localhost mnt]#umount /mnt/arm_linux
[root@localhost mnt]#umount /mnt/udisk
五、设备号的另类应用
1.配置linux主机IP地址:192.168.220.54
2.配置ARM开发板IP地址:192.168.220.1
3.配置Windows的IP地址:192.168.220.55
4.在putty软件或超级终端下:#ping 192.168.220.54
5.将linux主机的/home/lishuai目录挂载到ARM开发板的/mnt/arm_linux目录下:
#mount -o nolock,wsize=1024,rsize=1024192.168.220.54:/home/lishuai /mnt/arm_linux
6.在linux主机的/home/lishuai目录下创建hehe.c源码.
#vim hehe.c
#include <stdio.h>
int main(void)
{
printf("hello embeded!/n");
return 0;
}
7.在linux主机的/home/lishuai目录下使用arm-linux-gcc编译hehe.c(为了在ARM平台上运行,必须使用arm-linux-gcc编译器).
#arm-linux-gcc hehe.c -o hehe.arm
编译成功后,在putty软件或超级终端下的/mnt/arm_linux目录下会新产生一个hehe.arm的可执行文件.由此看出,linux主机的/home/lishuai与ARM开发板的/mnt/arm_linux目录是同步更新的.
8.在putty软件或超级终端下:
#./hehe.arm > /dev/tty0 //将hehe.arm执行结果打印到LCD上
#clear > /dev/tty0 //清屏
#ls > /dev/tty0 //将显示出当前路径(/mnt/arm_linux)下的文件和目录
Attention!!!
(1)通常向LCD上写这些重定向,是写到tty0,而不是fb0.
(2)使用NFS实现文件挂载时,必须保证下面几点.
<1>linux主机的NFS服务器正常使用.
若有问题,可通过指令重启服务器:#service nfs restart
或查询服务器状态:#service nfs status
<2>Windows、linux主机和ARM开发板的IP地址在同一网段内,且通过ARM开发板可以ping通另外两个设备.因为文件挂载是通过网络实现的.
(3)在实际的嵌入式开发中,常常无法将Linux主机的某个目录挂载到ARM开发板上,此时可以从以下三个方面着手:
<1>由于这种挂载依赖于NFS服务器,因此可以查询NFS服务器的状态,或者重启NFS服务器.
#service nfs restart
#service nfs status
<2>重新配置Linux虚拟机的IP地址.这种挂载基于ARM开发板、Linux主机和Windows网卡在同一网段上,有时相互之间ping通但却无法挂载.
<3>在Linux主机内输入命令来查看Linux主机是否能挂载自己.
#ifconfig eth0 192.168.0.50
#mount -o nolock 192.168.0.50:/home/lishuai /mnt
//将Linux主机的/home/lishuai目录挂载到本机的/mnt目录下
一、查看是否安装NFS(portmap是用于RPC传输的)
# rpm -q nfs-utils portmap
nfs-utils-1.0.9-47.el5_5
portmap-4.0-65.2.2.1
二、配置
1。配置文件
# vi /etc/exports
配置实例:
1)/nfs/public 192.168.16.0/24(rw,async) *(ro)
共享目录 客户机1 客户机2
nfs/public共享目录可供子网192.168.16.0/24中的所有客户端进行读写操作,其它网络中的客户端只能有读取操作权限。
2)/home/test 192.168.0.0/24(rw,no_root_squash,async)
no_root_squash:不讲root用户及所属用户组映射为匿名用户或用户组,默认root是被映射为匿名用户的nfsnobody,所有即使开了rw写权限,客户机也使无法写入的,这个不映射为匿名用户,还保留原来的用户权限就可以读写了,因为一般都是用root用户登录的。
注意:当客机是否有写权限时,还要看该目录对该用户有没有开放写入权限
三、维护NFS
格式:
exportfs 选项参数
-a:输出/etc/exports中设置的所有目录
-r:重新读取/etc/exports文件中的设置,并且立即生效,而不需要重新启动NFS服务。
-u:停止输出某一目录
-v:在输出目录时,将目录显示在屏幕上。
1.修改vi /etc/exports后,不用重启服务,直接使用命令输出共享目录
# exportfs -rv
2.停止输出所有共享目录
# exportfs -auv
四、启动和停止NFS服务
1.启动NFS服务
为了是NFS正常工作,需要启动portmap和nfs这两个目录,并且portmap一定要先于nfs启动。
# /etc/init.d/portmap start
# /etc/init.d/nfs start
2.停止NFS 服务
停止NFS服务器前,需要先停止NFS服务再停止portmap服务。如果系统中还有其它服务需要portmap时,则可以不用停止portmap服务。
/etc/init.d/nfs stop
/etc/init.d/portmap stop
3。自启动NFS服务
chkconfig --level 35 portmap on
chkconfig --level 35 nfs on
五、测试
1.检查输出目录所使用的选项
在/etc/exports配置文件中,即使只设置了一两个选项,在真正输出目录时,实际上还带了很多某人选项。通过查看 /var/lib/nfs/etab文件,就可以知道真正输出目录时,都是用了什么选项。
2.使用showmount测试NFS输出目录状态
格式:
showmount 参数选项 nfs服务器名称或地址
-a:显示指定的nfs服务器的所有客户端主机及其所连接的目录
-d:显示指定的nfs服务器中已经被客户端连接的所有共享目录
-e:显示指定的nfs服务器上所有输出的共享目录
(1)查看所有输出的共享目录
# showmount -e
(2)显示所有被挂载的所有输出目录
# showmount -d
六、nfs客户端使用配置
1.查看nfs服务器信息
在客户端,要查看nfs服务器上有哪些共享目录,可以使用showmount命令。
# showmount -e 192.168.0.51
如果出现报错信息,首先查看服务器nfs和portmap服务是否启动。再看是否被防火墙屏蔽掉了。
2.挂载nfs服务器上的共享目录
# mount -t nfs 192.168.0.51:/home/test /mnt/
-t:指定挂载设备的文件类型(nfs是网络文件系统)
192.168.0.51:nfs服务器ip地址
/home/test :nfs服务器的共享目录
/mnt/:挂载在本地的目录
3.卸载nfs
在不使用nfs目录时,可以用umount命令来卸载该目录
注意:当有客户机正在连接nfs服务器时,此时想要将nfs服务器关机,应该先关掉portmap和nfs这两个服务,否则要等很久才能正常关机。如果无法将portmap和nfs关掉,就直接kill掉进程。也可以用exportmap -auv命令将当前主机中的所有输出目录停止后再关机。
4.启动时自动连接nfs服务器
要先在启动时自动连接nfs服务器上的共享目录,要编辑/etc/fstab文件。在文件中加入
192.168.0.51:/home/test /mnt nfs defaults 0 0
192.168.0.51:/home/test:nfs服务器的共享目录
/mnt:本机挂载目录
-------------------------------------------------
拷贝时cp命令常用参数
cp -a -v /mnt /home/
- a 该选项通常在拷贝目录时使用。它保留链接、文件属性,并递归地拷贝目录,其作用等于dpR选项的组合。
-v或–verbose 显示指令执行过程。
-V<备份方式>或–version-control=<备份方式> 用”-b”参数备份目标文件后,备份文件的字尾会被加上一个备份字符串,这字符串不仅可用”-S”参数变更,当使用”-V”参数指定不同备份方式时,也会产生不同字尾的备份字串。
- i 和f选项相反,在覆盖目标文件之前将给出提示要求用户确认。回答y时目标文件将被覆盖,是交互式拷贝。
SIGHUP 终止进程 终端线路挂断
SIGINT 终止进程 中断进程
SIGQUIT 建立CORE文件终止进程,并且生成core文件
SIGILL 建立CORE文件 非法指令
SIGTRAP 建立CORE文件 跟踪自陷
SIGBUS 建立CORE文件 总线错误
SIGSEGV 建立CORE文件 段非法错误
SIGFPE 建立CORE文件 浮点异常
SIGIOT 建立CORE文件 执行I/O自陷
SIGKILL 终止进程 杀死进程
SIGPIPE 终止进程 向一个没有读进程的管道写数据
SIGALARM 终止进程 计时器到时
SIGTERM 终止进程 软件终止信号
SIGSTOP 停止进程 非终端来的停止信号
SIGTSTP 停止进程 终端来的停止信号
SIGCONT 忽略信号 继续执行一个停止的进程
SIGURG 忽略信号 I/O紧急信号
SIGIO 忽略信号 描述符上可以进行I/O
SIGCHLD 忽略信号 当子进程停止或退出时通知父进程
SIGTTOU 停止进程 后台进程写终端
SIGTTIN 停止进程 后台进程读终端
SIGXGPU 终止进程 CPU时限超时
SIGXFSZ 终止进程 文件长度过长
SIGWINCH 忽略信号 窗口大小发生变化
SIGPROF 终止进程 统计分布图用计时器到时
SIGUSR1 终止进程 用户定义信号1
SIGUSR2 终止进程 用户定义信号2
SIGVTALRM 终止进程 虚拟计时器到时
1) SIGHUP 本信号在用户终端连接(正常或非正常)结束时发出, 通常是在终端的控
制进程结束时, 通知同一session内的各个作业, 这时它们与控制终端
不再关联.
2) SIGINT 程序终止(interrupt)信号, 在用户键入INTR字符(通常是Ctrl-C)时发出
3) SIGQUIT 和SIGINT类似, 但由QUIT字符(通常是Ctrl-)来控制. 进程在因收到
SIGQUIT退出时会产生core文件, 在这个意义上类似于一个程序错误信
号.
4) SIGILL 执行了非法指令. 通常是因为可执行文件本身出现错误, 或者试图执行
数据段. 堆栈溢出时也有可能产生这个信号.
5) SIGTRAP 由断点指令或其它trap指令产生. 由debugger使用.
6) SIGABRT 程序自己发现错误并调用abort时产生.
6) SIGIOT 在PDP-11上由iot指令产生, 在其它机器上和SIGABRT一样.
7) SIGBUS 非法地址, 包括内存地址对齐(alignment)出错. eg: 访问一个四个字长
的整数, 但其地址不是4的倍数.
8) SIGFPE 在发生致命的算术运算错误时发出. 不仅包括浮点运算错误, 还包括溢
出及除数为0等其它所有的算术的错误.
9) SIGKILL 用来立即结束程序的运行. 本信号不能被阻塞, 处理和忽略.
10) SIGUSR1 留给用户使用
11) SIGSEGV 试图访问未分配给自己的内存, 或试图往没有写权限的内存地址写数据.
12) SIGUSR2 留给用户使用
13) SIGPIPE Broken pipe
14) SIGALRM 时钟定时信号, 计算的是实际的时间或时钟时间. alarm函数使用该
信号.
15) SIGTERM 程序结束(terminate)信号, 与SIGKILL不同的是该信号可以被阻塞和
处理. 通常用来要求程序自己正常退出. shell命令kill缺省产生这
个信号.
17) SIGCHLD 子进程结束时, 父进程会收到这个信号.
18) SIGCONT 让一个停止(stopped)的进程继续执行. 本信号不能被阻塞. 可以用
一个handler来让程序在由stopped状态变为继续执行时完成特定的
工作. 例如, 重新显示提示符
19) SIGSTOP 停止(stopped)进程的执行. 注意它和terminate以及interrupt的区别:
该进程还未结束, 只是暂停执行. 本信号不能被阻塞, 处理或忽略.
20) SIGTSTP 停止进程的运行, 但该信号可以被处理和忽略. 用户键入SUSP字符时
(通常是Ctrl-Z)发出这个信号
21) SIGTTIN 当后台作业要从用户终端读数据时, 该作业中的所有进程会收到SIGTTIN
信号. 缺省时这些进程会停止执行.
22) SIGTTOU 类似于SIGTTIN, 但在写终端(或修改终端模式)时收到.
23) SIGURG 有"紧急"数据或out-of-band数据到达socket时产生.
24) SIGXCPU 超过CPU时间资源限制. 这个限制可以由getrlimit/setrlimit来读取/
改变
25) SIGXFSZ 超过文件大小资源限制.
26) SIGVTALRM 虚拟时钟信号. 类似于SIGALRM, 但是计算的是该进程占用的CPU时间.
27) SIGPROF 类似于SIGALRM/SIGVTALRM, 但包括该进程用的CPU时间以及系统调用的
时间.
28) SIGWINCH 窗口大小改变时发出.
29) SIGIO 文件描述符准备就绪, 可以开始进行输入/输出操作.
30) SIGPWR Power failure
有两个信号可以停止进程:SIGTERM和SIGKILL。 SIGTERM比较友好,进程能捕捉这个信号,根据您的需要来关闭程序。在关闭程序之前,您可以结束打开的记录文件和完成正在做的任务。在某些情况下,假如进程正在进行作业而且不能中断,那么进程可以忽略这个SIGTERM信号。
对于SIGKILL信号,进程是不能忽略的。这是一个 “我不管您在做什么,立刻停止”的信号。假如您发送SIGKILL信号给进程,Linux就将进程停止在那里。
NTSC是National Television Systems Committee的缩写,意思是“国家电视系统委员会制式”。
NTSC负责开发一套美国标准电视广播传输和接收协议。此外还有两套标准:逐行倒像(PAL)和顺序与存色彩电视系统(SECAM),用于世界上其他的国家。NTSC标准从他们产生以来除了增加了色彩信号的新参数之外没有太大的变化。NTSC信号是不能直接兼容于计算机系统的。
NTSC电视全屏图像的每一帧有525条水平线。这些线是从左到右从上到下排列的。每隔一条线是跳跃的。所以每一个完整的帧需要扫描两次屏幕:第一次扫描是奇数线,另一次扫描是偶数线。每次半帧屏幕扫描需要大约1/60秒;整帧扫描需要1/30秒。这种隔行扫描系统也叫interlacing(也是隔行扫描的意思)。适配器可以把NTSC信号转换成为计算机能够识别的数字信号。相反地还有种设备能把计算机视频转成NTSC信号,能把电视接收器当成计算机显示器那样使用。但是由于通用电视接收器的分辨率要比一台普通显示器低,所以即使电视屏幕再大也不能适应所有的计算机程序。
近几年,行业里迫切的需要采用一套新的电视标准。有种提议使用协议是高清晰电视(HDTV)。HDTV标准可以完全的被计算机系统直接兼容。然而仍然有些设计上的问题没有解决。有些业内专家担心这样的兼容性会严重增加通用电视机的成本。
PAL制式是电视广播中色彩编码的一种方法,全名为 Phase Alternating Line 逐行倒相。它是西德在1962年指定的彩色电视广播标准,它采用逐行倒相正交平衡调幅的技术方法,克服了NTSC制相位敏感造成色彩失真的缺点。西德、英国等一些西欧国家,新加坡、中国大陆及香港,澳大利亚、新西兰等国家采用这种制式。PAL由德国人Walter Bruch在1967年提出,当时他是为德律风根(Telefunken)工作。“PAL”有时亦被用来指625 线,每秒25格,隔行扫描, PAL色彩编码的电视制式。PAL制式中根据不同的参数细节,又可以进一步划分为G、I、D等制式,其中PAL-D制是我国大陆采用的制式
argv: 指针的指针
argc: 整数
char **argv or char *argv[] or char argv[][]
为了能形象的说明这两个参数的含义,我们先用一个实例来进行讲解:
假设程序的名称为test,当只输入test,则由操作系统传来的参数为:
argc = 1,表示只有一程序名称;
argc只有一个元素,argv[0]指向输入的程序路径及名称:./ test
当输入test para_1,有一个参数,则由操作系统传来的参数为:
argc = 2,表示除了程序名外还有一个参数;
argv[0]指向输入的程序路径及名称;
argv[1]指向参数para_1字符串
当输入test para_1 para_2 有2个参数,则由操作系统传来的参数为:
argc = 3,表示除了程序名外还有两个参数;
argv[0]指向输入的程序路径及名称;
argv[1]指向参数para_1字符串;
argv[2]指向参数para_2字符串;
以此类推………………
void main( int argc, char *argv[] )
char *argv[]: argv是一个指针数组,元素个数是argc,存放的是指向每一个参数的指针,第一个元素即argv[0]为程序运行的全路径名,从二个元素(argv[1])开始,是每一个参数的名称,最后一个元素为NULL。总的来说,即:
* argv: 字符串数组
argv[0] 为程序运行的全路径名
argv[1] 为执行程序名后的第一个字符串;
argv[2] 为执行程序名后的第二个字符串;
...
argv[argc]为NULL。
int argc: 表示argv的大小,是实际参数个数+1,其中+1是因为argv[0]是编译后的可执行文件名
main() 参数 :
Turbo C2.0启动时总是把argc、argv、env(存放环境变量)这三个参数传递给main()函数, 可以在用户程序中说明(或不说明)它们, 如果说明了部分(或全部)参数, 它们就成为main()子程序的局部变量。
请注意: 一旦想说明这些参数, 则必须按argc, argv, env 的顺序, 如以下的例子:
main()
main(int argc)
main(int argc, char *argv[])
main(int argc, char *argv[], char *env[])
其中第二种情况是合法的, 但不常见, 因为在程序中很少有只用argc, 而不
用argv[]的情况。
以下提供一样例程序EXAMPLE.EXE, 演示如何在main()函数中使用三个参数:
#include <stdio.h>
#include <stdlib.h>
main(int argc, char *argv[], char *env[])
{
int i;
printf( "These are the %d command- line arguments passed to
main:\n\n", argc);
for( i = 0; i <= argc; i++)
printf( "argv[%d]:%s\n", i, argv[i] );
printf( "\nThe environment string(s)on this system are:\n\n");
for( i = 0; env[i] != NULL; i++ )
printf( " env[%d]:%s\n", i, env[i] );
}
./EXAMPLE first "I’m a good boy" c "last " stop
注意: 可以用双引号括起内含空格的参数, 如本例中的: " argument with blanks"和"Last but one")。
结果是这样的:
These are the 6 command-linearguments passed to main:
argv[0]:./ EXAMPLE
argv[1]:first
argv[2]: I’m a good boy
argv[3]:c
argv[4]: last
argv[5]:stop
argv[6]:(NULL)
Source Insight实质上是一个支持多种开发语言(java,c ,c 等等)的编辑器,只不过由于其查找、定位、彩色显示等功能的强大,常被我们当成源代码阅读工具使用。
作为一个开放源代码的操作系统,Linux附带的源代码库使得广大爱好者有了一个广泛学习、深入钻研的机会,特别是Linux内核的组织极为复杂,同时,又不能像windows平台的程序一样,可以使用集成开发环境通过察看变量和函数,甚至设置断点、单步运行、调试等手段来弄清楚整个程序的组织结构,使得Linux内核源代码的阅读变得尤为困难。
当然Linux下的vim和emacs编辑程序并不是没有提供变量、函数搜索,彩色显示程序语句等功能。它们的功能是非常强大的。比如,vim和emacs就各自内嵌了一个标记程序,分别叫做ctag和etag,通过配置这两个程序,也可以实现功能强大的函数变量搜索功能,但是由于其配置复杂,linux附带的有关资料也不是很详细,而且,即使建立好标记库,要实现代码彩色显示功能,仍然需要进一步的配置(在另一片文章,我将会讲述如何配置这些功能),同时,对于大多数爱好者来说,可能还不能熟练使用vim和emacs那些功能比较强大的命令和快捷键。
为了方便的学习Linux源程序,我们不妨回到我们熟悉的window环境下,也算是“师以长夷以制夷”吧。但是在Window平台上,使用一些常见的集成开发环境,效果也不是很理想,比如难以将所有的文件加进去,查找速度缓慢,对于非Windows平台的函数不能彩色显示。于是笔者通过在互联网上搜索,终于找到了一个强大的源代码编辑器,它的卓越性能使得学习Linux内核源代码的难度大大降低,这便是Source Insight3.0,它是一个Windows平台下的共享软件,可以从 http://www.sourceinsight.com/上边下载30天试用版本。由于Source Insight是一个Windows平台的应用软件,所以首先要通过相应手段把Linux系统上的程序源代码弄到Windows平台下,这一点可以通过在linux平台上将/usr/src目录下的文件拷贝到Windows平台的分区上,或者从网上光盘直接拷贝文件到Windows平台的分区来实现。
下面主要讲解如何使用Source Insight,考虑到阅读源程序的爱好者都有相当的软件使用水平,本文对于一些琐碎、人所共知的细节略过不提,仅介绍一些主要内容,以便大家能够很快熟练使用本软件,减少摸索的过程。
安装Source Insight并启动程序,可以进入图1界面。在工具条上有几个值得注意的地方,如图所示,图中内凹左边的是工程按钮,用于显示工程窗口的情况;右边的那个按钮按下去将会显示一个窗口,里边提供光标所在的函数体内对其他函数的调用图,通过点击该窗体里那些函数就可以进入该函数所在的地方。
图1 Source Insight界面图
由于Source Insight实质上是一个支持多种开发语言(java,c ,c++等等)的编辑器,只不过由于其查找、定位、彩色显示等功能的强大,而被我们当成源代码阅读工具使用。所以,为了有效的阅读源程序,首先必须选择功能菜单上的 “Project”选项的子菜单“New Project”新建一个项目,项目名称可以自由选定,当然也可以选择删除(Remove)一个项目。当删除一个项目的时候,并不删除原有的源代码文件,只是将该软件生成的那些工程辅助文件删除。设定之后,将会弹出一个对话框如图2,接受默认选择,如果,硬盘空间足够,可以将第一个复选框选上,该选项将会需要与源代码大致同等的空间来建立一个本地数据库以加快查找的速度。
图2 工程设置
点击“OK”按钮,接受选择后,将会有一个新的对话框弹出,在这个对话框里,可以选择将要阅读的文件加入工程,一种方式是通过在File Name中输入要阅读源代码文件的名称,点击“Add”按钮将其加入,也可以通过其中“Add All”和“Add Tree”两个按钮可以将选中目录的所有文件加入到工程中,其中“Add All”选项会提示加入顶层文件和递归加入所有文件两种方式,而“Add Tree”相当于“Add All”选项的递归加入所有文件,可以根据需要使用,就我来说,更喜欢“Add Tree”一些。由于该程序采用了部分打开文件的方式,没有用到的文件不会打开,所以,加入数千个文件也不用担心加入的文件超出程序的所能容忍的最大值,我就是采用“Add Tree”的方式将Linux2.4内核的四千五百九十一个文件加入的。
图3 添加文件
加入文件后,点击一个文件,可以出现使用界面,如图4所示,其中,右边的那个窗口(Linux Project,即工程窗口)缺省按照字母顺序列出当前工程中所有的文件。
图4 工作窗口
点击一个文件就可以打开该文件,显示如图5所示,进入到右边的那个窗口分别可以以文件列表的方式,列出所有的文件,每个窗体下边有一排按钮,左边的窗口(21142.c)从左至右分别为:按字母顺序排列所有标记、按照文件中行数顺序排列标记、按照类型排列标记、浏览本地文件标记、标记窗口属性。右边的窗口(Linux Project)从左至右分别为:按字母顺序文件列表、显示文件夹、按照文件类型归类文件、全部文件的所有标记列表、按照标记类型归类标记、跳转到定义处、显示标记信息、浏览工程标记、查找函数调用、工程属性,其中全部文件的所有标记列表选项可能要一段时间抽取标记,同步到数据库去,如果开始选择了建立标记数据库,将会在今后节省同步时间,最有用的莫过于浏览标记信息和查找函数调用,前者可以通过“Jump”按钮在不同的地方查找同样的标志,还可以通过“Reference”按钮结合后者进行全局的标记查找。
Reference功能是Source Insight的特色之一,它可以在速度极快的在整个工程中找到所有的标记,并且在该行程序的前边加上红色箭头的小按钮链接上。图6是一个Reference搜索后的结果,它可以有两种模式,一种集中显示结果,图6显示的就是这种模式,在这种模式下,可以通过前边的红色箭头小按钮进入另外一种模式,该标记的具体的所在处,也可以通过标记的具体所在处点击红色箭头小按钮进入警种模式,还可以通过工具条上的两个红色小箭头直接在第二种模式下前后移动,察看相应信息。它的这个强大的功能使得阅读Linux源程序有如神助。但是要注意的是,当进行了第二次“Reference”时,它会提示你将结果集附加在第一个结果集的后边还是取代第一个结果集。如果选择前者,不能对结果集根据前后两次搜索结果进行分类,然后在其子类里进行移动,只能在整个结果集里移动;如果,选择后者,结果集将会被替换为第二次搜索的结果,略微有些不方便。
图6 Reference的搜索结果
Source Insight设置
1、背景色选择
要改变背景色Options->preference->windows background->color设置背景色
2、解决字符等宽对齐问题。
SIS默认字体是VERDANA,很漂亮。这网页上应该也是用的VERDANA字体。但由于美观的缘故,VERDANA字体是不等宽的。比如下面两行
llllllllll
MMMMMMMMMM
同样10个字符,长度差多了.用VERDANA来看程序,有些本应该对齐的就歪了。解放方法是使用等宽的字体,但肯定比较丑。比较推荐的是用Courier New。
3、解决TAB键缩进问题
Options-> Document Options里面的右下角Editing Options栏里,把Expand tabs勾起来,然后确定。OK,现在TAB键的缩进和四个空格的缩进在SIS里面看起来就对齐咯
4、SI中的自动对齐设置:
在C程序里, 如果遇到行末没有分号的语句,如IF, WHILE, SWITCH等, 写到该行末按回车,则新行自动相对上一行缩进两列。
Option->Document option下的Auto Indient中Auto Indient Type有三种类型 None,Simple,Smart。个人推荐选用Simple类型。
5、向项目中添加文件时,只添加特定类型的文件(文件类型过滤器)
编辑汇编代码时,在SIS里建立PROJECT并ADD TREE的时候,根据默认设置并不会把该TREE里面所有汇编文件都包含进来
只加了.inc和.asm后缀的,.s后缀的没有。而且用SIS打开.s的文件,一片黑白没有色彩,感觉回到DOS的EDIT时代了……
解决方法是在Options->Document Options里面,点左上的Document Type下拉菜单,选择x86 Asm Source File,
然后在右边的File filter里*.asm;*.inc;的后面加上*.s;接着CLOSE就可以了。
上面问题解决了,但注意加入*.s后还需要重新ADD TREE一遍才能把这些汇编加到PROJECT里面。
6、添加文件类型
用户可以定义自己的类型,Options->Document Options->add type,定义文件类型名以及文件名后缀。
勾选include when adding to projects在添加目录下文件到工程是该类文件就会添加进SI的工程。
如果需要将所有文件添加进SI的工程,可以定义一种文件类型*.*。
7、恢复ctrl+a的全选功能
通过关键词save 找到save all,更改为ctrl+shift+a,通过关键词select找到select all,更改为ctrl +a
Source Insight常用的快捷键:
Ctrl+= :Jump to definition
Alt+/ :Look up reference
F3 : search backward
F4 : search forward
F5: go to Line
F7 :Look up symbols
F8 :Look up local symbols
F9 :Ident left
F10 :Ident right
Alt+, :Jump backword
Alt+. : Jump forward
Shift+F3 : search the word under cusor backward
Shift+F4 : search the word under cusor forward
F12 : incremental search
Shift+Ctrl+f: search in project
shift+F8 : hilight word
Source Insight的窗口操作:
project window Ctrl+O打开
symbol window Alt+F8打开和关闭
Contex Window 自定义键打开和关闭
Relation Window 自定义键打开 先锁定再刷新联系
在Source Insight中添加自定义功能的步骤如下:
1.Source Insight中,Options->Custom Commands...->Add...,New Command name 随便写,我的是"Edit with Vim"
2.Run中写入: "C:\Program Files\Vim\vim63\gvim.exe" --remote-silent +%l %f
意思是在当前已经打开的gvim窗口里面打开当前的文件,并且跳转到指定行
%l为当前的行号,%f为文件名
使用 --remote-silent 的作用是,如果已经打开了对应文件,就不会打开第二次,而是在已经打开的文件里跳转到对应行
3.还是同一个对话框里面,选择Keys->Assign New Key...->按F12,如果你已经将F12设置给其他命令,选择其他的按键就行了
下面是一些常用自定义功能:( CUSTOM COMMANDS )
打开资源管理器并选中当前文件
ShellExecute open explorer /e,/select,%f
查看log
"C:\Program Files\TortoiseSVN\bin\TortoiseProc.exe" /command:log /path:%f /notempfile /closeonend
diff
"C:\Program Files\TortoiseSVN\bin\TortoiseProc.exe" /command:diff /path:%f /notempfile /closeonend
取得锁定(check out)
"C:\Program Files\TortoiseSVN\bin\TortoiseProc.exe" /command:lock /path:%f /notempfile /closeonend
提交(check in)
"C:\Program Files\TortoiseSVN\bin\TortoiseProc.exe" /command:commit /path:%f /notempfile /closeonend
更新(update)
"C:\Program Files\TortoiseSVN\bin\TortoiseProc.exe" /command:update /path:%f /notempfile /closeonend
更新整个目录(update all)
"C:\Program Files\TortoiseSVN\bin\TortoiseProc.exe" /command:update /path:*.* /notempfile /closeonend
取消锁定(undo check out)
"C:\Program Files\TortoiseSVN\bin\TortoiseProc.exe" /command:revert /path:%f /notempfile /closeonend
在ultriEdit中编辑
"C:\Program Files\UltraEdit-32/uedit32" %f
在vim中编辑并定位到当前行
"C:\Program Files\Vim\vim63\gvim.exe" --remote-silent +%l %f
汇总其他小技巧:
让{ 和 } 不缩进:
Options->Document Options->Auto Indent->Indent Open Brace/Indent Close Brace
hao space: SourceInsight 小技巧
1、按住"ctrl", 再用鼠标指向某个变量,点击一下,就能进入这个变量的定义。
2、今天把一个用sourceinsight排版整齐的C文件,偶然用VC打开一看,全乱了。研究了半天,发现SI对每个字符的宽度不太一致。
请教同事发现选上"view --> draft view", 就可以让每个字符的宽度一致了。快捷键是 "Alt + F12"
3、"shift+F8" 标亮所有文本中光标所在位置的单词
4、跳到某一行:"ctrl + g"
Source Insight是阅读和编写代码的好东东,基本上也算得上是经典之作了,虽然还有一点点小bug,不过对于我们这些C程序员来说可是一旦拥有别无所求。下 列小技巧是在工作中同事整理总结的,对提高工作效率多少有点帮助,其中有些是对应于SVN的,没有使用SVN做版本管理的人就不要白费力气了。
ShellExecute open explorer /e,/select,%f
/*作用是在资源管理器中打开当前编辑文件并选中*/
/*可以设置快捷键如ctrl+e,这样能很方便的在资源管理器打开对应的文件,并进行tortoiseSVN的相关操作*/
X:\Progra~1\TortoiseSVN\bin\TortoiseProc.exe /command:log /path:% /notempfile /closeonend
/*使用前注意更改对应的bin安装路径*/
/*作用是直接查看当前文件的svn log*/
/*可以设置快捷键如ctrl+l*/
X:\Progra~1\TortoiseSVN\bin\TortoiseProc.exe /command:diff /path:% /notempfile /closeonend
/*使用前注意更改对应的bin安装路径*/
/*作用是直接查看当前文件和基准版本的比较*/
/*可以设置快捷键如ctrl+d*/
一般用于将C++代码以标准C形式输出(即以C的形式被调用),这是因为C++虽然常被认为是C的超集,但是C++的编译器还是与C的编译器不同的。C中调用C++中的代码这样定义会是安全的。
一般的考虑跨平台使用方法如下:
#ifdefined(__cplusplus)||defined(c_plusplus) //跨平台定义方法
extern "C"{
#endif
//... 正常的声明段
#ifdefined(__cplusplus)||defined(c_plusplus)
}
#endif
简单的用在windows下可以如下定义:
#ifdef __cplusplus
extern "C"{
//... 正常的声明段
}
#endif
1. 信号概念
信号是进程在运行过程中,由自身产生或由进程外部发过来的消息(事件)。信号是硬件中断的软件模拟(软中断)。每个信号用一个整型常量宏表示,以SIG开头,比如SIGCHLD、SIGINT等,它们在系统头文件中定义,也可以通过在shell下键入kill –l查看信号列表,或者键入man 7 signal查看更详细的说明。
信号的生成来自内核,让内核生成信号的请求来自3个地方:
l 用户:用户能够通过输入CTRL+c、Ctrl+,或者是终端驱动程序分配给信号控制字符的其他任何键来请求内核产生信号;
l 内核:当进程执行出错时,内核会给进程发送一个信号,例如非法段存取(内存访问违规)、浮点数溢出等;
l 进程:一个进程可以通过系统调用kill给另一个进程发送信号,一个进程可以通过信号和另外一个进程进行通信。
由进程的某个操作产生的信号称为同步信号(synchronous signals),例如除0;由象用户击键这样的进程外部事件产生的信号叫做异步信号。(asynchronous signals)。
进程接收到信号以后,可以有如下3种选择进行处理:
l 接收默认处理:接收默认处理的进程通常会导致进程本身消亡。例如连接到终端的进程,用户按下CTRL+c,将导致内核向进程发送一个SIGINT的信号,进程如果不对该信号做特殊的处理,系统将采用默认的方式处理该信号,即终止进程的执行;
l 忽略信号:进程可以通过代码,显示地忽略某个信号的处理,例如:signal(SIGINT,SIGDEF);但是某些信号是不能被忽略的,
l 捕捉信号并处理:进程可以事先注册信号处理函数,当接收到信号时,由信号处理函数自动捕捉并且处理信号。
有两个信号既不能被忽略也不能被捕捉,它们是SIGKILL和SIGSTOP。即进程接收到这两个信号后,只能接受系统的默认处理,即终止线程。
2. signal信号处理机制
可以用函数signal注册一个信号捕捉函数。原型为:
#include
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
signal 的第1个参数signum表示要捕捉的信号,第2个参数是个函数指针,表示要对该信号进行捕捉的函数,该参数也可以是SIG_DEF(表示交由系统缺省处理,相当于白注册了)或SIG_IGN(表示忽略掉该信号而不做任何处理)。signal如果调用成功,返回以前该信号的处理函数的地址,否则返回 SIG_ERR。
sighandler_t是信号捕捉函数,由signal函数注册,注册以后,在整个进程运行过程中均有效,并且对不同的信号可以注册同一个信号捕捉函数。该函数只有一个参数,表示信号值。
示例:
1、 捕捉终端CTRL+c产生的SIGINT信号:
#include
#include
#include
#include
void SignHandler(int iSignNo)
{
printf("Capture sign no:%d ",iSignNo);
}
int main()
{
signal(SIGINT,SignHandler);
while(true)
sleep(1);
return 0;
}
该程序运行起来以后,通过按 CTRL+c将不再终止程序的运行。应为CTRL+c产生的SIGINT信号已经由进程中注册的SignHandler函数捕捉了。该程序可以通过 Ctrl+终止,因为组合键Ctrl+能够产生SIGQUIT信号,而该信号的捕捉函数尚未在程序中注册。
2、 忽略掉终端CTRL+c产生的SIGINT信号:
#include
#include
#include
#include
int main()
{
signal(SIGINT,SIG_IGN);
while(true)
sleep(1);
return 0;
}
该程序运行起来以后,将CTRL+C产生的SIGINT信号忽略掉了,所以CTRL+C将不再能是该进程终止,要终止该进程,可以向进程发送SIGQUIT信号,即组合键CTRL+
3、 接受信号的默认处理,接受默认处理就相当于没有写信号处理程序:
#include
#include
#include
#include
int main()
{
signal(SIGINT,DEF);
while(true)
sleep(1);
return 0;
}
3. sigaction信号处理机制
3.1. 信号处理情况分析
在signal处理机制下,还有许多特殊情况需要考虑:
1、 册一个信号处理函数,并且处理完毕一个信号之后,是否需要重新注册,才能够捕捉下一个信号;
2、 如果信号处理函数正在处理信号,并且还没有处理完毕时,又发生了一个同类型的信号,这时该怎么处理;
3、 如果信号处理函数正在处理信号,并且还没有处理完毕时,又发生了一个不同类型的信号,这时该怎么处理;
4、 如果程序阻塞在一个系统调用(如read(...))时,发生了一个信号,这时是让系统调用返回错误再接着进入信号处理函数,还是先跳转到信号处理函数,等信号处理完毕后,系统调用再返回。
示例:
#include
#include
#include
#include
int g_iSeq=0;
void SignHandler(int iSignNo)
{
int iSeq=g_iSeq++;
printf("%d Enter SignHandler,signo:%d. ",iSeq,iSignNo);
sleep(3);
printf("%d Leave SignHandler,signo:%d ",iSeq,iSignNo);
}
int main()
{
char szBuf[8];
int iRet;
signal(SIGINT,SignHandler);
signal(SIGQUIT,SignHandler);
do{
iRet=read(STDIN_FILENO,szBuf,sizeof(szBuf)-1);
if(iRet<0){
perror("read fail.");
break;
}
szBuf[iRet]=0;
printf("Get: %s",szBuf);
}while(strcmp(szBuf,"quit ")!=0);
return 0;
}
程序运行时,针对于如下几种输入情况(要输入得快),看输出结果:
1、 CTRL+c] [CTRL+c] [CTRL+c]
2、 [CTRL+c] [CTRL+]
3、 hello [CTRL+] [Enter]
4、 [CTRL+] hello [Enter]
5、 hel [CTRL+] lo[Enter]
针对于上面各种情况,不同版本OS可能有不同的响应结果。
3.2. sigaction信号处理注册
如果要想用程序控制上述各种情况的响应结果,就必须采用新的信号捕获机制,即使用sigaction信号处理机制。
函数原型:
#include
int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
sigaction也用于注册一个信号处理函数。
参数signum为需要捕捉的信号;
参数 act是一个结构体,里面包含信号处理函数地址、处理方式等信息。
参数oldact是一个传出参数,sigaction函数调用成功后,oldact里面包含以前对signum的处理方式的信息。
如果函数调用成功,将返回0,否则返回-1
结构体 struct sigaction(注意名称与函数sigaction相同)的原型为:
struct sigaction {
void (*sa_handler)(int); // 老类型的信号处理函数指针
void (*sa_sigaction)(int, siginfo_t *, void *);//新类型的信号处理函数指针
sigset_t sa_mask; // 将要被阻塞的信号集合
int sa_flags; // 信号处理方式掩码
void (*sa_restorer)(void); // 保留,不要使用。
}
该结构体的各字段含义及使用方式:
1、字段sa_handler是一个函数指针,用于指向原型为void handler(int)的信号处理函数地址, 即老类型 的信号处理函数;
2、字段sa_sigaction也是一个函数指针,用于指向原型为:
void handler(int iSignNum,siginfo_t *pSignInfo,void *pReserved);
的信号处理函数,即新类型的信号处理函数。
该函数的三个参数含义为:
iSignNum :传入的信号
pSignInfo :与该信号相关的一些信息,它是个结构体
pReserved :保留,现没用
3、字段sa_handler和sa_sigaction只应该有一个生效,如果想采用老的信号处理机制,就应该让sa_handler指向正确的信号处理函数;否则应该让sa_sigaction指向正确的信号处理函数,并且让字段 sa_flags包含SA_SIGINFO选项。
4、字段sa_mask是一个包含信号集合的结构体,该结构体内的信号表示在进行信号处理时,将要被阻塞的信号。针对sigset_t结构体,有一组专门的函数对它进行处理,它们是:
#include
int sigemptyset(sigset_t *set); // 清空信号集合set
int sigfillset(sigset_t *set); // 将所有信号填充进set中
int sigaddset(sigset_t *set, int signum); // 往set中添加信号signum
int sigdelset(sigset_t *set, int signum); // 从set中移除信号signum
int sigismember(const sigset_t *set, int signum); // 判断signnum是不是包含在set中
例如,如果打算在处理信号SIGINT时,只阻塞对SIGQUIT信号的处理,可以用如下种方法:
struct sigaction act;
sigemptyset(&act.sa_mask);
sigaddset(&act_sa_mask,SIGQUIT);
sigaction(SIGINT,&act,NULL);
5、 字段sa_flags是一组掩码的合成值,指示信号处理时所应该采取的一些行为,各掩码的含义为:
掩码 描述
SA_RESETHAND 处理完毕要捕捉的信号后,将自动撤消信号处理函数的注册,即必须再重新注册信号处理函数,才能继续处理接下来产生的信号。该选项不符合一般的信号处理流程,现已经被废弃。
SA_NODEFER 在处理信号时,如果又发生了其它的信号,则立即进入其它信号的处理,等其它信号处理完毕后,再继续处理当前的信号,即递规地处理。如果sa_flags包含了该掩码,则结构体sigaction的sa_mask将无效!
SA_RESTART 如果在发生信号时,程序正阻塞在某个系统调用,例如调用read()函数,则在处理完毕信号后,接着从阻塞的系统返回。该掩码符合普通的程序处理流程,所以一般来说,应该设置该掩码,否则信号处理完后,阻塞的系统调用将会返回失败!
SA_SIGINFO 指示结构体的信号处理函数指针是哪个有效,如果sa_flags包含该掩码,则sa_sigactiion指针有效,否则是sa_handler指针有效。
我的混乱
1.。。可执行cgi文件在超级终端可以运行,但是用浏览器访问服务器时 前后出现了莫名其妙的乱码错误
2.。。表单以action=http://192.168.1.230/cgi-bin/...cgi 提交之后不能运行 ...cgi 但是直接在网
址中输入http://192.168.1.230/cgi-bin/...cgi 可以运行 (依然是乱码匆匆)(两种连接的地址栏中
是一样的地址)
3.。。为什么别人的可以顺利运行我的不行
I HATE IT !!!
首先声明 :这是我借鉴别人联合自己的交叉编译经验做改动而来的
1。# tar zxvf sqlite-3.3.7.tar.gz
#cd /usr/local/arm-linux/sqlite-3.3.7
新建一个sqlite-arm-linux目录
2.# mkdir /usr/local/arm-linux/sqlite-arm-linux
3.# cd /usr/local/arm-linux/sqlite-arm-linux
# export PATH=/usr/local/arm-linux/bin:$PATH
4.#../sqlite-3.3.7/configure --host=arm-linux --prefix=/usr/local/arm-linux/sqlite-arm-linux
这部会出现下面的错误:
configure: error: unable to find a compiler for building build tools
这个错误的解决方法是:
首先,我们进入目录usr/local/arm-linux/sqlite-1.3.7,打开其中的configure文件,用查找功能找到下列语句:
(用 test "$cross_compiling" = yes &&进行搜索)
# test "$cross_compiling" = yes &&
# { { echo "$as_me:13264: error: cannot check for file existence when cross compiling" >&5
#echo "$as_me: error: cannot check for file existence when cross compiling" >&2;}
# { (exit 1); exit 1; }; }
把其中的{ (exit 1); exit 1; }; }改为 { (echo 1); echo 1; }; }
一共有两处,都改过来。
然后,我们要设置config_TARGET_CC和config_BUILD_CC两个环境变量。config_TARGET_CC是交叉编译器,config_BUILD_CC是主机编译器。重来:
#export config_BUILD_CC=gcc
#export config_TARGET_CC=arm-linux-gcc
下面重新编译就可以了
#../sqlite-3.3.7/configure --host=arm-linux --prefix=/usr/local/arm-linux/sqlite-arm-linux
然后我们会发现在在/usr/local/arm-linux/sqlite-arm-linux目录下生成一些相关文件: config.log config.status libtool Makefile sqlite3.pc
如果:还是出现如下同样的错误
checking for /usr/include/readline.h... configure: error: cannot check for file existence when cross compiling
那么 首先 : 你检查你的交叉编译环境 错误?? 如果真的没有则安装readline.h 在ubuntu的软件中心查找libncurses5-dev libreadline5-dev进行安装
如果安装之后从新。/conigure还是有这个错误 那就不管了 我不知道了但是还是生成了makefile文件!
下面在make之前我们修改一下Makefile文件,把其中的BCC = arm-linux-gcc -g -O2 为 BCC = gcc -g -O2
#make
#make install
会出现这样的话语:libsqlite3.so.0.8.6: ELF 32-bit LSB shared object, ARM, version 1 (ARM), not stripped
over !!!
本人ubuntu又连上了网
说明: 开始 为了让虚拟机中得ubuntu能用串口连接上ARM 板,本人对虚拟机添加串口,设为自动使用物理机串口,设置完后vm提示没有多余的串口之类的,接着ubuntu就不能联网了,
后来,把添加的串口删除掉仍然不能上网,
最后 折腾很久vm中得fedora可以上但ubuntu就是不能上 ,
没办法 把vm重装了一遍 ,然后
1.vm中vm-》setting -》network adapter-》nat
2.vm中edit-》virturenetworkeditor把vmnet0设置为host only 并且勾选最下方的两个 确定
同时把 vmnet8 设置成nat同时勾选最下方的两列 确认
3.打开ubunu ifconfig 可见
eth0 Link encap:Ethernet HWaddr 00:0c:29:05:48:93
inet addr:192.168.188.128 Bcast:192.168.188.255 Mask:255.255.255.0
inet6 addr: fe80::20c:29ff:fe05:4893/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:18 errors:0 dropped:0 overruns:0 frame:0
TX packets:69 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:2134 (2.1 KB) TX bytes:10542 (10.5 KB)
Interrupt:19 Base address:0x2024
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:16436 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
联网成功
由上可见etho联网成功
但是lo并没有 在、etc/network/interfaces 里面可见
auto lo
iface lo inet loopback
原来 lo是本地回环地址 在ping127.0.0.1 时被使用到
在ubuntu中安装arm-linux-gcc-4.3.2
1.把arm-linux-gcc-4.3.2压缩文件拷贝到tmp文件夹下面
(arm 文件夹是自己建立的在终端使用命令 mkdir arm建立注意是在 /usr/local/目录下)
解压的时候 tar zxvf arm-linux-gcc-4.3.2 -C / c要大些而且后面还有一个空格,否则解压过程中会自动的建立目录/usr/local/arm/
2.修改配置文件,就是建立路径 打开/etc/bashrc文件(linux下的系统环境变量) ,(如果不能修改应该是权限问题,修改权限就行,chmod命令进行修改)在文件的末尾加上export PATH=$PATH:/usr/local/arm/
4.3.2/bin 亲中4.3.2文件夹是我解压之后的文件夹, 到此就完成了安装。
3.测试 arm-linux-gcc -v 查看到了版本的就表示安装成功
说明: 本人初学,不是很懂。看到网上交叉编译方法很多,简易各不相同,如有不同或者错误请多指点!!