Linux下面,创建进程是一件十分有意思的事情。我们都知道,进程是操作系统下面享有资源的基本单位。那么,在linux下面应该怎么创建进程呢?其实非常简单,一个fork函数就可以搞定了。但是,我们需要清楚的是子进程与父进程之间除了代码是共享的之外,堆栈数据和全局数据均是独立的,主要是学习标准的H文件的包含。

 linux下的C语言开发(创建进程)

  1. #include <unistd.h>
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <math.h>
  5. #include <errno.h>
  6. #include <sys/types.h>
  7. #include <sys/wait.h>
  8. int main()
  9. {
  10. pid_t pid;
  11. if(-1 == (pid = fork()))
  12. {
  13. printf("Error happened in fork function!\n");
  14. return 0;
  15. }
  16. if(0 == pid)
  17. {
  18. printf("This is child process: %d\n", getpid());
  19. }
  20. else
  21. {
  22. printf("This is parent process: %d\n", getpid());
  23. }
  24. return 0;
  25. }

==================================================================================

linux下的C语言开发(多线程编程)

多线程和多进程还是有很多区别的。其中之一就是,多进程是Linux内核本身所支持的,而多线程则需要相应的动态库进行支持。对于进程而言,数据之间都是相互隔离的,而多线程则不同,不同的线程除了堆栈空间之外所有的数据都是共享的。说了这么多,我们还是自己编写一个多线程程序看看结果究竟是怎么样的。

  1. #include <stdio.h>
  2. #include <pthread.h>
  3. #include <unistd.h>
  4. #include <stdlib.h>
  5. void func_1(void* args)
  6. {
  7. while(1){
  8. sleep(1);
  9. printf("this is func_1!\n");
  10. }
  11. }
  12. void func_2(void* args)
  13. {
  14. while(1){
  15. sleep(2);
  16. printf("this is func_2!\n");
  17. }
  18. }
  19. int main()
  20. {
  21. pthread_t pid1, pid2;
  22. if(pthread_create(&pid1, NULL, func_1, NULL))
  23. {
  24. return -1;
  25. }
  26. if(pthread_create(&pid2, NULL, func_2, NULL))
  27. {
  28. return -1;
  29. }
  30. while(1){
  31. sleep(3);
  32. }
  33. return 0;
  34. }

和我们以前编写的程序有所不同,多线程代码需要这样编译,输入gcc thread.c -o thread -lpthread,编译之后你就可以看到thread可执行文件,输入./thread即可。

  1. [test@localhost Desktop]$ ./thread
  2. this is func_1!
  3. this is func_2!
  4. this is func_1!
  5. this is func_1!
  6. this is func_2!
  7. this is func_1!
  8. this is func_1!
  9. this is func_2!
  10. this is func_1!
  11. this is func_1!

=================================================================

linux下的C语言开发(管道通信)

Linux系统本身为进程间通信提供了很多的方式,比如说管道、共享内存、socket通信等。管道的使用十分简单,在创建了匿名管道之后,我们只需要从一个管道发送数据,再从另外一个管道接受数据即可。

  1. #include <stdio.h>
  2. #include <unistd.h>
  3. #include <stdlib.h>
  4. #include <string.h>
  5. int pipe_default[2];
  6. int main()
  7. {
  8. pid_t pid;
  9. char buffer[32];
  10. memset(buffer, 0, 32);
  11. if(pipe(pipe_default) < 0)
  12. {
  13. printf("Failed to create pipe!\n");
  14. return 0;
  15. }
  16. if(0 == (pid = fork()))
  17. {
  18. close(pipe_default[1]);
  19. sleep(5);
  20. if(read(pipe_default[0], buffer, 32) > 0)
  21. {
  22. printf("Receive data from server, %s!\n", buffer);
  23. }
  24. close(pipe_default[0]);
  25. }
  26. else
  27. {
  28. close(pipe_default[0]);
  29. if(-1 != write(pipe_default[1], "hello", strlen("hello")))
  30. {
  31. printf("Send data to client, hello!\n");
  32. }
  33. close(pipe_default[1]);
  34. waitpid(pid, NULL, 0);
  35. }
  36. return 1;
  37. }

下面我们就可以开始编译运行了,老规矩分成两步骤进行:(1)输入gcc pipe.c -o pipe;(2)然后输入./pipe,过一会儿你就可以看到下面的打印了。

  1. [test@localhost pipe]$ ./pipe
  2. Send data to client, hello!
  3. Receive data from server, hello!

=====================================================================

 linux下的C语言开发(信号处理)
 

信号处理是Linux程序的一个特色。用信号处理来模拟操作系统的中断功能,对于我们这些系统程序员来说是最好的一个选择了。要想使用信号处理功能,你要做的就是填写一个信号处理函数即可。一旦进程有待处理的信号处理,那么进程就会立即进行处理。

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <signal.h>
  4. int value = 0;
  5. void func(int sig)
  6. {
  7. printf("I get a signal!\n");
  8. value = 1;
  9. }
  10. int main()
  11. {
  12. signal(SIGINT, func);
  13. while(0 == value)
  14. sleep(1);
  15. return 0;
  16. }

