- 浏览: 427751 次
- 性别:
- 来自: 杭州
文章分类
最新评论
-
lkun__blog:
网页打不开啊
博客搬家到http://cuiz.me -
bglmmz:
楼主怎么解决的?我用python调用ice服务,也出现此问题, ...
syscall exception: 存储空间不足,无法处理此命令 -
luliangy:
哥,你什么配置,我10W个请求10秒左右就搞定了,毫无压力,R ...
Nginx和Apache简单的并发压力测试 -
liuxuejin:
这!看的我都···········。我看代码而已。怎么
EPOLL及消息队列实现SMTP 之 青楼的故事 -
zires:
night_stalker 写道unicorn 也很好维护啊, ...
Unicorn和Passenger性能测试对比
第一次用epoll去实现一个服务器,
之前并不清楚epoll的用法,
了解之后才发现epoll服务器的主线程其实最好和处理业务的代码分开,
也就是说:
epoll响应外界的io请求,当epoll得到一个请求的时候,扔到一个消息队列中,然后epoll直接返回,再去等待io请求.而消息队列会通知多个线程去处理这些业务逻辑.
epoll第一次用,消息队列更是第一次用,开始一直在想,怎么写个阻塞的队列,而且要有主动通知的功能,想了一会儿发现pthread_cond_wait和pthread_cond_signal可以实现,于是就简单的试试,下面的代码已经可以实现我刚才想要得到的那个模型,细节就不管了.
对消息队列熟悉的同学请帮忙提点意见,并告诉我下还有哪些方法可以实现阻塞的消息队列.
对代码的解释和描述都写到注释中了.
:)谢谢提醒
这个代码是完全编译不通过的,仔细看结构体的定义都有问题,我对语法还不是很记得清,要是有同学想编译的话,我还有个可执行的版本可以提供.
之前并不清楚epoll的用法,
了解之后才发现epoll服务器的主线程其实最好和处理业务的代码分开,
也就是说:
epoll响应外界的io请求,当epoll得到一个请求的时候,扔到一个消息队列中,然后epoll直接返回,再去等待io请求.而消息队列会通知多个线程去处理这些业务逻辑.
epoll第一次用,消息队列更是第一次用,开始一直在想,怎么写个阻塞的队列,而且要有主动通知的功能,想了一会儿发现pthread_cond_wait和pthread_cond_signal可以实现,于是就简单的试试,下面的代码已经可以实现我刚才想要得到的那个模型,细节就不管了.
对消息队列熟悉的同学请帮忙提点意见,并告诉我下还有哪些方法可以实现阻塞的消息队列.
对代码的解释和描述都写到注释中了.
/* 几个用到的类型定义以及全局变量bq */ char smtp_cmd_format; struct epoll_event ev, events[MAX_EPOLL_SIZE]; int kdpfd,nfds; struct block_queue { int queue[THREADS_COUNT]; long size; pthread_cond_t cond; pthread_mutex_t mutex; }block_queue_t; block_queue_t bq; struct block_queue_param { void* func; void* queue; }block_queue_param_t;
void *block_queue(void * param) { void(* func)(void* ); int fd,i; /* 由于block_queue是pthread_create的回调方法, 所以block_queue的参数必须是void*类型 */ block_queue_t* bque = (block_queue_param_t*)param->queue; /* param->func是block_queue解锁时需要调用的函数, 而这个函数的参数是一个int fd, 该fd是消息队列中刚刚插入的一个元素. */ func = (block_queue_param_t*)param->func; for(;;) { /* lock->wait->unlock 这是经典的模式, 切记: pthread_cond_wait的方法自带了先解锁,再等待,最后再加锁的代码 */ pthread_mutex_lock(bque->mutex); /* 线程在pthread_cond_wait这里被block住了, 当听到pthread_cond_signal通知的时候, 内核会从阻塞队列里面通过先进先出的原则唤醒一个线程, 这个线程会执行pthread_cond_wait之后的代码. */ pthread_cond_wait(bque->cond,bque->mutex); if(bque->size==0) { /* 啥也不做 */ }else { fd = bque->queue[0]; /* 移动队列, 由于该队列是简单的用数组保存fd, 所以移动这个操作必不可少,但肯定性能比链表差很多, 这是懒惰的代价 */ for(i = 0; i < bque->size; ++i) bque->queue[i] = bque->queue[i+1]; bque->queue[bque->size-1] = 0; bque->size--; /* 执行被唤醒后的方法,参数是刚刚插入到队列中的一个fd */ func(fd); } pthread_mutex_unlock(bque->mutex); } } void insert_queue(struct block_queue *bque,int fd) { /* 加锁->通知->解锁 将元素插入队列之前需要先加锁 */ pthread_mutex_lock(bque->mutex); /* 检查队列目前的大小, 检查1: 当大小已经达到定义的数组大小THREADS_COUNT时, 抛弃该fd,说明服务器忙不过来了,消息队列已经满了 检查2: 当大小超过数组定义的大小THREADS_COUNT时, 肯定发生了异常,那就直接退出服务吧. */ if(bque->size == THREADS_COUNT) return; /* bque->size其实也是队列末尾位置指针, 当插入一个元素后,这个指针自然也要向后移动一位. */ bque->queue[bque->size+1] = fd; if(++bque->size > THREADS_COUNT) { fprintf(stderr,"Queue size over folow.%d",bque->size); exit 1; } /* 当元素插入bque队列时, 该通过pthread_cond_signal通知内核去调度wait的线程了 */ pthread_cond_signal(bque->cond); pthread_mutex_unlock(bque->mutex); } /* init_threads代码是初始化线程组的, 随便写写的,大家知道怎么实现就行 */ int init_threads() { size_t i=0; block_queue_param_t bqp; /* smtp_echo是处理epoll扔进队列中的fd的函数, 该方法实现了整个模型的业务逻辑, 整体代码的IO处理+消息队列以及业务处理分的很清晰, 三个模块每个只有一处代码和其它模块通讯,没有多少耦合. */ bqp.func = (void*)smtp_echo; bqp.queue = (void*)bq; pthread_cond_init(bqp.cond,NULL); pthread_mutex_init(bqp.mutex,NULL); for( i = 0; i < THREADS_COUNT; ++i) { pthread_t child_thread; pthread_attr_t child_thread_attr; pthread_attr_init(&child_thread_attr); pthread_attr_setdetachstate(&child_thread_attr,PTHREAD_CREATE_DETACHED); if( pthread_create(&child_thread,&child_thread_attr,block_queue, (void *)bqp) < 0 ) { printf("pthread_create Failed : %s\n",strerror(errno)); return 1; } else { printf("pthread_create Success : %d\n",(int)child_thread); return 0; } } } /* handler是主线程访问的方法, 主线程通过handler把一个fd扔到消息队列之后, 不再做任何事情就直接返回了. 在我的应用中,主线程是个epoll实现的服务器, 由于epoll被响应的时候会知道哪些fd已经就位, 于是直接把就位的fd扔到消息队列中就好了, 主线程在继续等待其它fd的响应,而不需要去关心fd如何被处理. */ int handler(void* fd) { printf("handler:fd => %d\n",*(int *)(fd)); insert_queue(&bq,fd); return 0; } /* main函数是整个程序的入口点, 也是epoll服务器的实现, epoll的思想很精髓,用法很简单, 只要把man 4 epoll_ctl的例子copy出来,就可用了, 不过那个例子语法有点问题, 而且events数组是用指针,应该用[]实现,因为指针没有分配空间. */ int main(int argc, char **argv) { int server_socket = init_smtp(); int n; if(init_threads() == 0) printf("Success full init_threads."); smtp_cmd_format = "^([a-zA-Z0-9]) (.*)$"; kdpfd = epoll_create(MAX_EPOLL_SIZE); ev.events = EPOLLIN | EPOLLET; ev.data.fd = server_socket; if (epoll_ctl(kdpfd, EPOLL_CTL_ADD, server_socket, &ev) < 0) { fprintf(stderr, "epoll set insertion error: fd=%d < 0", server_socket); return -1; } /* epoll的使用看这里 */ for(;;) { struct sockaddr_in local; socklen_t length = sizeof(local); int client; nfds = epoll_wait(kdpfd, events, MAX_EPOLL_SIZE, -1); /* 当没有事件要处理时,epoll会阻塞住, 否则,内核会填充events数组,里面的每一个events[n].data.fd就是发生io时间的文件句柄 */ for(n = 0; n < nfds; ++n) { /* 这里要判断一下请求的来源, if(events[n].data.fd == server_socket) { 这里是新建的连接, 因为io发生在server_socket上 } else{ 这里是已有的连接, 因为fd!= server_socket 那fd肯定是之前从server_socket接收到, 并且通过epoll_ctl(kdpfd, EPOLL_CTL_ADD, client, &ev) 加入到kdpfd所指向的内存空间中. kdpfd其实是个文件句柄,在epoll_create(MAX_EPOLL_SIZE)时得到 } */ if(events[n].data.fd == server_socket) { client = accept(server_socket, (struct sockaddr *) &local,&length); if(client < 0){ perror("accept"); continue; } setnonblocking(client); smtp_cmd("220",client); ev.events = EPOLLIN | EPOLLET; ev.data.fd = client; if (epoll_ctl(kdpfd, EPOLL_CTL_ADD, client, &ev) < 0) { fprintf(stderr, "epoll set insertion error: fd=%d < 0", client); return -1; } } else /* 当已有的fd发生io操作时, 执行如下代码.也就是把fd扔到消息队列中. */ if(handler((void *)&events[n].data.fd) != 0) perror("handler ret != 0"); } } close(server_socket); return 0; }
评论
5 楼
CharlesCui
2011-01-09
看我另一篇:http://charlescui.iteye.com/blog/726914
4 楼
LaoLiulaoliu
2011-01-09
有几处不解,还望楼主指点。
1. bq.size 没有初始化(已修改)
2.block_queue 里面的bque实际指向全局变量bq,这样多个线程都指向这个全局的变量(修改参数传地址的错误)
3.setnonblocking(client)是否是伪代码,可以用下面表示:
fcntl(client, F_SETFL, O_NONBLOCK);
4.init_smtp() , smtp_echo(), smtp_cmd() 3个函数没有实现,这样就不明白楼主要干什么了。
5.如果我有许多的fd需要insert,那么每次insert完成后,都要队列的移动和执行func后才能释放锁,然后再次insert。这样就不能保证很快的响应其他的请求了。
下面我把我修改的代码也贴出来吧:
1. bq.size 没有初始化(已修改)
2.block_queue 里面的bque实际指向全局变量bq,这样多个线程都指向这个全局的变量(修改参数传地址的错误)
3.setnonblocking(client)是否是伪代码,可以用下面表示:
fcntl(client, F_SETFL, O_NONBLOCK);
4.init_smtp() , smtp_echo(), smtp_cmd() 3个函数没有实现,这样就不明白楼主要干什么了。
5.如果我有许多的fd需要insert,那么每次insert完成后,都要队列的移动和执行func后才能释放锁,然后再次insert。这样就不能保证很快的响应其他的请求了。
下面我把我修改的代码也贴出来吧:
#include <pthread.h> #define MAX_EPOLL_SIZE 0x40 #define THREADS_COUNT 0xa /* 几个用到的类型定义以及全局变量bq */ struct block_queue { int queue[THREADS_COUNT]; long size; pthread_cond_t cond; pthread_mutex_t mutex; }block_queue_t; struct block_queue_param { void* func; void* queue; }block_queue_param_t; block_queue_t bq; void *block_queue(void *param) { void(* func)(void* ); int fd, i; /* 由于block_queue是pthread_create的回调方法, 所以block_queue的参数必须是void*类型 bque实际指向全局变量bq */ block_queue_t *bque = (block_queue_param_t *)param->queue; /* param->func是block_queue解锁时需要调用的函数, 而这个函数的参数是一个int fd, 该fd是消息队列中刚刚插入的一个元素. */ func = (block_queue_param_t*)param->func; for(;;) { /* lock->wait->unlock 这是经典的模式, 切记: pthread_cond_wait的方法自带了先解锁,再等待,最后再加锁的代码 只有一个线程会抢到锁 */ pthread_mutex_lock(&bque->mutex); /* 线程在pthread_cond_wait这里被block住了, 当听到pthread_cond_signal通知的时候, 内核会从阻塞队列里面通过先进先出的原则唤醒一个线程, 这个线程会执行pthread_cond_wait之后的代码. */ pthread_cond_wait(&bque->cond, &bque->mutex); if(bque->size==0) { }else { fd = bque->queue[0]; /* 移动队列, 由于该队列是简单的用数组保存fd, 所以移动这个操作必不可少,但肯定性能比链表差很多, 这是懒惰的代价 */ for(i = 0; i < bque->size - 1; ++i) bque->queue[i] = bque->queue[i+1]; bque->queue[bque->size-1] = 0; bque->size--; /* 执行被唤醒后的方法,参数是刚刚插入到队列中的一个fd */ func(fd); } pthread_mutex_unlock(&bque->mutex); } } void insert_queue(struct block_queue *bque,int fd) { /* 加锁->通知->解锁 将元素插入队列之前需要先加锁 */ pthread_mutex_lock(&bque->mutex); /* 检查队列目前的大小, 检查1: 当大小已经达到定义的数组大小THREADS_COUNT时, 抛弃该fd,说明服务器忙不过来了,消息队列已经满了 检查2: 当大小超过数组定义的大小THREADS_COUNT时, 肯定发生了异常,那就直接退出服务吧. */ if(bque->size == THREADS_COUNT) return; /* bque->size其实也是队列末尾位置指针, 当插入一个元素后,这个指针自然也要向后移动一位. */ bque->queue[bque->size] = fd; if(++bque->size > THREADS_COUNT) { fprintf(stderr,"Queue size over folow.%d",bque->size); exit 1; } /* 当元素插入bque队列时, 该通过pthread_cond_signal通知内核去调度wait的线程了 */ pthread_cond_signal(&bque->cond); pthread_mutex_unlock(&bque->mutex); } /* init_threads代码是初始化线程组的 */ int init_threads() { size_t i=0; block_queue_param_t bqp; /* smtp_echo是处理epoll扔进队列中的fd的函数, 该方法实现了整个模型的业务逻辑, 整体代码的IO处理+消息队列以及业务处理分的很清晰, 三个模块每个只有一处代码和其它模块通讯,没有多少耦合. */ bqp.func = (void*)smtp_echo; bqp.queue = (void*)&bq; if ( !pthread_mutex_init(bq.mutex, NULL) ) return 1; if ( !pthread_cond_init(bq.cond, NULL) ) return 1; for(i = 0; i < THREADS_COUNT; ++i) { pthread_t child_thread; pthread_attr_t child_thread_attr; if ( pthread_attr_init(&child_thread_attr) ) continue; pthread_attr_setdetachstate(&child_thread_attr,PTHREAD_CREATE_DETACHED); if(pthread_create(&child_thread,&child_thread_attr,block_queue,(void *)&bqp) != 0) { printf("pthread_create Failed : %s\n",strerror(errno)); continue; } else { printf("pthread_create Success : %d\n",(int)child_thread); } pthread_attr_destroy(&child_thread_attr); } return 0; } /* handler是主线程访问的方法, 主线程通过handler把一个fd扔到消息队列之后, 不再做任何事情就直接返回了. 在我的应用中,主线程是个epoll实现的服务器, 由于epoll被响应的时候会知道哪些fd已经就位, 于是直接把就位的fd扔到消息队列中就好了, 主线程在继续等待其它fd的响应,而不需要去关心fd如何被处理. */ int handler(void* fd) { printf("handler:fd => %d\n",*(int *)(fd)); insert_queue(&bq,fd); return 0; } /* main函数是整个程序的入口点, 也是epoll服务器的实现, epoll的思想很精髓,用法很简单, 只要把man 4 epoll_ctl的例子copy出来,就可用了, 不过那个例子语法有点问题, 而且events数组是用指针,应该用[]实现,因为指针没有分配空间. */ int main(int argc, char **argv) { char smtp_cmd_format; int kdpfd, nfds; struct epoll_event ev, events[MAX_EPOLL_SIZE]; int server_socket = init_smtp(); int n; bq.size = 0; if(init_threads() == 0) printf("Success full init_threads."); smtp_cmd_format = "^([a-zA-Z0-9]) (.*)$"; kdpfd = epoll_create(MAX_EPOLL_SIZE); //kdpfd = epoll_create1(0); if (kdpfd == -1) { perror("epoll_create1"); return -1; } ev.events = EPOLLIN | EPOLLET; ev.data.fd = server_socket; if (epoll_ctl(kdpfd, EPOLL_CTL_ADD, server_socket, &ev) < 0) { fprintf(stderr, "epoll set insertion error: fd=%d < 0", server_socket); return -1; } /* epoll的使用看这里 */ for(;;) { struct sockaddr_in local; socklen_t length = sizeof(local); int client; nfds = epoll_wait(kdpfd, events, MAX_EPOLL_SIZE, -1); /* 当没有事件要处理时,epoll会阻塞住, 否则,内核会填充events数组,里面的每一个events[n].data.fd就是发生io时间的文件句柄 */ for(n = 0; n < nfds; ++n) { /* 这里要判断一下请求的来源, if(events[n].data.fd == server_socket) { 这里是新建的连接, 因为io发生在server_socket上 } else{ 这里是已有的连接, 因为fd!= server_socket 那fd肯定是之前从server_socket接收到, 并且通过epoll_ctl(kdpfd, EPOLL_CTL_ADD, client, &ev) 加入到kdpfd所指向的内存空间中. kdpfd其实是个文件句柄,在epoll_create(MAX_EPOLL_SIZE)时得到 } */ if(events[n].data.fd == server_socket) { client = accept(server_socket, (struct sockaddr *) &local,&length); if(client < 0){ perror("accept"); continue; } setnonblocking(client); smtp_cmd("220",client); ev.events = EPOLLIN | EPOLLET; ev.data.fd = client; if (epoll_ctl(kdpfd, EPOLL_CTL_ADD, client, &ev) < 0) { fprintf(stderr, "epoll set insertion error: fd=%d < 0", client); return -1; } } else /* 当已有的fd发生io操作时, 执行如下代码.也就是把fd扔到消息队列中. */ if(handler((void *)&events[n].data.fd) != 0) perror("handler ret != 0"); } } close(server_socket); return 0; }
3 楼
CharlesCui
2010-07-15
sunzixun 写道
attr 没有destory 内存泄漏
:)谢谢提醒
这个代码是完全编译不通过的,仔细看结构体的定义都有问题,我对语法还不是很记得清,要是有同学想编译的话,我还有个可执行的版本可以提供.
2 楼
sunzixun
2010-07-14
attr 没有destory 内存泄漏
1 楼
sunzixun
2010-07-14
msgrcv (key, you_buffer, mesg_len, mesg_type, (m_iBlock ? MSG_NOERROR : IPC_NOWAIT|MSG_NOERROR));
发表评论
-
使用CURL库在编译时遇到的问题
2010-12-29 18:49 9303表现: windows平台,使用libcur ... -
Apache模块-下载文件-性能测试打靶用的靶子
2010-12-16 18:30 2622apache模块, 下载某一个文件, 性能测试打靶用, ... -
[分享我的经验]Cpp项目测试方案设计及实现
2010-07-15 16:04 969##第一次做Cpp项目的测试设计,代码的语法还 ... -
这里写的都是关于Flex的废话,不吐不快
2009-12-17 16:51 798我靠, 一个对象在MXML和AS里面一般都通用,MXML里面 ... -
Flex代码组织结构的一点经验
2009-12-15 14:23 2274在开始设计部门内部太极项目二期的时候,就一直在反思一期工作中的 ... -
要以可持续发展的眼光去做技术选型,嘿嘿^-^
2009-11-29 13:16 958部门内部有个很不错的 ... -
Your Kit Profiler解析Java性能
2009-07-22 16:24 1934#The below params will open the ... -
我知道了Ext总发出毫无意义的Http请求的原因
2009-05-08 17:21 911以前看别的项目组用Ext做的项目时,会发现经常有错误的请求发出 ... -
用JS处理HttpWatch转到的POST参数没有分隔好时候的方法
2009-01-12 15:46 1763HttpWatch版本太老的时候会出现post的参数被Http ... -
JavaScript画的股票曲线图
2008-12-16 14:42 3292目前做成这样了,用JavaScript的canvas画的,为了 ... -
javascript 中 outerHTML 、innerHTML、innerTEXT 三者的区别
2008-12-11 17:51 833Z:http://blog.52z.com/post/304. ... -
只有IE知道这句注释
2008-12-10 19:57 935<!--[if IE]>只有IE知道这句注释!&l ... -
图解程序设计关键词
2008-12-04 17:30 1191... -
旺旺SDK2.8插件 TC
2008-12-03 14:00 1749SDK2.8 联系人及联系人集合操作 入口类,实现了主程序和 ... -
练练手,好久不写都要生疏了
2008-11-22 01:26 915<!DOCTYPE HTML PUBLIC " ... -
(轻便)调试JavaScript的旺旺插件(基于jzshmyt的javascript-logger)
2008-11-21 10:16 1339Demo如下,大家拍砖吧! 请看下面介绍: ... -
我的Httpunit+Junit文件上传API测试用例
2008-07-29 14:16 2749package com.alisoft.aep.sip.cor ...
相关推荐
《UNIX环境高级编程》是一本深受程序员和系统管理员喜爱的经典之作,它深入探讨了在UNIX操作系统上进行系统级编程的各种技术和方法。这本书分为多个部分,详细涵盖了从基本的进程控制到复杂的网络通信、文件系统操作...
- **Posix事件标志**:`pthread_cond_wait()`和`pthread_cond_signal()`等函数提供线程间的同步和通信。 - **异步I/O(AIO)**:用户空间可以提交I/O请求,然后继续执行其他任务,内核在后台处理完后通过回调函数...
- **创建消息队列**:`msgget()`,创建一个新的消息队列; - **发送消息**:` msgsnd()`,向消息队列发送一条消息; - **接收消息**:`msgrcv()`,从消息队列接收一条消息; - **删除消息队列**:`msgctl()`,用于...
6. **线程编程**:线程的创建(pthread_create)、同步(pthread_mutex、pthread_cond)、线程属性和取消(pthread_join、pthread_cancel)。 7. **错误处理**:理解errno全局变量,学会使用perror和strerror函数来...
- **消息队列**:`msgget()`, `msgsnd()`, `msgrcv()`, `msgctl()`等函数提供一种有序的消息传递机制。 - **信号量(Semaphores)**:用于多进程间的同步,防止数据竞争。 4. **线程编程** - **创建线程**:使用`...
6. **线程编程**:涵盖了POSIX线程(pthread)API,如pthread_create()、pthread_join()、pthread_mutex_t和pthread_cond_t等,以及线程同步和互斥锁的使用。 7. **其他高级话题**:如程序异常处理、程序调试工具...
随书代码“tlpi-dist”包含的文件是这些知识点的实践载体,每个源代码文件对应书中的一节或一个主题。读者可以下载这些代码,在LINUX环境下编译和运行,以加深对理论的理解,提升编程技能。通过实践这些代码,不仅...
在这个压缩包中,代码被分章节组织,每个章节对应一个或多个文件,这样的结构便于读者按照书中的进度逐步学习和实践。以下是可能涉及的一些关键知识点: 1. **进程管理**:包括进程创建(fork()、vfork())、进程...
- **线程同步**: 使用互斥锁(`pthread_mutex_t`)、条件变量(`pthread_cond_t`)等实现同步。 - **线程取消**: 取消线程(`pthread_cancel()`等)。 #### 八、网络编程 - **套接字编程**: 基础网络通信(`socket()`/`...
7. **并发编程**:线程的创建与管理(`pthread_create()`, `pthread_join()`),线程同步(`pthread_mutex_t`, `pthread_cond_t`)和线程局部存储。 8. **程序链接与装载**:解析ELF文件格式,动态链接器的工作原理...
通过源代码,你可以学习到socket()、bind()、listen()、accept()、connect()、send()、recv()等函数的使用,以及多路复用I/O(select()、poll()、epoll())的实现。 4. **信号处理**:源代码展示了如何使用signal()...
3. **线程管理**:Linux支持多线程编程,线程是轻量级的进程,它们共享同一地址空间,线程创建(pthread_create)、线程同步(pthread_mutex、pthread_cond)和线程退出(pthread_exit)是主要操作。 4. **文件I/O*...
10. **多线程编程**:包括`pthread_create()`, `pthread_join()`, `pthread_exit()`, `pthread_mutex_*()`, `pthread_cond_*()`等函数的使用,以及线程同步和竞态条件的处理。 通过分析和实践这些代码,读者不仅...
9. **进程间通信(IPC)**:Linux提供了多种进程间通信方式,如管道(无名管道和命名管道)、消息队列、共享内存、信号量等,这些都用于不同进程之间的数据交换和协调。 10. **系统调用接口(System Call Interface...
在Linux操作系统中,高级程序设计是一项关键技能,它涉及到对系统接口、内存管理、进程通信、文件I/O...对于希望在Linux环境中进行系统级编程或者开发服务器端软件的程序员来说,这本书的源代码是一个无价的学习工具。
在“uxix”平台下进行C语言高级编程涵盖了多个关键领域,这些领域构成了现代软件开发的基础。本教程将深入探讨这些主题,旨在帮助开发者提升在UNIX环境中的编程技能。以下是根据标题、描述和标签总结的知识点: 1. ...
Unix文件系统是层次结构的,每个文件都有一个唯一的路径名。对文件的操作包括创建、打开、关闭、读取、写入、重命名和删除。学习如何正确使用文件描述符、文件权限、硬链接和软链接对于编写健壮的程序至关重要。 四...