Linux programming

MISC

 

Linux的图形编程环境库

       GTK: GNOME环境基础
       Qt:KDE环境的基础

 

 

window编译Unix代码的方法


1.修改编译器,让window下的编译器把诸如fork的调用翻译成等价的形式--这就是mingw的做法.
2.修改库,让window提供一个类似unix提供的库,他们对程序的接口如同unix一样,而这些库,当然是由win32的API实现的--这就是cygwin的做法.

 

 

Process Layout

 

Linux的内存模型,一般为:

地址

作用

说明

>=0xc000 0000

内核虚拟存储器

用户代码不可见区域

<0xc000 0000

Stack(用户栈)

ESP指向栈顶

 

 

 

空闲内存

>=0x4000 0000

文件映射区

 

<0x4000 0000

 

 

 

空闲内存

 

 

Heap(运行时堆)

通过brk/sbrk系统调用扩大堆,向上增长。

 

.data.bss(读写段)

从可执行文件中加载

>=0x0804 8000

.init.text.rodata(只读段)

从可执行文件中加载

<0x0804 8000

保留区域

 

 

很多书上都有类似的描述,本图取自于《深入理解计算机系统》p603

 

 

每个进程的所占内存信息在/proc/XX/maps中记录。包括堆,栈,代码段。。。

当动态分配的大内存时,不是在heap区,而是在文件映射区

 

Network

 

 

Socket通信的步骤
Server端:
1)        调用socket来创建server_socket,
2)        调用bind来命名server_socket,
3)        调用listen来创建队列用来存放来自client的连接
4)        调用accept来接受client的连接,并获得client_socket
5)        当与client建立连接后,可以对client_socket进行write和read
6)        调用close来关闭server_socket和client_socket
Client端:
1)        调用socket来创建client_socket
2)        调用connect使client_socket与server的server_socket建立连接
3)        当与server建立连接后,可以对client_socket进行write和read

1)        Server socket是命名套接字,用于建立连接
2)        Client socket是未命名套接字,用于双向读写数据,即发送和接收数据

 

阻塞/非阻塞发送接收
关于socket属性和send/recv的MSG_WAITALL参数设置的实验结果:
前提:getsockopt(sockfd,SOL_SOCKET, SO_SNDBUF, &val, &len) -> val is 50700
(1)    Sock fd默认 + send (MSG_WAITALL)202800(50700 * 4) -> 第一次send返回值为202800
(2)    Sock fd默认 + send (MSG_DONTWAIT)202800(50700 * 4) –> 第一次send返回值为65536,对方没有取出接收缓冲区中的数据时,第二次send返回值为147456
(3)    Sock fd设置|=O_NONBLOCK + send(不论设置阻塞还是非阻塞)或是用write,现象同(2)
结论:
1. 如果fd没有设置为非阻塞,send的wait参数决定是否阻塞发送;否则一律非阻塞发送
2.  Block send,不论是否用select,send返回值总是要发送的字节数
3.  NonBlock send,不论是否用select, send返回值可能不等于要发送的字节数;但是发送字节数小于65536时,如果用select判断可读时写入sock,返回值总是要发送的字节数目。
4. block read在可读时就返回,返回值不一定等于参数设置的字节数


Socket的断开处理
正常断开从来都应该是客户端主动提出的,服务端响应客户端退出请求,close发送FIN到客户端,客户端recv返回0,于是close完成整个断开.

非正常断开只能做心跳,服务端select接受所有客户端的UDP心跳包并立即返回心跳响应包并给相应客户端心跳计数清0,对于不可读的套接字,累加心跳计数+1,在计数超过K次时,则断开并关闭该客户的TCP套接字和UDP.

客户端则是给服务器发送一个心跳包,然后select该 UDP心跳套接字N秒,如超时,则心跳计数+1,如果连续超时K次,则断开并关闭该TCP套接字和UDP套接字.

如果对方调用close正常断开(在没有自定退出包的情况下)
recv会收到 0,这时就可以判断对方断开
如果再次recv产生一个-1错误

IO的处理方式——阻塞和非阻塞,Select,poll,epoll
非阻塞模式,如果暂时没有数据,返回的值也会是<=0的,
阻塞模式,返回<=0的值是可以认为socket已经无效了。