为了显示linux对signal的处理流程,我们需要进行两个步骤。第一,输入gcc sig.c -o sig, 然后输入./sig即可;第二则重启一个console窗口,输入ps -aux | grep sig, 在获取sig的pid之后然后输入kill -INT 2082, 我们即可得到如下的输出。

  1. [root@localhost fork]#./sig
  2. I get a signal!
  3. [root@localhost fork]#

===========================================================

 linux下的C语言开发(进程等待)

所谓进程等待,其实很简单。前面我们说过可以用fork创建子进程,那么这里我们就可以使用wait函数让父进程等待子进程运行结束后才开始运行。注意,为了证明父进程确实是等待子进程运行结束后才继续运行的,我们使用了sleep函数。但是,在Linux下面,sleep函数的参数是秒,而windows下面sleep的函数参数是毫秒。

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <unistd.h>
  4. int main(int argc, char* argv[])
  5. {
  6. pid_t pid;
  7. pid = fork();
  8. if(0 == pid)
  9. {
  10. printf("This is child process, %d\n", getpid());
  11. sleep(5);
  12. }
  13. else
  14. {
  15. wait(NULL);
  16. printf("This is parent process, %d\n", getpid());
  17. }
  18. return 1;
  19. }

下面,我们需要做的就是两步,首先输入gcc fork.c -o fork, 然后输入./fork,就会在console下面获得这样的结果。

  1. [root@localhost fork]# ./fork
  2. This is child process, 2135
  3. This is parent process, 2134
 
 ===================================================
linux下的C语言开发(线程等待)

和多进程一样,多线程也有自己的等待函数。这个等待函数就是pthread_join函数。那么这个函数有什么用呢?我们其实可以用它来等待线程运行结束。

  1. #include <stdio.h>
  2. #include <pthread.h>
  3. #include <unistd.h>
  4. #include <stdlib.h>
  5. void func(void* args)
  6. {
  7. sleep(2);
  8. printf("this is func!\n");
  9. }
  10. int main()
  11. {
  12. pthread_t pid;
  13. if(pthread_create(&pid, NULL, func, NULL))
  14. {
  15. return -1;
  16. }
  17. pthread_join(pid, NULL);
  18. printf("this is end of main!\n");
  19. return 0;
  20. }

编写wait.c文件结束之后,我们就可以开始编译了。首先你需要输入gcc wait.c -o wait -lpthread,编译之后你就可以看到wait可执行文件,输入./wait即可。

  1. [test@localhost thread]$ ./thread
  2. this is func!
  3. this is end of main!
 
 =====================================================
linux下的C语言开发(线程互斥)

对于编写多线程的朋友来说,线程互斥是少不了的。在Linux下面,编写多线程常用的工具其实是pthread_mutex_t。本质上来说,它和Windows下面的mutex其实是一样的,差别几乎是没有。希望对线程互斥进行详细了解的朋友可以看这里

  1. #include <stdio.h>
  2. #include <pthread.h>
  3. #include <unistd.h>
  4. #include <stdlib.h>
  5. static int value = 0;
  6. pthread_mutex_t mutex;
  7. void func(void* args)
  8. {
  9. while(1)
  10. {
  11. pthread_mutex_lock(&mutex);
  12. sleep(1);
  13. value ++;
  14. printf("value = %d!\n", value);
  15. pthread_mutex_unlock(&mutex);
  16. }
  17. }
  18. int main()
  19. {
  20. pthread_t pid1, pid2;
  21. pthread_mutex_init(&mutex, NULL);
  22. if(pthread_create(&pid1, NULL, func, NULL))
  23. {
  24. return -1;
  25. }
  26. if(pthread_create(&pid2, NULL, func, NULL))
  27. {
  28. return -1;
  29. }
  30. while(1)
  31. sleep(0);
  32. return 0;
  33. }

编写mutex.c文件结束之后,我们就可以开始编译了。首先你需要输入gcc mutex.c -o mutex -lpthread,编译之后你就可以看到mutex可执行文件,输入./mutex即可。

  1. [test@localhost thread]$ ./mutex
  2. value = 1!
  3. value = 2!
  4. value = 3!
  5. value = 4!
  6. value = 5!
  7. value = 6!

=======================================================

linux下的C语言开发(网络编程)

不管在Windows平台下面还是在Linux平台下面,网络编程都是少不了的。在互联网发达的今天,我们的生活基本上已经离不开网络了。我们可以用网络干很多的事情,比如说IM聊天、FTP下载、电子银行、网络购物、在线游戏、电子邮件的收发等等。所以说,对于一个软件的开发者来说,如果说他不会进行网络程序的开发,那真是难以想象的。

