Solaris 10 C 编程

90
Solaris 10 Solaris 10 C C 编编 编编 南南南南南南南南南南南南 南南南南南南南南南南南南 南南 南南 QQ:31423047 MSN:cz_888@hotmail. QQ:31423047 MSN:cz_888@hotmail. com com

description

Solaris 10 C 编程. 南京天石软件技术有限公司 陈锺 ( QQ:31423047 MSN:[email protected] ). Solaris — 软件开发环境的搭建. 添加必须的路径信息到环境变量 添加如下信息到 /.profile PATH=$PATH:/usr/sfw/bin:/usr/local/bin:/usr/local/lib:/usr/ccs/bin;export PATH 复制必须的 lib 以使 gcc 工作正常 - PowerPoint PPT Presentation

Transcript of Solaris 10 C 编程

Page 1: Solaris 10 C 编程

Solaris 10Solaris 10CC 编程编程南京天石软件技术有限公司南京天石软件技术有限公司陈锺 陈锺 (( QQ:31423047 MSN:[email protected]:31423047 MSN:[email protected] ))

Page 2: Solaris 10 C 编程

Solaris—Solaris— 软件开发环境的搭建软件开发环境的搭建 添加必须的路径信息到环境变量添加必须的路径信息到环境变量添加如下信息到添加如下信息到 /.profile/.profilePATH=$PATH:/usr/sfw/bin:/usr/local/bin:/uPATH=$PATH:/usr/sfw/bin:/usr/local/bin:/usr/local/lib:/usr/ccs/bin;export PATHsr/local/lib:/usr/ccs/bin;export PATH 复制必须的复制必须的 liblib 以使以使 gccgcc 工作正常工作正常执行如下命令执行如下命令 :cp /usr/sfw/lib/libstdc++.so.6 /l:cp /usr/sfw/lib/libstdc++.so.6 /lib/ib/ 和和 cp /usr/sfw/lib/libgcc_s.so.1 /lib/ cp /usr/sfw/lib/libgcc_s.so.1 /lib/ 为了编译为了编译 gtkgtk 软件,例如制图包和一次图:软件,例如制图包和一次图:将将 /usr/lib/pkgconfig/gthread-2.0.pc/usr/lib/pkgconfig/gthread-2.0.pc 和和 /usr/li/usr/lib/pkgconfig/ORBit-2.0.pcb/pkgconfig/ORBit-2.0.pc 中的中的 -mt-mt 替换成替换成 -D_REENTRANT-D_REENTRANT 重新启动重新启动

Page 3: Solaris 10 C 编程

Solaris—Sun StudioSolaris—Sun Studio 安装安装 安装安装 Sun Studio11Sun Studio11

安装包为安装包为 studio11-sol-x86.tar.bz2studio11-sol-x86.tar.bz2bzip2 -d studio11-sol-x86.tar.bz2bzip2 -d studio11-sol-x86.tar.bz2 解压解压tar xf studio11-sol-x86.tartar xf studio11-sol-x86.tar 解包解包./installer./installer 进行安装进行安装

Page 4: Solaris 10 C 编程

Solaris—Sun StudioSolaris—Sun Studio 安装安装

Page 5: Solaris 10 C 编程

Solaris—Sun StudioSolaris—Sun Studio 安装安装

Page 6: Solaris 10 C 编程

Solaris—Sun StudioSolaris—Sun Studio 安装安装

Page 7: Solaris 10 C 编程

Solaris—Sun StudioSolaris—Sun Studio 安装安装

Page 8: Solaris 10 C 编程

Solaris—Sun StudioSolaris—Sun Studio 安装安装

Page 9: Solaris 10 C 编程

Solaris—Sun StudioSolaris—Sun Studio 安装安装

Page 10: Solaris 10 C 编程

Solaris—Sun StudioSolaris—Sun Studio 安装安装

Page 11: Solaris 10 C 编程

Solaris—Sun StudioSolaris—Sun Studio 安装安装

Page 12: Solaris 10 C 编程

Solaris—Sun StudioSolaris—Sun Studio 安装安装

Page 13: Solaris 10 C 编程

Solaris—Sun StudioSolaris—Sun Studio 安装安装

Page 14: Solaris 10 C 编程

Solaris—Sun StudioSolaris—Sun Studio 安装安装 为为 Sun StudioSun Studio 配置环境配置环境

在在 /.profile/.profile 文件的文件的 PATHPATH 变量赋值中加入变量赋值中加入/opt/SUNWspro/bin/opt/SUNWspro/bin

Page 15: Solaris 10 C 编程

Solaris—gccSolaris—gcc 在为在为 UnixUnix 开发应用程序时开发应用程序时 ,, 绝大多数情况下使用的都是绝大多数情况下使用的都是 CC语言语言 ,, 因此几乎每一位因此几乎每一位 LinuxLinux 程序员面临的首要问题都是程序员面临的首要问题都是如何如何灵活运用灵活运用 CC 编译器编译器 ..目前目前 LinuxLinux 下最常用的下最常用的 CC 语言编译器是语言编译器是 GCC(GNU CompGCC(GNU Compiler Collection),iler Collection), 它是它是 GNUGNU 项目中符合项目中符合 ANSI CANSI C 标准的编标准的编译系统译系统 ,, 能够编译用能够编译用 CC 、、 C++C++ 和和 Object CObject C 等语言编写的程等语言编写的程序序 ..GCCGCC 不仅功能非常强大不仅功能非常强大 ,, 结构也异常灵活结构也异常灵活 .. 最值得称道的最值得称道的一点就是它可以通过不同的前端模块来支持各种语言一点就是它可以通过不同的前端模块来支持各种语言 ,, 如如 JJavaava 、、 FortranFortran 、、 PascalPascal 、、 Modula-3Modula-3 和和 AdaAda 等等 . . 开放、自由和灵活是开放、自由和灵活是 gccgcc 的魅力所在的魅力所在 ,, 程序员通过它能够程序员通过它能够更好地控制整个编译过程更好地控制整个编译过程 ..各操作系统的各操作系统的 gccgcc 略有不同。略有不同。

Page 16: Solaris 10 C 编程

Solaris—gccSolaris—gcc 使用使用 GCCGCC 编译程序时编译程序时 ,, 编译过程可以被细编译过程可以被细分为四个阶段分为四个阶段 : : ◆ ◆ 预处理预处理 (Pre-Processing) (Pre-Processing) ◆ ◆ 编译编译 (Compiling) (Compiling) ◆ ◆ 汇编汇编 (Assembling) (Assembling) ◆ ◆ 链接链接 (Linking) (Linking)

Page 17: Solaris 10 C 编程

Solaris—Solaris— 软件开发模式软件开发模式 模式一模式一

每个程序员机器上安装每个程序员机器上安装 SolarisSolaris ,使用,使用 gedgeditit 编写程序或者编写程序或者 Sun studioSun studio 集成开发。集成开发。优点:直接编写、编译、调试。优点:直接编写、编译、调试。缺点:缺点: SolarisSolaris 下其他辅助工具少,下其他辅助工具少, SolarisSolaris桌面提供的软件相对匮乏,桌面提供的软件相对匮乏, wordword 文档等文档等在在 windowswindows 与与 SolarisSolaris 间无法完全兼容。间无法完全兼容。

Page 18: Solaris 10 C 编程

Solaris—Solaris— 软件开发模式软件开发模式 模式二模式二每个程序员机器上使用每个程序员机器上使用 windowswindows ,,在一台编程调试服务器上安装在一台编程调试服务器上安装 SolarisSolaris 。程。程序员使用序员使用 XmanagerXmanager 登陆到服务器的登陆到服务器的 SolaSolarisris 进行程序编写、编译。进行程序编写、编译。优点:双操作系统并存,优点:双操作系统并存, windowswindows 资源丰资源丰富,在富,在 SolarisSolaris 下直接编写、编译、调试。下直接编写、编译、调试。缺点:对调试服务器性能要求较高,否则缺点:对调试服务器性能要求较高,否则交互速度太慢。交互速度太慢。

Page 19: Solaris 10 C 编程

Solaris—Solaris— 软件开发模式软件开发模式 模式三模式三每个程序员机器上使用每个程序员机器上使用 windowswindows ,,在一台编程调试服务器上安装在一台编程调试服务器上安装 SolarisSolaris 。使。使用用 windowswindows 环境编写程序,通过环境编写程序,通过 ftpftp 工具工具将代码传输到服务器的将代码传输到服务器的 SolarisSolaris ,通过,通过 telntelnetet 远程登陆编译。远程登陆编译。优点:程序编写工具丰富。优点:程序编写工具丰富。缺点:必须经过代码传输过程,远程字符缺点:必须经过代码传输过程,远程字符模式的编译、修改、调试。模式的编译、修改、调试。

Page 20: Solaris 10 C 编程

Solaris—helloworld.cSolaris—helloworld.c#include <stdio.h>#include <stdio.h>int main(void)int main(void){{ printf ("Hello world, Solaris programming!\n");printf ("Hello world, Solaris programming!\n"); return 0;return 0;}}gcc helloworld.c -o helloworld.ogcc helloworld.c -o helloworld.o./helloworld.o./helloworld.oHello world, Solaris programming!Hello world, Solaris programming!