当使用 select()函数测试一个socket是否可读时,如果select()函数返回值为1,
且使用recv()函数读取的数据长度为0时,就说明该socket已经断开。

在linux新的内核中,有了一种替换它的机制,就是epoll。
相比于select,epoll最大的好处在于它不会随着监听fd数目的增长而降低效率。因为在内核中的select实现中,它是采用轮询来处理的,轮询的fd数目越多,自然耗时越多。

 

Linux线程

线程标准
Native POSIX Thread Library (NPTL)标准,大部分线程库都是基于此标准而实现的。
Linux的线程实现
Linux线程是通过进程来实现。Linux kernel为进程创建提供一个clone()系统调用,clone的参数包括如CLONE_VM, CLONE_FILES, CLONE_SIGHAND 等。通过clone()的参数,新创建的进程,也称为LWP(Lightweight process)与父进程共享内存空间,文件句柄,信号处理等,从而达到创建线程相同的目的。
Linux 2.6的线程库叫NPTL(NativePOSIX Thread Library)。POSIX thread(pthread)是一个编程规范,通过此规范开发的多线程程序具有良好的跨平台特性。尽管是基于进程的实现,但新版的NPTL创建线程的效率非常高。
NPTL的实现是在kernel增加了futex(fastuserspace mutex)支持用于处理线程之间的sleep与wake。futex是一种高效的对共享资源互斥访问的算法。kernel在里面起仲裁作用,但通常都由进程自行完成。
NPTL是一个1×1的线程模型,即一个线程对于一个操作系统的调度进程,优点是非常简单。而其他一些操作系统比如Solaris则是MxN的,M对应创建的线程数,N对应操作系统可以运行的实体。(N<M),优点是线程切换快,但实现稍复杂。
在技术实现上,NPTL仍然采用1:1的线程模型,并配合glibc和最新的Linux Kernel2.5.x开发版在信号处理、线程同步、存储管理等多方面进行了优化。和LinuxThreads不同,NPTL没有使用管理线程,核心线程的管理直接放在核内进行,这也带了性能的优化。

线程实现
在核外实现的线程又可以分为"一对一"、"多对一"两种模型,前者用一个核心进程(也许是轻量进程)对应一个线程,将线程调度等同于进程调度,交给核心完成,而后者则完全在核外实现多线程,调度也在用户态完成。后者就是前面提到的单纯的用户级线程模型的实现方式
Linux内核只提供了轻量进程的支持,限制了更高效的线程模型的实现,但Linux着重优化了进程的调度开销,一定程度上也弥补了这一缺陷。目前最流行的线程机制LinuxThreads所采用的就是线程-进程"一对一"模型,调度交给核心,而在用户级实现一个包括信号处理在内的线程管理机制。
POSIC线程相比进程的优势:
代价小,可以使两件事请或者更多事情以一种非常紧密的方式同时发生
因为当执行fork调用时,创建进程副本。新的进程将拥有自己的变量和PID,时间调度也是独立的,完全与父进程无关; 但是进程中创建一个新线程时,新的执行线程将拥有自己的栈(即局部变量),但是与它的创建者共享全局变量,文件描述符,信号处理函数和当前目录状态
installpthread manpage
         man -k pthread OR apropos pthread
         sudo apt-get install manpages-posixmanpages-posix-dev
createdetach pthread
         非分离线程:父线程要用join函数等待子线程结束来回收子线程的资源
         NOTE:线程自己不拥有系统资源,只拥有一点在运行中必不可少的资源,但它可与同属一个进程的其它线程共享进程所拥有的全部资源
         分离线程:子线程退出后资源自动释放掉

线程退出
   1.执行完自动退出
   2.线程本身调用pthread_exit (void * retval);退出
      外部调用pthread_cancel (pthread_t thread);终止一个线程

 

Dynamic library loading

 

Debugging

 

errno

进程中的errno变量是被所有线程共享的,所以会覆盖掉上一次的数值
man 3 errno to view description of error no

打印errno的方法:
1. #include <string.h>
char * strerror(int errnum);
2. #include <stdio.h>

void perror(const char *msg); //print to console

 

查看程序堆栈大小ulimit -a

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值