在开始介绍网络编程的方法之前,我们可以回忆一下计算机网络的相关知识。目前为止,我们使用的最多网络协议还是tcp/ip网络。通常来说,我们习惯上称为tcp/ip协议栈。至于协议栈分成几层,有两种说法。一种是五层,一种是七层,我个人本身也比较倾向于五层的划分方法。大家可以通过下面的图看看协议栈是怎么划分的。

5、应用层
    4、传输层
    3、网络层
    2、数据链路层
    1、物理层

网络的不同层次实现网络的不同功能。物理层主要实现报文的成帧处理;数据链路层完成对报文的优先级的管理,同时实现二层转发和流量控制;网络层实现路由和转发的功能,一方面它需要实现对报文的fragment处理,另外一方面它还需要对路由信息进行处理和保存;传输层实现报文的发送和接受,它利用计数、时序、定时器、重发等机制实现对报文的准确发送,当然这都是tcp的发送机制,而udp一般是不保证报文正确发送和接收的;应用层就是根据传输层的端口信息调用不同的程序来处理传输的内容,端口8080是http报文,端口21是ftp报文等等。上面的逻辑稍显复杂,朋友们可以这么理解,

物理层关心的是如何把电气信号变成一段报文;数据链路层关心的是mac地址、vlan、优先级等;网络层关心的是ip地址,下一跳ip;传输层关心的是端口资源;应用层关心的是报文组装、解析、渲染、存储、执行等等。

目前关于tcp/ip完整协议栈的代码很多,其中我认为写得比较好的还是linux内核/net/ipv4下面的代码。如果朋友们对ipv6的代码感兴趣,也可以看看/net/ipv6的代码。档案如果朋友们对整个协议栈的代码结构理解得不是很清楚,可以参考《linux网络分析与开发》这本书。

当然,作为应用层,我们的其实考虑的不用这么复杂。对于网络程序编写人员来讲,所有网络的资源只要和一个socket关联在一起就可以了。当然在socket可用之前,我们需要为它配置端口信息和ip地址。配置完了之后,我们就可以慢慢等待报文的收发了。所以一般来说,作为服务器端口的处理流程是这样的,

a) 创建socket
    b) 绑定socket到特定的ip地址
    c) 对socket进行侦听处理
    d) 接受socket,表明有客户端和服务器连接
    e) 和客户端循环收发报文
    f) 关闭socket

作为服务器程序而言,它要对特定的端口进行绑定和侦听处理,这样稍显复杂。但是如果是编写客户端的程序,一切的一切就变得非常简单了,

   a) 创建socket
    b) 链接服务器端地址
    c) 和服务器端的socket收发报文

上面只是对网络编程做了一个基本的介绍,但是好多的东西还是没有涉及到,比如说:(1) 什么时候该使用udp,什么时候该使用tcp?(2) 如何把多线程和网络编程联系在一起? (3) 如何把多进程和网络编程联系在一起? (4) 如何利用select函数、epoll_create机制、非阻塞函数提高socket的并发处理效率? (5) linux内核是怎么实现tcp/ip协议的? (6) 我们自己是否也可以实现协议的处理流程等等?

 
 
 

最新文章

  1. (转载)Spring的refresh()方法相关异常
  2. Mallet 使用说明
  3. &lt;UL&gt;中&lt;li&gt;标签前编号图片的简单调用
  4. WAMP启动失败简单解决方法
  5. 10. Max Points on a Line
  6. Atitit. 提升软件开发效率and 开发质量---java 实现dsl 4gl 的本质and 精髓 O725
  7. Dynamic Web Module 3.0 requires Java 1.6 or newer
  8. 关于#include后面&lt;&gt;和&quot; &quot;的区别
  9. poj 2388 Who&amp;#39;s in the Middle
  10. .NET:国际化和本地化
  11. 解决window7 x64位Anaconda启动报错:AttributeError: &#39;_NamespacePath&#39; object has no attribute &#39;sort&#39;
  12. 关于微信小程序使用canvas生成图片,内容图片跨域的问题
  13. Oracle考试题作业
  14. 「THUWC 2017」在美妙的数学王国中畅游
  15. c++内存泄漏原因及解决办法(智能指针)
  16. github简单命令
  17. sql语句中的不等于 &lt;&gt;
  18. django源码解析之 BooleanField (三)
  19. #网页中动态嵌入PDF文件/在线预览PDF内容#
  20. 【转载】COM 组件设计与应用(十三)——事件和通知(VC6.0)

热门文章

  1. hihoCoder#1077 RMQ问题再临-线段树
  2. [luoguP2401] 不等数列
  3. 【区间dp+组合数+数学期望】Expression
  4. Operating system management of address-translation-related data structures and hardware lookasides
  5. 1085 数字游戏 2003年NOIP全国联赛普及组
  6. POJ 1064_Cable master
  7. Servlet表单数据处理
  8. 我的arcgis培训照片11
  9. 制作svg动画
  10. Jquery的运用