Page 21: Solaris 10 C 编程

Solaris—dbxSolaris—dbx dbxdbx 程序调试工具—程序崩溃程序调试工具—程序崩溃例子:例子: crash.c crash.c 1:#include <stdio.h>1:#include <stdio.h>2:int main(void)2:int main(void)3:{3:{4: char * ss=NULL;4: char * ss=NULL;5: sprintf(ss,"helloworld!\n");5: sprintf(ss,"helloworld!\n");6: printf(ss);6: printf(ss);7: return 0;7: return 0; 8:}8:}

Page 22: Solaris 10 C 编程

Solaris—dbxSolaris—dbx 使用使用 -g-g 编译程序,以使编译出来的程序带编译程序,以使编译出来的程序带调试环境调试环境 gcc -g crash.c –o crash.ogcc -g crash.c –o crash.o 运行运行 crash.ocrash.o

bash-3.00# ./crash.o bash-3.00# ./crash.o 段错误 段错误 (core dumped)(core dumped)怎么样快速找到问题?怎么样快速找到问题?

Page 23: Solaris 10 C 编程

Solaris—dbxSolaris—dbxbash-3.00# bash-3.00# dbx crash.odbx crash.oFor information about new features see `help changes'For information about new features see `help changes'To remove this message, put `dbxenv suppress_startup_messaTo remove this message, put `dbxenv suppress_startup_message 7.5' in your .dbxrcge 7.5' in your .dbxrcReading crash.oReading crash.oReading ld.so.1Reading ld.so.1Reading libc.so.1Reading libc.so.1(dbx) (dbx) runrunRunning: crash.o Running: crash.o (process id 1230)(process id 1230)signal SEGV (no mapping at the fault address) in memchr at 0xsignal SEGV (no mapping at the fault address) in memchr at 0xd27044d5d27044d50xd27044d5: memchr+0x0055: cmpb (%eax),%cl0xd27044d5: memchr+0x0055: cmpb (%eax),%clCurrent function is mainCurrent function is main 5 sprintf(ss,"helloworld!\n");(dbx) (dbx) quitquit

Page 24: Solaris 10 C 编程

Solaris—dbxSolaris—dbx dbxdbx 程序调试工具—内存泄露程序调试工具—内存泄露例子:例子: leak.cleak.c1:#include <stdio.h>1:#include <stdio.h>2:int main(void)2:int main(void)3:{3:{4: int i=0;4: int i=0;5: printf(“pid=%d\n”,getpid());5: printf(“pid=%d\n”,getpid());6: while(i<100)6: while(i<100)7: {7: {8: char *ss=malloc(sizeof(char)*64);8: char *ss=malloc(sizeof(char)*64);9: sprintf(ss,"helloworld!\n");9: sprintf(ss,"helloworld!\n");10: usleep(100000);10: usleep(100000);11: i++;11: i++;12: }12: }13: return 0;13: return 0;14:}14:}

Page 25: Solaris 10 C 编程

Solaris—dbxSolaris—dbx 使用使用 -g-g 编译程序,以使编译出来的程序带调试环编译程序,以使编译出来的程序带调试环境境 gcc -g leak.c -o leak.ogcc -g leak.c -o leak.o 运行运行 leak.oleak.obash-3.00# ./ leak.obash-3.00# ./ leak.opid=1325pid=1325 使用使用 prstat -p 1325 1prstat -p 1325 1 命令查看命令查看 leak.oleak.o 进程状态,进程状态,怎么怎么 SIZESIZE (占用的虚拟内存)和(占用的虚拟内存)和 RSSRSS (内存)(内存)不断增长?不断增长? 怎么样快速找到内存泄露问题?怎么样快速找到内存泄露问题?

Page 26: Solaris 10 C 编程

Solaris—dbxSolaris—dbx bash-3.00# bash-3.00# dbx leak.odbx leak.oFor information about new features see `helFor information about new features see `help changes'p changes'To remove this message, put `dbxenv supprTo remove this message, put `dbxenv suppress_startup_message 7.5' in your .dbxrcess_startup_message 7.5' in your .dbxrcReading leak.oReading leak.oReading ld.so.1Reading ld.so.1Reading libc.so.1Reading libc.so.1(dbx) (dbx) dbxenv rtc_mel_at_exit verbosedbxenv rtc_mel_at_exit verbose 开开启结束后显示详细信息启结束后显示详细信息(dbx) (dbx) check -leakscheck -leaks 开启内存泄露选项开启内存泄露选项leaks checking - ONleaks checking - ON(dbx)(dbx) run run

Page 27: Solaris 10 C 编程

Solaris—dbxSolaris—dbxRunning: leak.o Running: leak.o (process id 1329)(process id 1329)Reading rtcapihook.soReading rtcapihook.soReading libdl.so.1Reading libdl.so.1Reading rtcaudit.soReading rtcaudit.soReading libmapmalloc.so.1Reading libmapmalloc.so.1Reading libgen.so.1Reading libgen.so.1Reading libm.so.2Reading libm.so.2Reading rtcboot.soReading rtcboot.soReading librtc.soReading librtc.soRTC: Enabling Error Checking...RTC: Enabling Error Checking...RTC: Running program...RTC: Running program...pid=1329pid=1329

Page 28: Solaris 10 C 编程

Solaris—dbxSolaris—dbxChecking for memory leaks...Checking for memory leaks...Actual leaks report (actual leaks: 100 total size:Actual leaks report (actual leaks: 100 total size: 6400000 bytes) 6400000 bytes)Memory Leak (mel):Memory Leak (mel):Found 100 leaked blocks with total size 6400000 bytesFound 100 leaked blocks with total size 6400000 bytesAt time of each allocation, the call stack was:At time of each allocation, the call stack was: [1] main() at line 8 in "leak.c"[1] main() at line 8 in "leak.c"Possible leaks report (possible leaks: 0 total sizPossible leaks report (possible leaks: 0 total size: 0 bytes)e: 0 bytes)execution completed, exit code is 0execution completed, exit code is 0(dbx) (dbx) quitquit

Page 29: Solaris 10 C 编程

Solaris—dbxSolaris—dbx 小结小结

dbxdbx 包含在包含在 Sun StudioSun Studio 中。中。编译时必须使用编译时必须使用 -g-g 才能在才能在 dbxdbx 显示出与源显示出与源代码相关的调试结果信息。代码相关的调试结果信息。守护进程在调试前,请先使其成为普通进守护进程在调试前,请先使其成为普通进程。程。调试网络程序时,在调试网络程序时,在 dbxdbx 调试时使用调试时使用 ignoignore SIGPIPEre SIGPIPE 来避免网络信号导致调试中断。来避免网络信号导致调试中断。

Page 30: Solaris 10 C 编程

Solaris—Solaris— 常用调试手段常用调试手段 直接在终端中输出信息直接在终端中输出信息 如果是守护进程写调试信息文件如果是守护进程写调试信息文件 使用使用 dbxdbx 使用使用 sunixsunix 系统的系统的 webweb 调试平台调试平台

Page 31: Solaris 10 C 编程

Solaris—Solaris— 时间函数时间函数 char *ctime(const time_t *clock);char *ctime(const time_t *clock); struct tm *localtime(const time_t *clock);struct tm *localtime(const time_t *clock); struct tm *gmtime(const time_t *clock);struct tm *gmtime(const time_t *clock); char *asctime(const struct tm *tm);-----------char *asctime(const struct tm *tm);----------- 以上非以上非 MT-SafeMT-Safechar *ctime_r(const time_t *clock, char *buf, int buflen);char *ctime_r(const time_t *clock, char *buf, int buflen);struct tm *localtime_r(const time_t *restrict clock, structstruct tm *localtime_r(const time_t *restrict clock, struct tm *restrict res);tm *restrict res);struct tm *gmtime_r(const time_t *restrict clock, struct tmstruct tm *gmtime_r(const time_t *restrict clock, struct tm *restrict res);*restrict res);char *asctime_r(const struct tm *restrict tm, char *restrictchar *asctime_r(const struct tm *restrict tm, char *restrict buf, int buflen);-------------------------buf, int buflen);------------------------- 以上为以上为 MT-Safe MT-Safe 推推荐荐

Page 32: Solaris 10 C 编程

Solaris—Solaris— 解析传递给程序的参解析传递给程序的参数数 如何在程序中使用执行时传递过来的参数?如何在程序中使用执行时传递过来的参数?例如:例如: ./arguments.o debug hello=1./arguments.o debug hello=1 。。 带有参数的带有参数的 main()main()函数头格式如下:函数头格式如下:int main(int argc, char * argv[])int main(int argc, char * argv[])其中,第一个参数其中,第一个参数 argcargc 是是 intint型的,它用来存放命令行型的,它用来存放命令行参数的个数,实际上参数的个数,实际上 argcargc 所存放的数值比命令行参数的所存放的数值比命令行参数的个数多个数多 11 ,即将命令字,即将命令字 (( 可执行文件名可执行文件名 )) 也计算在内。第也计算在内。第二个参数二个参数 argvargv 是一个一维的一级指针数组,它是用来存是一个一维的一级指针数组,它是用来存放命令行中各个参数和命令字的字符串的,并且规定:放命令行中各个参数和命令字的字符串的,并且规定:argv[0]argv[0] 存放命令字存放命令字argv[1]argv[1] 存放命令行中第一个参数存放命令行中第一个参数argv[2]argv[2] 存放命令行中第二个参数存放命令行中第二个参数……这里,这里, argcargc 的值和的值和 argv[]argv[] 各元素的值都是系统自动组赋各元素的值都是系统自动组赋值的。值的。

