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目录下