4. `./configure --build=mipsel-linux --host=i386-linux
--target=mipsel-linux' will cross-build mipsel-linux cross-binutils for
i386-linux on mipsel-linux.
說明我們利用mipsel-linux的編譯器對binutils進行編譯,編譯出來的binutils運行在i386-linux,這個binutils用來編譯能夠在mipsel-linux運行的代碼。“這個選項可以用來在i386主機上建立一個mipsel-linux的交叉編譯環(huán)境,但是交叉編譯環(huán)境在mipsel-linux 編譯出來,安裝到i386-linux主機上,估計沒有多少人會這么用吧”
總的來說,只有host !=build的時候編譯才是交叉編譯。否則就是正常編譯。
1. NAT分類
根據(jù)Stun協(xié)議(RFC3489),NAT大致分為下面四類
http://blog.csdn.net/ronmy/category/819006.aspx
1) Full Cone
這種NAT內(nèi)部的機器A連接過外網(wǎng)機器C后,NAT會打開一個端口.然后外網(wǎng)的任何發(fā)到這個打開的端口的UDP數(shù)據(jù)報都可以到達A.不管是不是C發(fā)過來的.
例如 A:192.168.8.100 NAT:202.100.100.100 C:292.88.88.88
A(192.168.8.100:5000) -> NAT(202.100.100.100 : 8000) -> C(292.88.88.88:2000)
任何發(fā)送到 NAT(202.100.100.100:8000)的數(shù)據(jù)都可以到達A(192.168.8.100:5000)
2) Restricted Cone
這種NAT內(nèi)部的機器A連接過外網(wǎng)的機器C后,NAT打開一個端口.然后C可以用任何端口和A通信.其他的外網(wǎng)機器不行.
例如 A:192.168.8.100 NAT:202.100.100.100 C:292.88.88.88
A(192.168.8.100:5000) -> NAT(202.100.100.100 : 8000) -> C(292.88.88.88:2000)
任何從C發(fā)送到 NAT(202.100.100.100:8000)的數(shù)據(jù)都可以到達A(192.168.8.100:5000)
3) Port Restricted Cone
這種NAT內(nèi)部的機器A連接過外網(wǎng)的機器C后,NAT打開一個端口.然后C可以用原來的端口和A通信.其他的外網(wǎng)機器不行.
例如 A:192.168.8.100 NAT:202.100.100.100 C:292.88.88.88
A(192.168.8.100:5000) -> NAT(202.100.100.100 : 8000) -> C(292.88.88.88:2000)
C(202.88.88.88:2000)發(fā)送到 NAT(202.100.100.100:8000)的數(shù)據(jù)都可以到達A(192.168.8.100:5000)
以上三種NAT通稱Cone NAT.我們只能用這種NAT進行UDP打洞.
4) Symmetic
對于這種NAT.連接不同的外部目標.原來NAT打開的端口會變化.而Cone NAT不會.雖然可以用端口猜測.但是成功的概率很小.因此放棄這種NAT的UDP打洞.
2. UDP hole punching
對于Cone NAT.要采用UDP打洞.需要一個公網(wǎng)機器C來充當”介紹人”.內(nèi)網(wǎng)的A,B先分別和C通信.打開各自的NAT端口.C這個時候知道A,B的公網(wǎng)IP: Port. 現(xiàn)在A和B想直接連接.比如A給B發(fā).除非B是Full Cone.否則不能通信.反之亦然.但是我們可以這樣.
A要連接B.A給B發(fā)一個UDP包.同時.A讓那個介紹人給B發(fā)一個命令,讓B同時給A發(fā)一個UDP包.這樣雙方的NAT都會記錄對方的IP,然后就會允許互相通信.
3. 同一個NAT后面的情況
如果A,B在同一個NAT后面.如果用上面的技術(shù)來進行互連.那么如果NAT支持loopback(就是本地到本地的轉(zhuǎn)換),A,B可以連接,但是比較浪費帶寬和NAT.有一種辦法是,A,B和介紹人通信的時候,同時把自己的local IP也告訴服務(wù)器.A,B通信的時候,同時發(fā)local ip和公網(wǎng)IP.誰先到就用哪個IP.但是local ip就有可能不知道發(fā)到什么地方去了.比如A,B在不同的NAT后面但是他們各自的local ip段一樣.A給B的local IP發(fā)的UDP就可能發(fā)給自己內(nèi)部網(wǎng)里面的某某某了.
還有一個辦法是服務(wù)器來判斷A,B是否在一個NAT后面.(網(wǎng)絡(luò)拓樸不同會不會有問題?)
本文出自 “淡泊明志,寧靜致遠” 博客,請務(wù)必保留此出處http://keren.blog.51cto.com/720558/170822
程序描述:
打開一個文件描述符,分別適用dup和賦值語句進行復(fù)制,復(fù)制之后,打印原始和被復(fù)制的文件描述符id,看看是否具有相同的值,然后關(guān)閉文件,測試關(guān)閉是否成功。
程序示例:
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
int sys_err(char *str)
{
puts(str);
exit(0);
}
int main(void)
{
int p,q;
if((p=open("c_fid.c", O_RDONLY)) == -1)
sys_err("open error");
q = dup(p);
puts("dup:");
printf("file p,q fd is:%d %d\n", q, p);
printf("close file p ok?: %d\n", close(p));
printf("close file q ok?: %d\n", close(q));
if((p=open("c_fid.c", O_RDONLY)) == -1)
sys_err("open error");
q = p;
puts("=:");
printf("file p,q fd is:%d %d\n", q, p);
printf("close file p ok?: %d\n", close(p));
printf("close file q ok?: %d\n", close(q));
return 0;
}
程序運行結(jié)果:
dup:
file p,q fd is:4 3 //文件p,q使用不同的文件描述符
close file p ok?: 0
close file q ok?: 0 //文件關(guān)閉成功
=:
file p,q fd is:3 3 //簡單復(fù)制
close file p ok?: 0
close file q ok?: -1//關(guān)閉失敗,原因是此描述符已經(jīng)被關(guān)閉了
由此證明,dup是產(chǎn)生一個新的文件描述符id和指針在進程表項中,但是他們共用文件表,這時,關(guān)閉一個文件描述符,另外一個仍舊可用,文件表并不會被釋放。而賦值語句不同,它只是簡單的在另外一個變量中記錄原始文件指針等,2個變量的文件描述符相同,進程表項中并不產(chǎn)生新的項目。
關(guān)于socket的文件描述符
socket接口增加了網(wǎng)絡(luò)通信操作的抽象定義,與文件操作一樣,每個打開的socket都對應(yīng)一個整數(shù),我們稱它為socket描述符,該整數(shù)也是socket描述符在文件描述符表中的索引值。但socket描述符在描述符表中的表項并不指向文件表,而是指向一個與該socket有關(guān)的數(shù)據(jù)結(jié)構(gòu)。BSD UNIX中新增加了一個socket調(diào)用,應(yīng)用程序可以調(diào)用它來新建一個socket描述符,注意進程用open只能產(chǎn)生文件描述符,而不能產(chǎn)生socket描述符。socket調(diào)用只能完成建立通信的部分工作,一旦建立了一個socket,應(yīng)用程序可以使用其他特定的調(diào)用來為它添加其他詳細信息,以完成建立通信的過程。
給定了命令參數(shù)的數(shù)量 (argc
)、指向這些參數(shù)的數(shù)組 (argv
) 和選項字符串 (optstring
) 后,getopt()
將返回第一個選項,并設(shè)置一些全局變量。使用相同的參數(shù)再次調(diào)用該函數(shù)時,它將返回下一個選項,并設(shè)置相應(yīng)的全局變量。如果不再有識別到的選項,將返回 -1
,此任務(wù)就完成了。
getopt()
所設(shè)置的全局變量包括:
optarg
——指向當前選項參數(shù)(如果有)的指針。optind
——再次調(diào)用 getopt()
時的下一個 argv 指針的索引。optopt
——最后一個已知選項。 ./getopt -a -d -b foo
optind: 2
HAVE option: -a
./getopt: invalid option -- d
optind: 3
Unknown option: d
optind: 5
HAVE option: -b
The argument of -b is foo
if (execute_command) { run_init_process(execute_command); printk(KERN_WARNING "Failed to execute %s. Attempting " "defaults...\n", execute_command); } run_init_process("/sbin/init"); run_init_process("/etc/init"); run_init_process("/bin/init"); run_init_process("/bin/sh"); panic("No init found. Try passing init= option to kernel.");
mkdir /newroot/nfsroot/xxx <- 建立用戶的home 路徑
adduser xxx -d /newroot/nfsroot/xxx/ -g pnd <- 添加用戶到組
passwd wyn <- 設(shè)置用戶密碼
chown xxx:pnd /newroot/nfsroot/xxx/ <- 更改home路徑擁有者和組
echo xxx ALL=(ALL) NOPASSWD:NOPASSWD:ALL >> /etc/sudoers <- 添加sudo權(quán)限
smbpasswd -a xxx <- 添加samba 用戶
ps: /etc/samba/smb.conf 的內(nèi)容:
[global]
workgroup = TUX-NET
printing = cups
printcap name = cups
printcap cache time = 750
cups options = raw
map to guest = Bad User
include = /etc/samba/dhcp.conf
logon path = \\%L\profiles\.msprofile
logon home = \\%L\%U\.9xprofile
logon drive = P:
usershare allow guests = Yes
add machine script = /usr/sbin/useradd -c Machine -d /var/lib/nobody -s /bin/false %m$
domain logons = Yes
domain master = Yes
local master = Yes
os level = 65
preferred master = Yes
security = user
[homes]
comment = Home Directories
valid users = %S, %D%w%S
browseable = No
read only = No
inherit acls = Yes
本文來自CSDN博客,轉(zhuǎn)載請標明出處:http://blog.csdn.net/stevenliyong/archive/2009/03/12/3984926.aspx
asctime(將時間和日期以字符串格式表示) |
|
相關(guān)函數(shù) |
time,ctime,gmtime,localtime |
表頭文件
|
#include<time.h> |
定義函數(shù)
|
char * asctime(const struct tm * timeptr); |
函數(shù)說明
|
asctime()將參數(shù)timeptr所指的tm結(jié)構(gòu)中的信息轉(zhuǎn)換成真實世界所使用的時間日期表示方法,然后將結(jié)果以字符串形態(tài)返回。此函數(shù)已經(jīng)由時區(qū)轉(zhuǎn)換成當?shù)貢r間,字符串格式為:“Wed Jun 30 21:49:08 1993\n” |
返回值
|
若再調(diào)用相關(guān)的時間日期函數(shù),此字符串可能會被破壞。此函數(shù)與ctime不同處在于傳入的參數(shù)是不同的結(jié)構(gòu)。 |
附加說明
|
返回一字符串表示目前當?shù)氐臅r間日期。 |
范例
|
#include <time.h> main() { time_t timep; time (&timep); printf(“%s”,asctime(gmtime(&timep))); } |
執(zhí)行
|
Sat Oct 28 02:10:06 2000 |
|
ctime(將時間和日期以字符串格式表示) |
相關(guān)函數(shù)
|
time,asctime,gmtime,localtime |
表頭文件
|
#include<time.h> |
定義函數(shù)
|
char *ctime(const time_t *timep); |
函數(shù)說明
|
ctime()將參數(shù)timep所指的time_t結(jié)構(gòu)中的信息轉(zhuǎn)換成真實世界所使用的時間日期表示方法,然后將結(jié)果以字符串形態(tài)返回。此函數(shù)已經(jīng)由時區(qū)轉(zhuǎn)換成當?shù)貢r間,字符串格式為“Wed Jun 30 21 :49 :08 1993\n”。若再調(diào)用相關(guān)的時間日期函數(shù),此字符串可能會被破壞。 |
返回值
|
返回一字符串表示目前當?shù)氐臅r間日期。 |
范例
|
#include<time.h> main() { time_t timep; time (&timep); printf(“%s”,ctime(&timep)); } |
執(zhí)行
|
Sat Oct 28 10 : 12 : 05 2000 |
|
gettimeofday(取得目前的時間) |
相關(guān)函數(shù)
|
time,ctime,ftime,settimeofday |
表頭文件
|
#include <sys/time.h> #include <unistd.h> |
定義函數(shù)
|
int gettimeofday ( struct timeval * tv , struct timezone * tz ) |
函數(shù)說明
|
gettimeofday()會把目前的時間有tv所指的結(jié)構(gòu)返回,當?shù)貢r區(qū)的信息則放到tz所指的結(jié)構(gòu)中。 timeval結(jié)構(gòu)定義為: struct timeval{ long tv_sec; /*秒*/ long tv_usec; /*微秒*/ }; timezone 結(jié)構(gòu)定義為: struct timezone{ int tz_minuteswest; /*和Greenwich 時間差了多少分鐘*/ int tz_dsttime; /*日光節(jié)約時間的狀態(tài)*/ }; 上述兩個結(jié)構(gòu)都定義在/usr/include/sys/time.h。tz_dsttime 所代表的狀態(tài)如下 DST_NONE /*不使用*/ DST_USA /*美國*/ DST_AUST /*澳洲*/ DST_WET /*西歐*/ DST_MET /*中歐*/ DST_EET /*東歐*/ DST_CAN /*加拿大*/ DST_GB /*大不列顛*/ DST_RUM /*羅馬尼亞*/ DST_TUR /*土耳其*/ DST_AUSTALT /*澳洲(1986年以后)*/ |
返回值
|
成功則返回0,失敗返回-1,錯誤代碼存于errno。附加說明EFAULT指針tv和tz所指的內(nèi)存空間超出存取權(quán)限。 |
范例
|
#include<sys/time.h> #include<unistd.h> main(){ struct timeval tv; struct timezone tz; gettimeofday (&tv , &tz); printf(“tv_sec; %d\n”, tv,.tv_sec) ; printf(“tv_usec; %d\n”,tv.tv_usec); printf(“tz_minuteswest; %d\n”, tz.tz_minuteswest); printf(“tz_dsttime, %d\n”,tz.tz_dsttime); } |
執(zhí)行
|
tv_sec: 974857339 tv_usec:136996 tz_minuteswest:-540 tz_dsttime:0 |
|
gmtime(取得目前時間和日期) |
相關(guān)函數(shù)
|
time,asctime,ctime,localtime |
表頭文件
|
#include<time.h> |
定義函數(shù)
|
struct tm*gmtime(const time_t*timep); |
函數(shù)說明
|
gmtime()將參數(shù)timep 所指的time_t 結(jié)構(gòu)中的信息轉(zhuǎn)換成真實世界所使用的時間日期表示方法,然后將結(jié)果由結(jié)構(gòu)tm返回。 結(jié)構(gòu)tm的定義為 struct tm { int tm_sec; int tm_min; int tm_hour; int tm_mday; int tm_mon; int tm_year; int tm_wday; int tm_yday; int tm_isdst; }; int tm_sec 代表目前秒數(shù),正常范圍為0-59,但允許至61秒 int tm_min 代表目前分數(shù),范圍0-59 int tm_hour 從午夜算起的時數(shù),范圍為0-23 int tm_mday 目前月份的日數(shù),范圍01-31 int tm_mon 代表目前月份,從一月算起,范圍從0-11 int tm_year 從1900 年算起至今的年數(shù) int tm_wday 一星期的日數(shù),從星期一算起,范圍為0-6 int tm_yday 從今年1月1日算起至今的天數(shù),范圍為0-365 int tm_isdst 日光節(jié)約時間的旗標 此函數(shù)返回的時間日期未經(jīng)時區(qū)轉(zhuǎn)換,而是UTC時間。 |
返回值
|
返回結(jié)構(gòu)tm代表目前UTC 時間 |
范例
|
#include <time.h> main(){ char *wday[]={"Sun","Mon","Tue","Wed","Thu","Fri","Sat"}; time_t timep; struct tm *p; time(&timep); p=gmtime(&timep); printf(“%d%d%d”,(1900+p->tm_year), (1+p->tm_mon),p->tm_mday); printf(“%s%d;%d;%d\n”, wday[p->tm_wday], p->tm_hour, p->tm_min, p->tm_sec); } |
執(zhí)行
|
2000/10/28 Sat 8:15:38 |
|
localtime(取得當?shù)啬壳皶r間和日期) |
相關(guān)函數(shù)
|
time, asctime, ctime, gmtime |
表頭文件
|
#include<time.h> |
定義函數(shù)
|
struct tm *localtime(const time_t * timep); |
函數(shù)說明
|
localtime()將參數(shù)timep所指的time_t結(jié)構(gòu)中的信息轉(zhuǎn)換成真實世界所使用的時間日期表示方法,然后將結(jié)果由結(jié)構(gòu)tm返回。結(jié)構(gòu)tm的定義請參考gmtime()。此函數(shù)返回的時間日期已經(jīng)轉(zhuǎn)換成當?shù)貢r區(qū)。 |
返回值
|
返回結(jié)構(gòu)tm代表目前的當?shù)貢r間。 |
范例
|
#include<time.h> main(){ char *wday[]={“Sun”,”Mon”,”Tue”,”Wed”,”Thu”,”Fri”,”Sat”}; time_t timep; struct tm *p; time(&timep); p=localtime(&timep); /*取得當?shù)貢r間*/ printf (“%d%d%d ”, (1900+p->tm_year),( l+p->tm_mon), p->tm_mday); printf(“%s%d:%d:%d\n”, wday[p->tm_wday],p->tm_hour, p->tm_min, p->tm_sec); } |
執(zhí)行
|
2000/10/28 Sat 11:12:22 |
|
mktime(將時間結(jié)構(gòu)數(shù)據(jù)轉(zhuǎn)換成經(jīng)過的秒數(shù)) |
相關(guān)函數(shù)
|
time,asctime,gmtime,localtime |
表頭文件
|
#include<time.h> |
定義函數(shù)
|
time_t mktime(strcut tm * timeptr); |
函數(shù)說明
|
mktime()用來將參數(shù)timeptr所指的tm結(jié)構(gòu)數(shù)據(jù)轉(zhuǎn)換成從公元1970年1月1日0時0分0 秒算起至今的UTC時間所經(jīng)過的秒數(shù)。 |
返回值
|
返回經(jīng)過的秒數(shù)。 |
范例
|
/* 用time()取得時間(秒數(shù)),利用localtime() 轉(zhuǎn)換成struct tm 再利用mktine()將struct tm轉(zhuǎn)換成原來的秒數(shù)*/ #include<time.h> main() { time_t timep; strcut tm *p; time(&timep); printf(“time() : %d \n”,timep); p=localtime(&timep); timep = mktime(p); printf(“time()->localtime()->mktime():%d\n”,timep); } |
執(zhí)行
|
time():974943297 time()->localtime()->mktime():974943297 |
|
settimeofday(設(shè)置目前時間) |
相關(guān)函數(shù)
|
time,ctime,ftime,gettimeofday |
表頭文件
|
#include<sys/time.h> #include<unistd.h> |
定義函數(shù)
|
int settimeofday ( const struct timeval *tv,const struct timezone *tz); |
函數(shù)說明
|
settimeofday()會把目前時間設(shè)成由tv所指的結(jié)構(gòu)信息,當?shù)貢r區(qū)信息則設(shè)成tz所指的結(jié)構(gòu)。詳細的說明請參考gettimeofday()。注意,只有root權(quán)限才能使用此函數(shù)修改時間。 |
返回值
|
成功則返回0,失敗返回-1,錯誤代碼存于errno。 |
錯誤代碼
|
EPERM 并非由root權(quán)限調(diào)用settimeofday(),權(quán)限不夠。 EINVAL 時區(qū)或某個數(shù)據(jù)是不正確的,無法正確設(shè)置時間。 |
|
time(取得目前的時間) |
相關(guān)函數(shù)
|
ctime,ftime,gettimeofday |
表頭文件
|
#include<time.h> |
定義函數(shù)
|
time_t time(time_t *t); |
函數(shù)說明
|
此函數(shù)會返回從公元1970年1月1日的UTC時間從0時0分0秒算起到現(xiàn)在所經(jīng)過的秒數(shù)。如果t 并非空指針的話,此函數(shù)也會將返回值存到t指針所指的內(nèi)存。 |
返回值
|
成功則返回秒數(shù),失敗則返回((time_t)-1)值,錯誤原因存于errno中。 |
范例
|
#include<time.h> mian() { int seconds= time((time_t*)NULL); printf(“%d\n”,seconds); } |
執(zhí)行
|
9.73E+08 |
1. 函數(shù)庫libdbus,用于兩個應(yīng)用程序呼叫聯(lián)系和交互消息。
2. Message bus daemon,總線守護進程可同時與多個應(yīng)用程序相連,并能把來自一個應(yīng)用程序的消息路由到0或者多個其他程序。
3. 一系列基于特定應(yīng)用程序框架的Wrapper庫。 比如libdbus-glib, libdbus-python.
參看圖1-1, Bus Daemon Process就是運行在linux的daemon(dbus-daemon, 用戶可以在/etc/init.d/dbus 操作,stop, start等等), dbus-daemon運行時會調(diào)用libdus的庫。 在Application Process1里面就是應(yīng)用層的東西了,應(yīng)用程序調(diào)用特定的應(yīng)用程序框架的Wrapper庫與dbus-daemon進行通信。
我前段時間就是用Python寫程序與dbus-daemon通信,所以就需要libdbus-python,后來又用c寫程序,又裝了libdus-glib。實質(zhì)上在dbus主頁上(http://www.freedesktop.org/wiki/Software/dbus)提供了很多Wrapper庫, for QT4, JAVA, Perl, C++, Pascal, QT3, .NET, Ruby等等。這個Wrapper庫呢其實就是對dbus下層調(diào)用做了封裝,給上層暴露一個友好的接口。dbus的底層其實也是通過socket通信的
圖 1-1
我再給一張bluez的例子讓大家更理解dbus; 有四個應(yīng)用想與bluz的damon通信,bluez注冊到dbus中,其它的應(yīng)用只需要向dbus要bluez的數(shù)據(jù),
dbus負責再和bluez溝通了,但是bluez一定要把接口告訴其它應(yīng)用。
select系統(tǒng)調(diào)用是用來讓我們的程序監(jiān)視多個文件句柄(file descriptor)的狀態(tài)變化的。程序會停在select這里等待,直到被監(jiān)視的文件句柄有某一個或多個發(fā)生了狀態(tài)改變。 文件在句柄在Linux里很多,如果你man某個函數(shù),在函數(shù)返回值部分說到成功后有一個文件句柄被創(chuàng)建的都是的,如man socket可以看到“On success, a file descriptor for the new socket is returned.”而man 2 open可以看到“open() and creat() return the new file descriptor”,其實文件句柄就是一個整數(shù),看socket函數(shù)的聲明就明白了:
int socket(int domain, int type, int protocol);
當然,我們最熟悉的句柄是0、1、2三個,0是標準輸入,1是標準輸出,2是標準錯誤輸出。0、1、2是整數(shù)表示的,對應(yīng)的FILE *結(jié)構(gòu)的表示就是stdin、stdout、stderr,0就是stdin,1就是stdout,2就是stderr。比如下面這兩段代碼都是從標準輸入讀入9個字節(jié)字符:
#include <stdio.h> #include <unistd.h> #include <string.h> int main(int argc, char ** argv) { char buf[10] = ""; read(0, buf, 9); /* 從標準輸入 0 讀入字符 */ fprintf(stdout, "%s\n", buf); /* 向標準輸出 stdout 寫字符 */
return 0; } /* **上面和下面的代碼都可以用來從標準輸入讀用戶輸入的9個字符** */ #include <stdio.h> #include <unistd.h> #include <string.h> int main(int argc, char ** argv) { char buf[10] = ""; fread(buf, 9, 1, stdin); /* 從標準輸入 stdin 讀入字符 */ write(1, buf, strlen(buf));
return 0; } |
繼續(xù)上面說的select,就是用來監(jiān)視某個或某些句柄的狀態(tài)變化的。
select函數(shù)原型如下:
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
函 數(shù)的最后一個參數(shù)timeout顯然是一個超時時間值,其類型是struct timeval *,即一個struct timeval結(jié)構(gòu)的變量的指針,所以我們在程序里要申明一個struct timeval tv;然后把變量tv的地址&tv傳遞給select函數(shù)。struct timeval結(jié)構(gòu)如下:
struct timeval { long tv_sec; /* seconds */ long tv_usec; /* microseconds */ }; |
第2、 3、4三個參數(shù)是一樣的類型: fd_set *,即我們在程序里要申明幾個fd_set類型的變量,比如rdfds, wtfds, exfds,然后把這個變量的地址&rdfds, &wtfds, &exfds 傳遞給select函數(shù)。
這三個參數(shù)都是一個句柄的集合,第一個rdfds是用來保存這樣的句柄的:當句柄的狀態(tài)變成可讀的時系統(tǒng)就會告訴select函數(shù)返回,同理第二個wtfds是指有句柄狀態(tài)變成可寫的時系統(tǒng)就會告訴select函數(shù)返回,同理第三個參數(shù)exfds是特殊情況,即句柄上有特殊情況發(fā)生時系統(tǒng)會告訴select函數(shù)返回。特殊情況比如對方通過一個socket句柄發(fā)來了緊急數(shù)據(jù)。如果我們程序里只想檢測某個socket是否有數(shù)據(jù)可讀,我們可以這樣:
fd_set rdfds; /* 先申明一個 fd_set 集合來保存我們要檢測的 socket句柄 */ struct timeval tv; /* 申明一個時間變量來保存時間 */ int ret; /* 保存返回值 */ FD_ZERO(&rdfds); /* 用select函數(shù)之前先把集合清零 */ FD_SET(socket, &rdfds); /* 把要檢測的句柄socket加入到集合里 */
tv.tv_sec = 1; tv.tv_usec = 500; /* 設(shè)置select等待的最大時間為1秒加500微秒 */
ret = select(socket + 1, &rdfds, NULL, NULL, &tv); /* 檢測我們上面設(shè)置到集合rdfds里的句柄是否有可讀信息 */ if(ret < 0) perror("select");/* 這說明select函數(shù)出錯 */ else if(ret == 0) printf("超時\n"); /* 說明在我們設(shè)定的時間值1秒加500毫秒的時間內(nèi),socket的狀態(tài)沒有發(fā)生變化 */ else { /* 說明等待時間還未到1秒加500毫秒,socket的狀態(tài)發(fā)生了變化 */ printf("ret=%d\n", ret); /* ret這個返回值記錄了發(fā)生狀態(tài)變化的句柄的數(shù)目,由于我們只監(jiān)視了socket這一個句柄,所以這里一定ret=1,如果同時有多個句柄發(fā)生變化返回的就是句柄的總和了 */ /* 這里我們就應(yīng)該從socket這個句柄里讀取數(shù)據(jù)了,因為select函數(shù)已經(jīng)告訴我們這個句柄里有數(shù)據(jù)可讀 */ if(FD_ISSET(socket, &rdfds)) { /* 先判斷一下socket這外被監(jiān)視的句柄是否真的變成可讀的了 */ /* 讀取socket句柄里的數(shù)據(jù) */ recv(...); } } |
注意select函數(shù)的第一個參數(shù),是所有加入集合的句柄值的最大那個值還要加1。比如我們創(chuàng)建了3個句柄:
int sa, sb, sc; sa = socket(...); /* 分別創(chuàng)建3個句柄并連接到服務(wù)器上 */ connect(sa,...); sb = socket(...); connect(sb,...); sc = socket(...); connect(sc,...); FD_SET(sa, &rdfds);/* 分別把3個句柄加入讀監(jiān)視集合里去 */ FD_SET(sb, &rdfds); FD_SET(sc, &rdfds); |
在使用select函數(shù)之前,一定要找到3個句柄中的最大值是哪個,我們一般定義一個變量來保存最大值,取得最大socket值如下:
int maxfd = 0; if(sa > maxfd) maxfd = sa; if(sb > maxfd) maxfd = sb; if(sc > maxfd) maxfd = sc; |
然后調(diào)用select函數(shù):
ret = select(maxfd + 1, &rdfds, NULL, NULL, &tv); /* 注意是最大值還要加1 */ |
同樣的道理,如果我們要檢測用戶是否按了鍵盤進行輸入,我們就應(yīng)該把標準輸入0這個句柄放到select里來檢測,如下:
FD_ZERO(&rdfds);
FD_SET(0, &rdfds);
tv.tv_sec = 1;
tv.tv_usec = 0;
ret = select(1, &rdfds, NULL, NULL, &tv); /* 注意是最大值還要加1 */
if(ret < 0)
perror("select");/* 出錯 */
else if(ret == 0)
printf("超時\n"); /* 在我們設(shè)定的時間tv內(nèi),用戶沒有按鍵盤 */
else { /* 用戶有按鍵盤,要讀取用戶的輸入 */
scanf("%s", buf); }
Linux環(huán)境下的軟件安裝,并不是一件容易的事情;如果通過源代碼編譯后在安裝,當然事情就更為復(fù)雜一些;現(xiàn)在安裝各種軟件的教程都非常普遍;但萬變不離其中,對基礎(chǔ)知識的扎實掌握,安裝各種軟件的問題就迎刃而解了。Configure腳本配置工具就是基礎(chǔ)之一,它是autoconf的工具的基本應(yīng)用。
與一些技巧相比,Configure顯得基礎(chǔ)一些,當然使用和學(xué)習(xí)起來就顯得枯燥乏味一些,當然要成為高手,對基礎(chǔ)的熟悉不能超越哦。
為此我轉(zhuǎn)載了一篇關(guān)于Configure選項配置的詳細介紹。供大家參考
'configure'腳本有大量的命令行選項。對不同的軟件包來說,這些選項可能會有變化,但是許多基本的選項是不會改變的。帶上'--help'選項執(zhí)行'configure'腳本可以看到可用的所有選項。盡管許多選項是很少用到的,但是當你為了特殊的需求而configure一個包時,知道他們的存在是很有益處的。下面對每一個選項進行簡略的介紹:
--cache-file=FILE
'configure'會在你的系統(tǒng)上測試存在的特性(或者bug!)。為了加速隨后進行的配置,測試的結(jié)果會存儲在一個cache file里。當configure一個每個子樹里都有'configure'腳本的復(fù)雜的源碼樹時,一個很好的cache file的存在會有很大幫助。
--help
輸出幫助信息。即使是有經(jīng)驗的用戶也偶爾需要使用使用'--help'選項,因為一個復(fù)雜的項目會包含附加的選項。例如,GCC包里的'configure'腳本就包含了允許你控制是否生成和在GCC中使用GNU匯編器的選項。
--no-create
'configure'中的一個主要函數(shù)會制作輸出文件。此選項阻止'configure'生成這個文件。你可以認為這是一種演習(xí)(dry run),盡管緩存(cache)仍然被改寫了。
--quiet
--silent
當'configure'進行他的測試時,會輸出簡要的信息來告訴用戶正在作什么。這樣作是因為'configure'可能會比較慢,沒有這種輸出的話用戶將會被扔在一旁疑惑正在發(fā)生什么,使用這兩個選項中的任何一個都會把你扔到一旁。(譯注:這兩句話比較有意思,原文是這樣的:If there was no such output, the user would be left wondering what is happening. By using this option, you too can be left wondering!)
--version
打印用來產(chǎn)生'configure'腳本的Autoconf的版本號。
--prefix=PEWFIX
'--prefix'是最常用的選項。制作出的'Makefile'會查看隨此選項傳遞的參數(shù),當一個包在安裝時可以徹底的重新安置他的結(jié)構(gòu)獨立部分。舉一個例子,當安裝一個包,例如說Emacs,下面的命令將會使Emacs Lisp file被安裝到"/opt/gnu/share":
$ ./configure --prefix=/opt/gnu
--exec-prefix=EPREFIX
與'--prefix'選項類似,但是他是用來設(shè)置結(jié)構(gòu)倚賴的文件的安裝位置,編譯好的'emacs'二進制文件就是這樣一個問件。如果沒有設(shè)置這個選項的話,默認使用的選項值將被設(shè)為和'--prefix'選項值一樣。
--bindir=DIR
指定二進制文件的安裝位置,這里的二進制文件定義為可以被用戶直接執(zhí)行的程序。
--sbindir=DIR
指定超級二進制文件的安裝位置。這是一些通常只能由超級用戶執(zhí)行的程序。
--libexecdir=DIR
指定可執(zhí)行支持文件的安裝位置。與二進制文件相反,這些文件從來不直接由用戶執(zhí)行,但是可以被上面提到的二進制文件所執(zhí)行。
--datadir=DIR
指定通用數(shù)據(jù)文件的安裝位置。
--sysconfdir=DIR
指定在單個機器上使用的只讀數(shù)據(jù)的安裝位置。
--sharedstatedir=DIR
指定可以在多個機器上共享的可寫數(shù)據(jù)的安裝位置。
--localstatedir=DIR
指定只能單機使用的可寫數(shù)據(jù)的安裝位置。
--libdir=DIR
指定庫文件的安裝位置。
--includedir=DIR
指定C頭文件的安裝位置。其他語言如C++的頭文件也可以使用此選項。
--oldincludedir=DIR
指定為除GCC外編譯器安裝的C頭文件的安裝位置。
--infodir=DIR
指定Info格式文檔的安裝位置.Info是被GNU工程所使用的文檔格式。
--mandir=DIR
指定手冊頁的安裝位置。
--srcdir=DIR
這個選項對安裝沒有作用,他會告訴'configure'源碼的位置。一般來說不用指定此選項,因為'configure'腳本一般和源碼文件在同一個目錄下。
--program-prefix=PREFIX
指定將被加到所安裝程序的名字上的前綴。例如,使用'--program-prefix=g'來configure一個名為'tar'的程序?qū)拱惭b的程序被命名為'gtar'。當和其他的安裝選項一起使用時,這個選項只有當他被`Makefile.in'文件使用時才會工作。
--program-suffix=SUFFIX
指定將被加到所安裝程序的名字上的后綴。
--program-transform-name=PROGRAM
這里的PROGRAM是一個sed腳本。當一個程序被安裝時,他的名字將經(jīng)過`sed -e PROGRAM'來產(chǎn)生安裝的名字。
--build=BUILD
指定軟件包安裝的系統(tǒng)平臺。如果沒有指定,默認值將是'--host'選項的值。
--host=HOST
指定軟件運行的系統(tǒng)平臺。如果沒有指定。將會運行`config.guess'來檢測。
--target=GARGET
指定軟件面向(target to)的系統(tǒng)平臺。這主要在程序語言工具如編譯器和匯編器上下文中起作用。如果沒有指定,默認將使用'--host'選項的值。
--disable-FEATURE
一些軟件包可以選擇這個選項來提供為大型選項的編譯時配置,例如使用Kerberos認證系統(tǒng)或者一個實驗性的編譯器最優(yōu)配置。如果默認是提供這些特性,可以使用'--disable-FEATURE'來禁用它,這里'FEATURE'是特性的名字,例如:
$ ./configure --disable-gui
-enable-FEATURE[=ARG]
相反的,一些軟件包可能提供了一些默認被禁止的特性,可以使用'--enable-FEATURE'來起用它。這里'FEATURE'是特性的名字。一個特性可能會接受一個可選的參數(shù)。例如:
$ ./configure --enable-buffers=128
`--enable-FEATURE=no'與上面提到的'--disable-FEATURE'是同義的。
--with-PACKAGE[=ARG]
在自由軟件社區(qū)里,有使用已有軟件包和庫的優(yōu)秀傳統(tǒng)。當用'configure'來配置一個源碼樹時,可以提供其他已經(jīng)安裝的軟件包的信息。例如,倚賴于Tcl和Tk的BLT器件工具包。要配置BLT,可能需要給'configure'提供一些關(guān)于我們把Tcl和Tk裝的何處的信息:
$ ./configure --with-tcl=/usr/local --with-tk=/usr/local
'--with-PACKAGE=no'與下面將提到的'--without-PACKAGE'是同義的。
--without-PACKAGE
有時候你可能不想讓你的軟件包與系統(tǒng)已有的軟件包交互。例如,你可能不想讓你的新編譯器使用GNU ld。通過使用這個選項可以做到這一點:
$ ./configure --without-gnu-ld
--x-includes=DIR
這個選項是'--with-PACKAGE'選項的一個特例。在Autoconf最初被開發(fā)出來時,流行使用'configure'來作為Imake的一個變通方法來制作運行于X的軟件。'--x-includes'選項提供了向'configure'腳本指明包含X11頭文件的目錄的方法。
--x-libraries=DIR
類似的,'--x-libraries'選項提供了向'configure'腳本指明包含X11庫的目錄的方法。
在源碼樹中運行'configure'是不必要的同時也是不好的。一個由'configure'產(chǎn)生的良好的'Makefile'可以構(gòu)筑源碼屬于另一棵樹的軟件包。在一個獨立于源碼的樹中構(gòu)筑派生的文件的好處是很明顯的:派生的文件,如目標文件,會凌亂的散布于源碼樹。這也使在另一個不同的系統(tǒng)或用不同的配置選項構(gòu)筑同樣的目標文件非常困難。建議使用三棵樹:一棵源碼樹(source tree),一棵構(gòu)筑樹(build tree),一棵安裝樹(install tree)。這里有一個很接近的例子,是使用這種方法來構(gòu)筑GNU malloc包:
$ gtar zxf mmalloc-1.0.tar.gz
$ mkdir build && cd build
$ ../mmalloc-1.0/configure
creating cache ./config.cache
checking for gcc... gcc
checking whether the C compiler (gcc ) works... yes
checking whether the C compiler (gcc ) is a cross-compiler... no
checking whether we are using GNU C... yes
checking whether gcc accepts -g... yes
checking for a BSD compatible install... /usr/bin/install -c
checking host system type... i586-pc-linux-gnu
checking build system type... i586-pc-linux-gnu
checking for ar... ar
checking for ranlib... ranlib
checking how to run the C preprocessor... gcc -E
checking for unistd.h... yes
checking for getpagesize... yes
checking for working mmap... yes
checking for limits.h... yes
checking for stddef.h... yes
updating cache ../config.cache
creating ./config.status
這樣這棵構(gòu)筑樹就被配置了,下面可以繼續(xù)構(gòu)筑和安裝這個包到默認的位置'/usr/local':
$ make all && make install
圖1-1
接著介紹下藍牙里面profile的定義,profile既是配置文件,配置文件定義了可能的應(yīng)用,藍牙配置文件表達了一般行為,藍牙設(shè)備可以通過這些行為與其它設(shè)備進行通信。藍牙技術(shù)定義了廣泛的配置文件,描述了許多不同類型的使用案例。按照藍牙規(guī)格中提供的指導(dǎo),開發(fā)商可以創(chuàng)建應(yīng)用程序以與其它符合藍牙規(guī)格的設(shè)備協(xié)同工作。 到目前為止,藍牙一共有22個profile,在這里我就不詳細介紹圖1-1的協(xié)議和每個Profile了,在www.bluetooth.com上有詳細的文檔說明。
在這里我想詳細介紹下已經(jīng)實現(xiàn)了r的協(xié)議棧。
我們是基于BlueMagic3的,最近呢也在研究bluez 4的移植和profile工作,后面我會再針對bluez做詳細介紹。
時間有限,簡單的寫了下,如果各位網(wǎng)友知道一些協(xié)議棧的動態(tài),或?qū)ξ覍懙挠醒a充,請給我留言,我會及時改正,
chdir("..");
_findclose(filehandle);
通過查證MSDN得知類似于_findfirst,findnext都是針對ASCII碼的,要讀unicode(windows默認字符集),就得用_wfindfirst,_wfindnext等讀寬字符的操作函數(shù),最終解決問題,但我沒有松氣,因為程序主要是運行在linux中的,Linux真不知道怎么整了。
Linux上讀多國語言的文件和目錄就需要對Linux系統(tǒng)深入了解,因為我要讀的文件是usb上的文件,所以得先掛載到一個目錄,
mount -t vfat /dev/sda1 /mnt/usb,然后readdir讀入文件,與Windows上同樣的錯,讀入的是"?",我想和windows一樣去找一個類似wreaddir,但是沒有。于是應(yīng)該從掛載著手,目前在NTFS和FAT32/VFAT下的文件系統(tǒng)上都使用了Unicode,這就需要系統(tǒng)在讀取這些文件名時動態(tài)將其轉(zhuǎn)換為相應(yīng)的語言編碼,也就是說掛載的時候要把usb上的編碼轉(zhuǎn)化成16位的Unicode編碼,改命令如下后成功。
mount -o iocharset = utf8 /dev/sda1 /mnt/usb.
Linux對iocharset的解釋如下:
Character set to use for converting between 8 bit characters and 16 bit unicode charaters.The default is iso8859-1. Long filenames are stored on disk in Unicode format.
至此終于解決了多國語言的問題,接著我無法想象還有什么問題會出來,但我準備好了。
ubuntu已經(jīng)被我從硬盤上擦除了,呵呵,因為一些問題,找了張suse,安裝時選了KDE,現(xiàn)在突然感覺不錯,從可用性上,界面上都不再是那個死板的Linux,而且我沒裝什么驅(qū)動用跑起來也沒問題(對于菜鳥來說這個比較重要),然后U盤也不用掛載就可用,不會出中文問題,就感覺還可以了,先給張圖片大家看看。