Page 33: Solaris 10 C 编程

Solaris—Solaris— 解析传递给程序的参解析传递给程序的参数数 程序范例程序范例#include "stdio.h"#include "stdio.h"int main(int argc, char *argv[])int main(int argc, char *argv[]){{ int i=0;int i=0; printf("The number of command line arguments is:%d\n",argc);printf("The number of command line arguments is:%d\n",argc); printf("The program name is:%s\n",argv[0]);printf("The program name is:%s\n",argv[0]); printf("The command line arguments:\n");printf("The command line arguments:\n"); for (i=1; i<argc; i++)for (i=1; i<argc; i++) {{ printf("argv[%d]:%s\n",i,argv[i]);printf("argv[%d]:%s\n",i,argv[i]); }} return 1;return 1;}}root@server1{/skystone} root@server1{/skystone} #./arguments.o debug hello=1#./arguments.o debug hello=1The number of command line arguments is:3The number of command line arguments is:3The program name is:./arguments.oThe program name is:./arguments.oThe command line arguments:The command line arguments:argv[1]:debugargv[1]:debugargv[2]:hello=1argv[2]:hello=1

Page 34: Solaris 10 C 编程

Solaris—Solaris— 守护进程守护进程 守护进程(守护进程( DaemonDaemon )是运行在后台的一种特殊)是运行在后台的一种特殊进程。它独立于控制终端并且周期性地执行某种进程。它独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件。守护进程是一任务或等待处理某些发生的事件。守护进程是一种很有用的进程。种很有用的进程。 UnixUnix 的大多数服务器就是用的大多数服务器就是用守护进程实现的。比如,守护进程实现的。比如, InternetInternet 服务器服务器 inetdinetd ,,WebWeb 服务器服务器 httpdhttpd 等。同时,守护进程完成许多等。同时,守护进程完成许多系统任务。比如,作业规划进程系统任务。比如,作业规划进程 crondcrond ,打印进,打印进程程 lpdlpd 等。 等。 守护进程的编程本身并不复杂,复杂的是各种版守护进程的编程本身并不复杂,复杂的是各种版本的本的 UnixUnix 的实现机制不尽相同,造成不同的实现机制不尽相同,造成不同 UnixUnix环境下守护进程的编程规则并不一致。这需要读环境下守护进程的编程规则并不一致。这需要读者注意,照搬某些书上的规则会出现错误的。 者注意,照搬某些书上的规则会出现错误的。

Page 35: Solaris 10 C 编程

Solaris—Solaris— 守护进程守护进程 forkfork 的含义的含义进程进程 AA 调用调用 int pid=fork()int pid=fork()之后,实际上是之后,实际上是克隆出来一个子进程克隆出来一个子进程 BB 。。进程进程 AA 是进程是进程 BB 的父进程;进程的父进程;进程 BB 是进程是进程 AA的子进程。的子进程。进程进程 BB 与进程与进程 AA 在堆栈、环境、状态方面在在堆栈、环境、状态方面在forkfork 的时候是一样的。的时候是一样的。在进程在进程 AA即父进程即父进程 fork()fork() 的返回值非的返回值非 00 ,返,返回的是子进程的回的是子进程的 pidpid;在进程;在进程 BB即子进程即子进程 fofork()rk()返回的是返回的是 00 。根据返回值,主子进程按。根据返回值,主子进程按照自己的不同逻辑执行下去。照自己的不同逻辑执行下去。

Page 36: Solaris 10 C 编程

Solaris—Solaris— 守护进程守护进程 SolarisSolaris 下守护进程实现函数下守护进程实现函数int sux_init_daemon(void) //int sux_init_daemon(void) // 返回值 返回值 !=2 !=2 退出程序退出程序{ { int pid; int pid; int i;int i; pid=fork();//pid=fork();// 派生一个进程派生一个进程 if (pid<0) return 0;//if (pid<0) return 0;// 派生失败派生失败 if(pid!=0) exit(0);//if(pid!=0) exit(0);// 是父进程,结束父进程 是父进程,结束父进程 //// 是第一子进程,后台继续执行 是第一子进程,后台继续执行 setsid();//setsid();// 第一子进程成为新的会话组长和进程组长 并与控制终端分离 第一子进程成为新的会话组长和进程组长 并与控制终端分离 signal( SIGHUP, SIG_IGN );//signal( SIGHUP, SIG_IGN );// 忽略忽略 SIGHUPSIGHUP pid=fork();//pid=fork();// 再次派生一个进程再次派生一个进程 if (pid<0) return 0;//if (pid<0) return 0;// 派生失败派生失败 if(pid!=0) exit(0);//if(pid!=0) exit(0);// 是第一子进程,结束第一子进程 是第一子进程,结束第一子进程 //// 是第二子进程,继续 第二子进程不再是会话组长 是第二子进程,继续 第二子进程不再是会话组长 for(i=0;i< getdtablesize();i++)//for(i=0;i< getdtablesize();i++)// 关闭打开的文件描述符 关闭打开的文件描述符 close(i); close(i); chdir("/tmp");//chdir("/tmp");// 改变工作目录到改变工作目录到 /tmp /tmp umask(0);//umask(0);// 重设文件创建掩模 重设文件创建掩模 return 2; return 2; }}

Page 37: Solaris 10 C 编程

Solaris—Solaris— 文件访问文件访问 打开文件打开文件FILE * fp=fopen(filename,“mode");FILE * fp=fopen(filename,“mode");modemode :: rr 文本方式读打开 文本方式读打开 ww 文本方式生成并写打开(原文件信息丢失)文本方式生成并写打开(原文件信息丢失) aa 文本方式打开文件追加文本方式打开文件追加 rbrb 二进制方式读打开二进制方式读打开 wbwb 二进制方式生成并写打开(原文件信息丢失)二进制方式生成并写打开(原文件信息丢失) abab 二进制方式打开文件追加二进制方式打开文件追加 r+br+b 二进制方式读二进制方式读 // 写打开文件写打开文件 w+bw+b 二进制方式生成读二进制方式生成读 // 写打开文件(原文件信息丢失)写打开文件(原文件信息丢失) a+ba+b 二进制方式读二进制方式读 // 写打开文件写打开文件 以读写方式打开文件时,读操作与写操作(无先后顺序)之间必以读写方式打开文件时,读操作与写操作(无先后顺序)之间必须有下列函数之一:须有下列函数之一: fflush(),fseek(),fsetpos(),rewind()fflush(),fseek(),fsetpos(),rewind()

Page 38: Solaris 10 C 编程

Solaris—Solaris— 文件访问文件访问 关闭文件关闭文件

int fcloseint fclose (( FILE* fpFILE* fp )) 重要函数重要函数

int fflush(FILE *fp)int fflush(FILE *fp)如果文件写打开,应调用如果文件写打开,应调用 fflush()fflush() 将输出将输出缓冲区中的内容物理写入文件。缓冲区中的内容物理写入文件。

Page 39: Solaris 10 C 编程

Solaris—Solaris— 文件访问文件访问 例一:读文本文件例一:读文本文件char readbuf[512];char readbuf[512];FILE *fp=fopen(filename,"rt");FILE *fp=fopen(filename,"rt");if (fp==NULL) if (fp==NULL) { { if (errno==ENOENT) return 2;//if (errno==ENOENT) return 2;//文件不存在文件不存在return -1;return -1;}}while (!feof(fp))while (!feof(fp)){{ if (fscanf(fp,"%511s\n",readbuf)!=1) continue;if (fscanf(fp,"%511s\n",readbuf)!=1) continue;… …… …}}if (fp!=NULL) if (fp!=NULL) {{fclose(fp);fclose(fp);fp=NULL;fp=NULL;}}

Page 40: Solaris 10 C 编程

Solaris—Solaris— 文件访问文件访问 例二:写文本文件例二:写文本文件 --日志文件日志文件

void handleftplog(char * s1)//void handleftplog(char * s1)// 写日志写日志 s1s1 中已经有中已经有 \n\n{{struct tm nowtm;struct tm nowtm; time_t nowtime;time_t nowtime;char log[1024];char log[1024];char filename[128];char filename[128]; struct timeval ntv;struct timeval ntv;gettimeofday(&ntv,NULL);gettimeofday(&ntv,NULL);nowtime=ntv.tv_sec;nowtime=ntv.tv_sec;localtime_r(&nowtime,&nowtm);localtime_r(&nowtime,&nowtm);sprintf(log,"%04d-%02d-%02d %02d:%02d:%02d [%d]%s",nowtm.tm_year+19sprintf(log,"%04d-%02d-%02d %02d:%02d:%02d [%d]%s",nowtm.tm_year+1900,nowtm.tm_mon+1,nowtm.tm_mday,00,nowtm.tm_mon+1,nowtm.tm_mday,nowtm.tm_hour,nowtm.tm_min,nowtm.tm_sec,getpid(),s1);nowtm.tm_hour,nowtm.tm_min,nowtm.tm_sec,getpid(),s1); sprintf(filename,"%s/%04d%02d%02d.log",FTP_LOG_PATH,nowtm.tsprintf(filename,"%s/%04d%02d%02d.log",FTP_LOG_PATH,nowtm.tm_year+1900,nowtm.tm_mon+1,nowtm.tm_mday);m_year+1900,nowtm.tm_mon+1,nowtm.tm_mday);FILE * fp fp=fopen(filename,"a+");FILE * fp fp=fopen(filename,"a+");if (fp==NULL) return;if (fp==NULL) return;fprintf(fp,"%s",log);fprintf(fp,"%s",log);fflush(fp);fflush(fp);fclose(fp);fclose(fp);}}

Page 41: Solaris 10 C 编程

Solaris—PosixSolaris—Posix 共享内存共享内存 PosixPosix 标准标准由于由于 UnixUnix版本的多样性,电子电气工程协会(版本的多样性,电子电气工程协会( IIEEEEEE )开发了一个独立的)开发了一个独立的 UnixUnix 标准,这个新的标准,这个新的ANSI UnixANSI Unix 标准被称为计算机环境的可移植性操标准被称为计算机环境的可移植性操作系统界面(作系统界面( POSIXPOSIX )。现有大部分)。现有大部分 UnixUnix 和流和流行版本都是遵循行版本都是遵循 POSIXPOSIX 标准的,而标准的,而 LinuxLinux从一从一开始就遵 循开始就遵 循 POSIXPOSIX 标准。标准。 共享内存:使得多个进程可以访问同一块内存空共享内存:使得多个进程可以访问同一块内存空间,是最快的可用间,是最快的可用 IPCIPC形式。是针对其他通信机形式。是针对其他通信机制运行效率较低而设计的。往往与其它通信机制,制运行效率较低而设计的。往往与其它通信机制,如信号量结合使用,来达到进程间的同步及互斥。如信号量结合使用,来达到进程间的同步及互斥。

Page 42: Solaris 10 C 编程

Solaris—PosixSolaris—Posix 共享内存共享内存 打开、创建共享内存打开、创建共享内存

int shm_open(const char *name, int oflag, int shm_open(const char *name, int oflag, mode_t mode);mode_t mode);name:name:共享内存名称,共享内存唯一标示,为兼共享内存名称,共享内存唯一标示,为兼容性考虑,一般以容性考虑,一般以 // 开头开头oflag:oflag:O_RDONLYO_RDONLY读方式打开读方式打开 O_RDWRO_RDWR读写方式打开读写方式打开 O_CREATO_CREAT 如果不存在则创建如果不存在则创建 O_EXCLO_EXCL 如果如果 O_CREATO_CREAT 同时被设置,同时被设置,那么共享内存如果已存在,就返回失败那么共享内存如果已存在,就返回失败 O_TRUNCO_TRUNC 如果共享内存被正确可读写打如果共享内存被正确可读写打开,那么该共享内存被重置为开,那么该共享内存被重置为 00长度长度

Page 43: Solaris 10 C 编程

Solaris—PosixSolaris—Posix 共享内存共享内存modemode 一般设置为一般设置为 S_IRUSR|S_IWUSR|S_S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTHIRGRP|S_IWGRP|S_IROTH|S_IWOTH ,,表示共享内存的访问权限。表示共享内存的访问权限。返回值:返回值:

成功成功 返回句柄返回句柄 >=0>=0失败失败 返回返回 -1-1 错误码 错误码 errornoerrorno

Page 44: Solaris 10 C 编程

Solaris—PosixSolaris—Posix 共享内存共享内存 关闭共享内存关闭共享内存int close(int fd);int close(int fd); 设置共享内存大小设置共享内存大小int ftruncate(int fd,off_t size);int ftruncate(int fd,off_t size);成功 返回成功 返回 00失败 返回失败 返回 -1 errno-1 errno 得到共享内存大小得到共享内存大小int fstat(int fd, struct stat * buf);int fstat(int fd, struct stat * buf);成功 返回成功 返回 00失败 返回失败 返回 -1 errno-1 errno 内存大小内存大小 =buf->st_size; =buf->st_size;

Page 45: Solaris 10 C 编程

Solaris—PosixSolaris—Posix 共享内存共享内存 映射内存地址映射内存地址void *mmap(void *addr, size_t len, int void *mmap(void *addr, size_t len, int prot, int flags, int fd, off_t off);prot, int flags, int fd, off_t off);

addraddr :指定文件应被映射到进程空间的起始地址,一般被指定一个空指针,:指定文件应被映射到进程空间的起始地址,一般被指定一个空指针,此时选择起始地址的任务留给内核来完成。 此时选择起始地址的任务留给内核来完成。 lenlen :是映射到调用进程地址空间的字节数,它从被映射文件开头:是映射到调用进程地址空间的字节数,它从被映射文件开头 offsetoffset 个个字节开始算起。字节开始算起。 prot prot :参数指定共享内存的访问权限。可取如下几个值的或::参数指定共享内存的访问权限。可取如下几个值的或: PROT_READPROT_READ (可读) (可读) , PROT_WRITE , PROT_WRITE (可写)(可写) , PROT_EXEC , PROT_EXEC (可执行)(可执行) , PROT_NONE, PROT_NONE (不可访问)。(不可访问)。 flagsflags :通常为:通常为 MAP_SHARED MAP_SHARED 。。fdfd :为即将映射到进程空间的文件描述字,一般由:为即将映射到进程空间的文件描述字,一般由 open()open()返回。返回。offoff :参数一般设为:参数一般设为 00 ,表示从文件头开始映射。,表示从文件头开始映射。 成功 返回指针成功 返回指针 失败 返回失败 返回 -1-1

Page 46: Solaris 10 C 编程

Solaris—PosixSolaris—Posix 共享内存共享内存 关闭映射关闭映射int munmap(void *addr, size_t len);int munmap(void *addr, size_t len);addraddr :: mmapmmap 映射的指针映射的指针lenlen :: mmapmmap映射的大小映射的大小返回成功 返回成功 00失败失败 -1-1 删除共享内存删除共享内存 int shm_unlink(const char *name);int shm_unlink(const char *name);namename :共享内存名:共享内存名返回成功 返回成功 00失败失败 -1-1

Page 47: Solaris 10 C 编程

Solaris—PosixSolaris—Posix 共享内存共享内存 头文件头文件#include<stdlib.h>#include<stdlib.h>#include<stdio.h>#include<stdio.h>#include<unistd.h>#include<unistd.h>#include<sys/mman.h>#include<sys/mman.h>#include<sys/time.h>#include<sys/time.h>#include<strings.h>#include<strings.h>#include<sys/types.h>#include<sys/types.h>#include<errno.h>#include<errno.h>#include<string.h>#include<string.h>#include<sys/stat.h>#include<sys/stat.h>#include<fcntl.h>#include<fcntl.h>#include<string.h>#include<string.h>#include <ctype.h>#include <ctype.h> 编译时加上编译时加上 -lrt-lrtgcc createshm.c -o createshm.o -lrtgcc createshm.c -o createshm.o -lrt

Page 48: Solaris 10 C 编程

int main(int argc,char * argv[])int main(int argc,char * argv[]) ////createshm.ccreateshm.c{{ printf("usage:%s shmname string\n",argv[0]);printf("usage:%s shmname string\n",argv[0]); if (argc!=3) return 0;if (argc!=3) return 0; size_t size=(strlen(argv[2])+1)*sizeof(char);size_t size=(strlen(argv[2])+1)*sizeof(char); shm_unlink(argv[1]);shm_unlink(argv[1]); int fd;int fd; fd=shm_open(argv[1],O_RDWR|O_CREAT|O_EXCL ,fd=shm_open(argv[1],O_RDWR|O_CREAT|O_EXCL , S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH); S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH); if (fd==-1)if (fd==-1) {{ printf("shm_open failed err:[%d]%s\n",errno,strerror(errno));printf("shm_open failed err:[%d]%s\n",errno,strerror(errno)); return 0;return 0; }} if (ftruncate(fd,size)==-1)if (ftruncate(fd,size)==-1) {{ printf("ftruncate failed err:[%d]%s\n",errno,strerror(errno));printf("ftruncate failed err:[%d]%s\n",errno,strerror(errno)); }} char * p=NULL;char * p=NULL; p=(char *)mmap(NULL,size,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);p=(char *)mmap(NULL,size,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0); if ((int)p==-1)if ((int)p==-1) {{ printf("mmap failed err:[%d]%s\n",errno,strerror(errno));printf("mmap failed err:[%d]%s\n",errno,strerror(errno)); }} memcpy(p,argv[2],size);memcpy(p,argv[2],size); munmap(p,size);munmap(p,size); close(fd);close(fd); printf("ok\n");printf("ok\n");}}

Page 49: Solaris 10 C 编程

int main(int argc,char * argv[])int main(int argc,char * argv[]) //readshm.c//readshm.c{{ printf("usage:%s shmname\n",argv[0]);printf("usage:%s shmname\n",argv[0]); if (argc!=2) return 0;if (argc!=2) return 0; size_t size;struct stat statbuf;size_t size;struct stat statbuf; int fd;int fd; fd=shm_open(argv[1],O_RDWR,fd=shm_open(argv[1],O_RDWR, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH); S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH); if (fd==-1)if (fd==-1) {{ printf("shm_open failed err:[%d]%s\n",errno,strerror(errno));printf("shm_open failed err:[%d]%s\n",errno,strerror(errno)); return 0;return 0; }} if (fstat(fd, &statbuf)==-1)if (fstat(fd, &statbuf)==-1) {{ printf("fstat failed err:[%d]%s\n",errno,strerror(errno));printf("fstat failed err:[%d]%s\n",errno,strerror(errno)); }} size=statbuf.st_size;size=statbuf.st_size; char * p=NULL;char * p=NULL; p=(char *)mmap(NULL,size,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);p=(char *)mmap(NULL,size,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0); if ((int)p==-1)if ((int)p==-1) {{ printf("mmap failed err:[%d]%s\n",errno,strerror(errno));printf("mmap failed err:[%d]%s\n",errno,strerror(errno)); }} printf("readshm:%s\n",p);printf("readshm:%s\n",p); munmap(p,size);munmap(p,size); close(fd);close(fd); printf("ok\n");printf("ok\n");}}

Page 50: Solaris 10 C 编程

Solaris—PosixSolaris—Posix 共享内存共享内存 #gcc createshm.c -o createshm.o -lrt#gcc createshm.c -o createshm.o -lrt #gcc readshm.c -o readshm.o -lrt#gcc readshm.c -o readshm.o -lrt #./createshm.o /tshm helloworld!#./createshm.o /tshm helloworld!usage:./createshm.o shmname stringusage:./createshm.o shmname stringokok #./readshm.o /tshm#./readshm.o /tshmusage:./readshm.o shmnameusage:./readshm.o shmnamereadshm:helloworld!readshm:helloworld!okok

Page 51: Solaris 10 C 编程

Solaris—PosixSolaris—Posix 信号量信号量 信号量(信号量( semaphoresemaphore ):主要作为进程间以及同):主要作为进程间以及同一进程不同线程之间的同步手段。一进程不同线程之间的同步手段。 打开、创建信号量打开、创建信号量sem_t *sem_open(const char *name, int oflag,sem_t *sem_open(const char *name, int oflag,/* unsigned long mode, unsigned int value */);/* unsigned long mode, unsigned int value */);

namename :信号量名称,信号量唯一标示,为兼容性:信号量名称,信号量唯一标示,为兼容性考虑,一般以考虑,一般以 // 开头开头oflagoflag :: O_RDWRO_RDWR读写方式打开读写方式打开 O_CREATO_CREAT 如果不存在则创建如果不存在则创建 O_EXCLO_EXCL 如果如果 O_CREATO_CREAT 同时被设置,那么信同时被设置,那么信号量如果已存在,就返回失败号量如果已存在,就返回失败

Page 52: Solaris 10 C 编程

Solaris—PosixSolaris—Posix 信号量信号量modemode 一般设置为一般设置为 S_IRUSR|S_IWUSR|S_S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTHIRGRP|S_IWGRP|S_IROTH|S_IWOTH ,,表示共享内存的访问权限。表示共享内存的访问权限。valuevalue :信号量初值:信号量初值返回值:返回值:成功成功 返回句柄返回句柄失败失败 返回返回 SEM_FAILEDSEM_FAILED错误码 错误码 errornoerrorno 打开信号量时打开信号量时 mode,valuemode,value 参数不需要参数不需要

Page 53: Solaris 10 C 编程

Solaris—PosixSolaris—Posix 信号量信号量 关闭信号量关闭信号量

int sem_close(sem_t *sem);int sem_close(sem_t *sem);返回成功 返回成功 0 0 失败失败 -1-1

等待信号量(死等)等待信号量(死等)int sem_wait(sem_t *sem);int sem_wait(sem_t *sem);返回成功 返回成功 0 0 失败失败 -1-1

等待信号量(立即返回)等待信号量(立即返回)int sem_trywait(sem_t *sem);int sem_trywait(sem_t *sem);返回成功返回成功 -- 等到信号量 等到信号量 0 0 失败失败 -1-1 (如果(如果 errno =errno == EAGAIN= EAGAIN ,表示没等到信号量),表示没等到信号量)

Page 54: Solaris 10 C 编程

Solaris—PosixSolaris—Posix 信号量信号量 等待信号量(带绝对时间超时)等待信号量(带绝对时间超时)

int sem_timedwait(sem_t *restrict sem, const int sem_timedwait(sem_t *restrict sem, const struct timespec *restrict abs_timeout);struct timespec *restrict abs_timeout);返回成功返回成功 -- 等到信号量等到信号量 0 0 失败失败 -1-1 (如果(如果 errno==ETIMerrno==ETIMEDOUTEDOUT表示没等到)表示没等到) abs_timeoutabs_timeout :绝对时间,等待超过这个时间就返回。:绝对时间,等待超过这个时间就返回。

等待信号量(带相对时间超时)等待信号量(带相对时间超时) ---- 与与 LinuxLinux 不兼容不兼容int sem_reltimedwait_np(sem_t *restrict sem, coint sem_reltimedwait_np(sem_t *restrict sem, const struct timespec *restrict rel_timeout);nst struct timespec *restrict rel_timeout);

Page 55: Solaris 10 C 编程

Solaris—PosixSolaris—Posix 信号量信号量 释放信号量释放信号量

int sem_post(sem_t *sem);int sem_post(sem_t *sem);返回成功 返回成功 0 0 失败失败 -1-1

删除信号量删除信号量int sem_unlink(const char *name);int sem_unlink(const char *name);返回成功 返回成功 0 0 失败失败 -1-1

Page 56: Solaris 10 C 编程

Solaris—PosixSolaris—Posix 共享内存与信共享内存与信号量号量 一般应用一般应用主程序:创建共享内存(一定要用主程序:创建共享内存(一定要用 memsememsett 将内存区清将内存区清 00 ),信号量),信号量其他程序:链接共享内存,链接信号量,其他程序:链接共享内存,链接信号量,{{ 等待信号量,处理共享内存,释放信号量等待信号量,处理共享内存,释放信号量

… … … …… … … …}}释放共享内存,释放信号量释放共享内存,释放信号量

Page 57: Solaris 10 C 编程

Solaris—PosixSolaris—Posix 共享内存与信共享内存与信号量号量 PosixPosix 共享内存的重要特性共享内存的重要特性PosixPosix 共享内存支持在被其他人映射的前提共享内存支持在被其他人映射的前提下,改变共享内存的大小。下,改变共享内存的大小。要点:要点: 步进式增加或缩小步进式增加或缩小在共享内存中含有该共享内存的在共享内存中含有该共享内存的大小信息大小信息 所有程序等待到信号量之后,如所有程序等待到信号量之后,如果共享内存与自己映射的发生改变,则需果共享内存与自己映射的发生改变,则需要重新映射要重新映射

Page 58: Solaris 10 C 编程

Solaris—PosixSolaris—Posix 共享内存与信共享内存与信号量号量 在在 SCADASCADA 通讯管理机中的实际意义通讯管理机中的实际意义共享内存的可伸缩性与无参数的通讯管理机相匹共享内存的可伸缩性与无参数的通讯管理机相匹配。配。通讯管理机真正做到可伸缩性。通讯管理机真正做到可伸缩性。

思考题思考题程序一:创建共享内存,信号量。程序一:创建共享内存,信号量。程序二:将用户添加的字符串添加到共享内存后程序二:将用户添加的字符串添加到共享内存后面。面。程序三:每程序三:每 55秒钟将共享内存的信息输出出来。秒钟将共享内存的信息输出出来。

Page 59: Solaris 10 C 编程

Solaris—TCP/IPSolaris—TCP/IP 编程编程 I/OI/O 模式模式阻塞模式阻塞模式非阻塞模式非阻塞模式 服务器模式服务器模式单进程单进程 I/OI/O 复用复用多线程多线程多进程多进程 编译编译gcc mysocket.c –o mysocket.o -lsocket -lnsl -lrgcc mysocket.c –o mysocket.o -lsocket -lnsl -lresolvesolv

Page 60: Solaris 10 C 编程

Solaris—TCP/IPSolaris—TCP/IP 编程编程 阻塞模式阻塞模式所有的所有的 I/OI/O 函数都是同步返回的。 函数都是同步返回的。 包括客户端的包括客户端的 connectconnect服务端的服务端的 acceptaccept ,, connectconnect客户端、服务端的客户端、服务端的 sendsend ,, recvrecv会造成程序在某个会造成程序在某个 I/OI/O 操作时挂起。操作时挂起。I/OI/O 效率低。效率低。

Page 61: Solaris 10 C 编程

Solaris—TCP/IPSolaris—TCP/IP 编程编程 非阻塞模式非阻塞模式所有的所有的 I/OI/O 函数都是异步立即返回的。 函数都是异步立即返回的。 包括客户端的包括客户端的 connectconnect服务端的服务端的 acceptaccept ,, connectconnect客户端、服务端的客户端、服务端的 sendsend ,, recvrecv程序不会阻塞在任何程序不会阻塞在任何 I/OI/O 操作上。操作上。I/OI/O 效率高。效率高。

Page 62: Solaris 10 C 编程

Solaris—TCP/IPSolaris—TCP/IP 编程编程 初始化初始化 socketsocketint initsocket(int * fd,struct sockaddr_in * mybind,char * ip,int int initsocket(int * fd,struct sockaddr_in * mybind,char * ip,int port,char * sockname,int canlisten)//port,char * sockname,int canlisten)// 初始化初始化 socketsocket{{ int optint opt ;;int bufsize=20480;int bufsize=20480;int flags;int flags;if ((*fd=socket(AF_INET,SOCK_STREAM,0))==-1)if ((*fd=socket(AF_INET,SOCK_STREAM,0))==-1){{ return -1;return -1;}}opt=1;// SO_REUSEADDR;opt=1;// SO_REUSEADDR; if (setsockopt(*fd,SOL_SOCKET,SO_REUSEADDR,&opt,if (setsockopt(*fd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt))<0) sizeof(opt))<0) {{ close(*fd);*fd=-1;return -1;close(*fd);*fd=-1;return -1;};};

Page 63: Solaris 10 C 编程

Solaris—TCP/IPSolaris—TCP/IP 编程编程////设置接收缓冲区设置接收缓冲区if (setsockopt(*fd,SOL_SOCKET,SO_RCVBUF,(char *)&bufsize,sizeofif (setsockopt(*fd,SOL_SOCKET,SO_RCVBUF,(char *)&bufsize,sizeof(bufsize))<0) (bufsize))<0) {{ close(*fd);*fd=-1;return -1;close(*fd);*fd=-1;return -1;};};////设置发送缓冲区设置发送缓冲区if (setsockopt(*fd,SOL_SOCKET,SO_SNDBUF,(char *)&bufsize,sizeofif (setsockopt(*fd,SOL_SOCKET,SO_SNDBUF,(char *)&bufsize,sizeof(bufsize))<0) (bufsize))<0) {{ close(*fd);*fd=-1;return -1;close(*fd);*fd=-1;return -1;};};bzero(mybind,sizeof(mybind));bzero(mybind,sizeof(mybind));mybind->sin_family=AF_INET;mybind->sin_family=AF_INET;mybind->sin_port=htons(port);mybind->sin_port=htons(port);memset(&mybind->sin_addr,0,sizeof(mybind->sin_addr));memset(&mybind->sin_addr,0,sizeof(mybind->sin_addr));inet_aton(ip,(struct in_addr *)&mybind->sin_addr.s_addr);inet_aton(ip,(struct in_addr *)&mybind->sin_addr.s_addr);if (bind(*fd,(struct sockaddr *)mybind,sizeof(struct sockaddr))==-1)if (bind(*fd,(struct sockaddr *)mybind,sizeof(struct sockaddr))==-1){{ close(*fd);*fd=-1;return -1;close(*fd);*fd=-1;return -1;};};

Page 64: Solaris 10 C 编程

Solaris—TCP/IPSolaris—TCP/IP 编程编程if (canlisten==1)if (canlisten==1){{ if(listen(*fd,128)==-1)if(listen(*fd,128)==-1){{ close(*fd);*fd=-1;return -1;close(*fd);*fd=-1;return -1;}}}}flags=fcntl(*fd,F_GETFL,0);flags=fcntl(*fd,F_GETFL,0);fcntl(*fd,F_SETFL,flags|O_NONBLOCK);fcntl(*fd,F_SETFL,flags|O_NONBLOCK);if (port==0)if (port==0){{ struct sockaddr_in sa;struct sockaddr_in sa;int ll=sizeof(sa);int ll=sizeof(sa);if (getsockname(*fd,&sa,&ll)==0)if (getsockname(*fd,&sa,&ll)==0){{ memcpy(&mybind->sin_port,&sa.sin_port,sizeof(mymemcpy(&mybind->sin_port,&sa.sin_port,sizeof(mybind->sin_port));bind->sin_port));}}}}return 1;return 1;}}

Page 65: Solaris 10 C 编程

Solaris—TCP/IPSolaris—TCP/IP 编程编程 关闭关闭 socketsocketint releasesocket(int *fd)//int releasesocket(int *fd)// 释放释放 socketsocket{{ if ((*fd)==-1) if ((*fd)==-1) {{ return 1;return 1;}}shutdown((*fd),SHUT_RDWR);shutdown((*fd),SHUT_RDWR);close(*fd);close(*fd);(*fd)=-1;(*fd)=-1;return 1;return 1;}}

Page 66: Solaris 10 C 编程

Solaris—TCP/IPSolaris—TCP/IP 编程编程 非阻塞实现重要函数非阻塞实现重要函数 selectselect int select(int nfds, fd_set *restrict readfds, fdint select(int nfds, fd_set *restrict readfds, fd_set *res-trict writefds, fd_set *restrict err_set *res-trict writefds, fd_set *restrict errorfds, struct timeval *restrict timeout);orfds, struct timeval *restrict timeout);

nfdsnfds :检测句柄范围,通常为:检测句柄范围,通常为 maxfd+1maxfd+1readfdsreadfds , , writefdswritefds , , errorfdserrorfds :判断可读、:判断可读、可写、出错的句柄集合可写、出错的句柄集合 timeouttimeout :超时时间:超时时间返回成功返回成功 >=0 >=0 返回满足条件的句柄数 失败 返回满足条件的句柄数 失败 -1-1

Page 67: Solaris 10 C 编程

Solaris—TCP/IPSolaris—TCP/IP 编程编程 客户端连接服务器流程客户端连接服务器流程char hint[512];char hint[512];int co,cook=-1;int co,cook=-1;clientlen=sizeof(client);clientlen=sizeof(client);client.sin_family=AF_INET;client.sin_family=AF_INET;client.sin_port=htons(m_serverport);client.sin_port=htons(m_serverport);inet_aton(serverip,(struct in_addr *)&client.sin_addr.s_addr);inet_aton(serverip,(struct in_addr *)&client.sin_addr.s_addr);if ((if ((现在时间现在时间 -- 开始连接时间开始连接时间 )>)>连接超时参数连接超时参数 )//)//超时超时{{ releasesocket();releasesocket();return -1;return -1;}}co=connect(m_fd,(struct sockaddr *)&client,clientlen);co=connect(m_fd,(struct sockaddr *)&client,clientlen);if ((co==-1)&&(errno==EISCONN))//Transport endpoint is alreaif ((co==-1)&&(errno==EISCONN))//Transport endpoint is already connecteddy connected{{ cook=1;cook=1;co=1;co=1;}}

Page 68: Solaris 10 C 编程

Solaris—TCP/IPSolaris—TCP/IP 编程编程if(((co==-1)&&(errno==EINPROGRESS))||if(((co==-1)&&(errno==EINPROGRESS))||((co==-1)&&(errno==EALREADY))((co==-1)&&(errno==EALREADY))||((co==-1)&&(errno==EWOULDBLOCK)))||((co==-1)&&(errno==EWOULDBLOCK))){{usleep(200000);usleep(200000);return 0;return 0;}else{}else{if(co==-1)if(co==-1){{////连接失败连接失败releasesocket();releasesocket();return -1;return -1;}else{}else{cook=1;cook=1;}}}}if (cook==1)if (cook==1){{////连接成功连接成功return 1;return 1;}}

Page 69: Solaris 10 C 编程

Solaris—TCP/IPSolaris—TCP/IP 编程编程 处理连接好的处理连接好的 socketsocket读写与异常读写与异常tm.tv_sec=0;tm.tv_sec=0;tm.tv_usec=10000;tm.tv_usec=10000; FD_ZERO(&rset); FD_ZERO(&wset);FD_ZERO(&rset); FD_ZERO(&wset); FD_SET(m_fd,&rset); FD_SET(m_fd,&wset);FD_SET(m_fd,&rset); FD_SET(m_fd,&wset);nready=select(maxfd+1,&rset,&wset,NULL,nready=select(maxfd+1,&rset,&wset,NULL,&tm); &tm); if (nready==0) {return 1;}if (nready==0) {return 1;}if (FD_ISSET(m_fd,&rset))if (FD_ISSET(m_fd,&rset)){{ int recvnum=0;int recvnum=0;unsigned charbuf[4096];unsigned charbuf[4096];recvnum=recv(m_fd,buf, 4096,0);recvnum=recv(m_fd,buf, 4096,0);

Page 70: Solaris 10 C 编程

if ((recvnum==-1)&&(errno==EWOULDBLOCK))//if ((recvnum==-1)&&(errno==EWOULDBLOCK))// 超时阻塞超时阻塞return 1;return 1;if ((recvnum==-1)&&(errno!=EWOULDBLOCK))if ((recvnum==-1)&&(errno!=EWOULDBLOCK)) ////错误错误{{releasesocket();releasesocket();return 1;return 1;}}if (recvnum==0)if (recvnum==0) ////客户端已关闭客户端已关闭{{releasesocket();releasesocket();return 1;return 1;}}//// 处理数据处理数据}}

Solaris—TCP/IPSolaris—TCP/IP 编程编程

Page 71: Solaris 10 C 编程

Solaris—TCP/IPSolaris—TCP/IP 编程编程if ((m_fd!=-1)&&(FD_ISSET(m_fd,&wset)))if ((m_fd!=-1)&&(FD_ISSET(m_fd,&wset))){{written=send(m_fd,buf,bufcount,0);written=send(m_fd,buf,bufcount,0);if (written<0)if (written<0){{if (errno==EWOULDBLOCK)if (errno==EWOULDBLOCK){{//// 发送缓冲区满,写不进去发送缓冲区满,写不进去}else{}else{//// 发送出错发送出错releasesocket();releasesocket();return -1;return -1;}}}else{}else{//// 数据发送出去数据发送出去}}}}return 1;return 1;}}

Page 72: Solaris 10 C 编程

Solaris—TCP/IPSolaris—TCP/IP 编程编程 TCP-ServerTCP-Server 编程模型编程模型单进程单进程 I/OI/O 复用:一个进程管理所有连接,复用:一个进程管理所有连接,程序复杂度较高,多应用于实时数据程序复杂度较高,多应用于实时数据的的 服务。服务。多线程:每个线程对应一个连接,注意线多线程:每个线程对应一个连接,注意线程间互斥。程间互斥。多进程:每个进程对应一个连接,连接之多进程:每个进程对应一个连接,连接之间关联度小。间关联度小。

Page 73: Solaris 10 C 编程

Solaris—TCP/IPSolaris—TCP/IP 编程编程 单进程单进程 I/OI/O 复用模型复用模型FD_ZERO(&rset);FD_ZERO(&rset);FD_ZERO(&wset);FD_ZERO(&wset);maxfd=m_fd;maxfd=m_fd;if (if ( 处在等待处在等待 acceptaccept状态状态 )){{FD_SET(m_fd,&rset);//FD_SET(m_fd,&rset);// 加入套接字加入套接字 ,,读套接字读套接字}}for (i=0;i<for (i=0;i<已连接客户端数已连接客户端数 ;i++);i++){{FD_SET(m_clients[i].fd,&rset);//FD_SET(m_clients[i].fd,&rset);// 加入套接字加入套接字 ,,读套接字读套接字if (maxfd<m_clients[i].fd) maxfd=m_clients[i].fd;if (maxfd<m_clients[i].fd) maxfd=m_clients[i].fd;}}tm.tv_sec=0; tm.tv_sec=0; tm.tv_usec=10000;tm.tv_usec=10000;nready=select(maxfd+1,&rset,NULL,NULL,&tm); nready=select(maxfd+1,&rset,NULL,NULL,&tm); clientlen=sizeof(client);clientlen=sizeof(client);if(FD_ISSET(m_fd,&rset))//if(FD_ISSET(m_fd,&rset))//判断是否有判断是否有 acceptaccept请求请求{{设置为处在处理设置为处在处理 accpetaccpet状态状态}}

Page 74: Solaris 10 C 编程

Solaris—TCP/IPSolaris—TCP/IP 编程编程if (if ( 处在处理处在处理 accpetaccpet 状态状态 )){{ connectfd=accept(m_fd,(struct sockaddr *)&client,&clientlen);connectfd=accept(m_fd,(struct sockaddr *)&client,&clientlen);if((connectfd==-1)&&(errno==EWOULDBLOCK))//if((connectfd==-1)&&(errno==EWOULDBLOCK))// 阻塞阻塞{{}else{}else{ if((connectfd==-1)&&(errno!=EWOULDBLOCK))//if((connectfd==-1)&&(errno!=EWOULDBLOCK))// 非阻塞,非阻塞,{{ releasesocket(&m_fd);releasesocket(&m_fd);return -1;return -1;}else{}else{ 将将 connectfdconnectfd 加入已连接缓冲池加入已连接缓冲池设置为处在等待设置为处在等待 acceptaccept 状态状态}}}}}}for (i=0;i<for (i=0;i< 已连接客户端数已连接客户端数 ;i++);i++){{ 处理连接池内的每个连接处理连接池内的每个连接... ...... ...}}

Page 75: Solaris 10 C 编程

Solaris—TCP/IPSolaris—TCP/IP 编程编程 多进程模型多进程模型//// 连接成功连接成功sprintf(hh,"sprintf(hh," 连接成功 连接成功 from %s from %s %d\n",inet_ntoa(client.sin_addr),ntohs(client.sin_port));%d\n",inet_ntoa(client.sin_addr),ntohs(client.sin_port));pid_t pid;pid_t pid; //// 进程进程 IDIDpid=fork();pid=fork(); //// 创建一个进程的系统调用创建一个进程的系统调用if(pid>0)//if(pid>0)// 主进程主进程{{ g_status=0;g_status=0;close(connectfd);close(connectfd);connectfd=-1;connectfd=-1;}}if(pid==0)//if(pid==0)// 产生新进程子进程产生新进程子进程{{ g_status=1;g_status=1;close(g_lis_fd); //close(g_lis_fd); // 关闭监听套接口关闭监听套接口g_lis_fd=-1;g_lis_fd=-1;g_con_fd=connectfd;g_con_fd=connectfd;}}if (pid<0)//if (pid<0)// 出错了出错了{{ g_con_fd=connectfd;g_con_fd=connectfd;close(g_con_fd);close(g_con_fd);g_con_fd=-1;g_con_fd=-1;}}

Page 76: Solaris 10 C 编程

Solaris—UDPSolaris—UDP 广播编程广播编程 初始化初始化 socketsocket

if ((m_fd=socket(AF_INET,SOCK_DGRAM,0))=if ((m_fd=socket(AF_INET,SOCK_DGRAM,0))==-1)=-1)bzero(&m_bind,sizeof(m_bind));bzero(&m_bind,sizeof(m_bind));m_bind.sin_family=AF_INET;m_bind.sin_family=AF_INET;m_bind.sin_port=htons(m_port);m_bind.sin_port=htons(m_port);m_bind.sin_addr.s_addr=htonl(INADDRm_bind.sin_addr.s_addr=htonl(INADDR_ANY);_ANY);if (bind(m_fd,(struct sockaddr *)&m_binif (bind(m_fd,(struct sockaddr *)&m_bind,sizeof(struct sockaddr))==-1)d,sizeof(struct sockaddr))==-1)

Page 77: Solaris 10 C 编程

Solaris—UDPSolaris—UDP 广播编程广播编程 发送发送m_aim.sin_family=AF_INET;m_aim.sin_family=AF_INET;m_aim.sin_port=htons(m_port);m_aim.sin_port=htons(m_port);m_aim.sin_addr.s_addr=htonl(INADDR_BRm_aim.sin_addr.s_addr=htonl(INADDR_BROADCAST);OADCAST);inet_aton(m_broadcastip,&m_aim.sin_addr);inet_aton(m_broadcastip,&m_aim.sin_addr);i=sendto(fd,buf,bufcount,0,(struct sockaddr i=sendto(fd,buf,bufcount,0,(struct sockaddr *)&m_aim,sin_size);*)&m_aim,sin_size); 接收接收recvnum=recvfrom(fd,recvbuf,2048,0,(struct recvnum=recvfrom(fd,recvbuf,2048,0,(struct sockaddr *)&from,(socklen_t *)&sin_size);sockaddr *)&from,(socklen_t *)&sin_size);

Page 78: Solaris 10 C 编程

Solaris—UDPSolaris—UDP 广播编程广播编程 要点要点

UDPUDP 是基于报文格式的,收发都是一包一是基于报文格式的,收发都是一包一包的。包的。UDPUDP 非阻塞的,写成功代表写入缓冲区。非阻塞的,写成功代表写入缓冲区。UDPUDP 不保证接收到的数据的完整、顺序。不保证接收到的数据的完整、顺序。UDPUDP广播经常采用连发广播经常采用连发 33 次(每次之间有次(每次之间有间隔),接收端过滤的模式防止丢包。间隔),接收端过滤的模式防止丢包。

Page 79: Solaris 10 C 编程

Solaris—Solaris— 共享库编程共享库编程 在在 WINDOWSWINDOWS 系统中有很多的动态链接库系统中有很多的动态链接库 (( 以以 ..DLLDLL 为后缀的文件,为后缀的文件, DLLDLL即即 Dynamic Link LiDynamic Link Library)brary) 。这种动态链接库,和静态函数库不同,。这种动态链接库,和静态函数库不同,它里面的函数并不是执行程序本身的一部分,而它里面的函数并不是执行程序本身的一部分,而是根据执行程序需要按需装入,同时其执行代码是根据执行程序需要按需装入,同时其执行代码可在多个执行程序间共享,节省了空间,提高了可在多个执行程序间共享,节省了空间,提高了效率,具备很高的灵活性,得到越来越多程序员效率,具备很高的灵活性,得到越来越多程序员和用户的青睐。和用户的青睐。 UnixUnix 的动态链接库不仅有,而且为数不少。在的动态链接库不仅有,而且为数不少。在 /l/libib 目录下,就有许多以目录下,就有许多以 .so.so 作后缀的文件,这就作后缀的文件,这就是是 UnixUnix 系统应用的动态链接库,只不过与系统应用的动态链接库,只不过与 WINWINDOWSDOWS叫法不同,它叫叫法不同,它叫 soso ,即,即 Shared ObjectShared Object ,,共享对象。共享对象。 (( 在在 LINUXLINUX 下,静态函数库是以下,静态函数库是以 .a.a作后缀的作后缀的 ))

Page 80: Solaris 10 C 编程

Solaris—Solaris— 共享库编程共享库编程 共享库编程共享库编程头文件头文件 mylib.hmylib.h#include "dlfcn.h"#include "dlfcn.h"#include "pthread.h"#include "pthread.h"typedef void (*lib_addtick)();typedef void (*lib_addtick)();typedef int (*lib_gettick)();typedef int (*lib_gettick)();typedef void (*lib_init)();typedef void (*lib_init)();typedef void (*lib_release)();typedef void (*lib_release)();typedef struct typedef struct {{ lib_init pinit;lib_init pinit; lib_release prelease;lib_release prelease; lib_addtick paddtick;lib_addtick paddtick; lib_gettick pgettick;lib_gettick pgettick;}S_INTERFACE;}S_INTERFACE;typedef S_INTERFACE * P_INTERFACE;typedef S_INTERFACE * P_INTERFACE;typedef void (*lib_getinterface)(P_INTERFACE pin);typedef void (*lib_getinterface)(P_INTERFACE pin);

Page 81: Solaris 10 C 编程

Solaris—Solaris— 共享库编程共享库编程 共享库编程共享库编程mylib.cmylib.c#include "stdio.h"#include "stdio.h"#include "mylib.h"#include "mylib.h"int g_tick=0;int g_tick=0;pthread_mutex_t mymutex;//pthread_mutex_t mymutex;// 互斥锁互斥锁void init()void init(){{ pthread_mutex_init(&mymutex, NULL);pthread_mutex_init(&mymutex, NULL);}}void release()void release(){{ pthread_mutex_destroy(&mymutex);pthread_mutex_destroy(&mymutex);}}

Page 82: Solaris 10 C 编程

Solaris—Solaris— 共享库编程共享库编程void addtick()void addtick(){{ pthread_mutex_lock(&mymutex);pthread_mutex_lock(&mymutex); g_tick++;g_tick++; pthread_mutex_unlock(&mymutex);pthread_mutex_unlock(&mymutex);}}int gettick()int gettick(){{ int i;int i; pthread_mutex_lock(&mymutex);pthread_mutex_lock(&mymutex); i=g_tick;i=g_tick; pthread_mutex_unlock(&mymutex);pthread_mutex_unlock(&mymutex); return i;return i;}}extern "C" void getinterface(P_INTERFACE pi)extern "C" void getinterface(P_INTERFACE pi){{ pi->pinit=&init;pi->pinit=&init; pi->prelease=&release;pi->prelease=&release; pi->paddtick=&addtick;pi->paddtick=&addtick; pi->pgettick=&gettick;pi->pgettick=&gettick;}}

Page 83: Solaris 10 C 编程

Solaris—Solaris— 共享库编程共享库编程 编译动态库编译动态库

g++ -c -fpic mylib.cg++ -c -fpic mylib.cg++ -fpic -o mylib.so ./mylib.o -shared -lpthread

Page 84: Solaris 10 C 编程

Solaris—Solaris— 共享库编程共享库编程 调用程序调用程序#include "mylib.h"#include "mylib.h"void (* m_getinterface)(P_INTERFACE p);//void (* m_getinterface)(P_INTERFACE p);// 得到接口函数指针集合得到接口函数指针集合void * m_ds=NULL;void * m_ds=NULL;S_INTERFACE m_ps;S_INTERFACE m_ps;void * start_add(void * p)void * start_add(void * p){{ while(1)while(1) {{ printf("%d---add\n",(*(int *)p));printf("%d---add\n",(*(int *)p)); m_ps.paddtick();m_ps.paddtick(); sleep(*(int*)p);sleep(*(int*)p); }}}}void * start_show(void * p)void * start_show(void * p){{ while(1)while(1) {{ printf("show----%d\n",m_ps.pgettick());printf("show----%d\n",m_ps.pgettick()); sleep(1);sleep(1); }}}}

Page 85: Solaris 10 C 编程

int main()int main(){{ pthread_t add1,add2,show;pthread_t add1,add2,show; int i1,i2;int i1,i2; m_ds= dlopen("./mylib.so", RTLD_LAZY);m_ds= dlopen("./mylib.so", RTLD_LAZY); if(m_ds== NULL)if(m_ds== NULL) {{ return -1;return -1; }} m_getinterface=(lib_getinterface)dlsym(m_ds,"getinterface");m_getinterface=(lib_getinterface)dlsym(m_ds,"getinterface"); if(m_getinterface== NULL)if(m_getinterface== NULL) {{ dlclose(m_ds);dlclose(m_ds); return(-1);return(-1); }} m_getinterface(&m_ps);m_getinterface(&m_ps); m_ps.pinit();m_ps.pinit(); i1=1;i1=1; pthread_create(&add1,NULL,start_add,&i1);pthread_create(&add1,NULL,start_add,&i1); i2=2;i2=2; pthread_create(&add2,NULL,start_add,&i2);pthread_create(&add2,NULL,start_add,&i2); pthread_create(&show,NULL,start_show,NULL);pthread_create(&show,NULL,start_show,NULL); while(1){sleep(1);}while(1){sleep(1);} m_ps.prelease();m_ps.prelease(); printf("ok\n");printf("ok\n"); return 1;return 1;}}

Page 86: Solaris 10 C 编程

Solaris—Solaris— 共享库编程共享库编程 共享库编程要点共享库编程要点共享库中的全局变量,函数与调用程序在共享库中的全局变量,函数与调用程序在一个地址空间,严禁重名,否则会有不可一个地址空间,严禁重名,否则会有不可预测的问题。预测的问题。共享库应封装线程级别的互斥锁支持,以共享库应封装线程级别的互斥锁支持,以解决多线程调用时的安全问题。解决多线程调用时的安全问题。共享库实例与调用程序一一对应,程序调共享库实例与调用程序一一对应,程序调用一次共享库,共享库实例化一次。用一次共享库,共享库实例化一次。

Page 87: Solaris 10 C 编程

Solaris—Solaris— 系统相对时间系统相对时间 得到系统从开机运行到现在经过的毫秒数得到系统从开机运行到现在经过的毫秒数int sux_gettickcount(unsigned long * last)//int sux_gettickcount(unsigned long * last)// 得得到到 msms 级系统计时器 级系统计时器 {{ hrtime_t now;hrtime_t now;now=gethrtime();now=gethrtime();*last=now/1000000;*last=now/1000000; return 1;return 1;}} 在程序中对该变量自始自终使用在程序中对该变量自始自终使用 unsigned longunsigned long变量,使用差值得到两个时间戳之间的时间,不变量,使用差值得到两个时间戳之间的时间,不受校时影响。受校时影响。

Page 88: Solaris 10 C 编程

Solaris—Solaris— 常用查找算法常用查找算法 二分法二分法实现简单,要求素材按关键字排序,素材实现简单,要求素材按关键字排序,素材规模规模 <10000<10000 时性能良好。时性能良好。

HashHash 查找查找实现复杂,要求找到散列良好的实现复杂,要求找到散列良好的 HashHash 算算法,素材规模与查找速度没太大关联,处法,素材规模与查找速度没太大关联,处理理 HashHash 冲突。冲突。

Page 89: Solaris 10 C 编程

Solaris—Solaris— 常用查找算法常用查找算法unsigned long hashstring(char * ssstr,unsigned long hashsize)unsigned long hashstring(char * ssstr,unsigned long hashsize){{ unsigned long ha=0;unsigned long ha=0;char * str=ssstr;char * str=ssstr;while(*str) while(*str) {{ char aa=(*str);char aa=(*str);aa=tolower(aa);aa=tolower(aa);ha=(ha*128+aa)%hashsize;ha=(ha*128+aa)%hashsize;str++;str++;}}return ha;return ha;}}

Page 90: Solaris 10 C 编程

Solaris—Solaris— 常用查找算法常用查找算法 HashHash 查找流程与查找流程与 HashHash 冲突冲突