hi,你好!欢迎访问本站!登录
本站由网站地图腾讯云宝塔系统阿里云强势驱动
当前位置:首页 - 教程 - 杂谈 - 正文 君子好学,自强不息!

linux C历程经常使用操纵

2019-11-18杂谈搜奇网41°c
A+ A-

不登高山,不知天之高也; 

不临深溪,不知地之厚也。

荀子《劝学》

 linux应用层主假如一个个自力使命的历程在运转,然则许多时刻,在事变中我们能够很少去从新写一个历程,

大部份的事变都是分派到了一个历程内的模块或许供应历程内特定功用的接口拓荒,这篇文章是想简朴申明下,

作为一个历程,在现实拓荒过程当中,能够用到的一些编程要领比方:main参数剖析,信号注册、回调函数、

线程建立、文件操纵(FIFE *fp)、历程间通讯(socket);每一种我都会附一个简朴的实例。

1、main参数剖析,参数较少,运用简朴推断argc并掏出对应的argv[i]值就就能够处置惩罚,代码以下:

1 #include <stdio.h>
2 int main(int argc, char *argv[])
3 {
4   int i = 0;
5   printf("argc is %d\n", argc);
6   for(i = 0; i < argc; i++)
7     printf("argv[%d] is %s\n", i, argv[i]);
8   return 0;
9 }

参数较多时就能够挪用getopt/getopt_long接口来完成事变。

函数的定义

int getopt(int argc, char * const argv[], const char *optstring);

参数申明:

argc:main()函数通报过来的参数的个数

argv:main()函数通报过来的参数的字符串指针数组

optstring:选项字符串,示知 getopt()能够处置惩罚哪一个选项以及哪一个选项需要参数

代码样列

 1 #include<stdio.h>
 2 #include<unistd.h>
 3 #include<getopt.h>
 4 int main(int argc, char *argv[])
 5 {
 6     int opt;
 7     /*单个字符示意选项没有参数                  输入花样:-A即可,不加参数
 8      *单字符加冒号示意选项有且必需加参数        输入花样:-B xiaocang或-Bxiaobo(二选一)
 9      *单字符加两个冒号示意选项能够有也能够无    输入花样:-Cxiaobo(必需挨着)
10      */
11     char *string = "AB:C::";
12     while ((opt = getopt(argc, argv, string))!= -1)
13     {  
14         /* 下面是经常使用的两个猎取选项及其值得变量optarg无需定义,全局变量
15          * opt          '-' 背面的字符,也就是参数字符
16          * optarg       指向当前选项参数(假如有)的指针。
17          */
18         printf("opt = %c\t\t", opt);
19         printf("optarg = %s\t\t\n", optarg);
20     }
21     return 0;
22 }

样列输出:

./argc-opt -A -B xiaocang -Cxiaobo
opt = A    optarg = (null)    
opt = B    optarg = xiaocang    
opt = C    optarg = xiaobo

2、信号注册,作为一个历程,很有必要注册肯定的信号,防备历程非常退出时,本身蒙圈。

函数定义:

1 #include <signal.h>
2 typedef void (*sighandler_t)(int);
3 sighandler_t signal(int signum, sighandler_t handler);

参数申明:

signum:要捕获的信号(检察信号:kill -l,9号SIGKILL信号不能被捕获); 

handler:我们要对信号举行的处置惩罚方式。

示例代码:

 1 #include <stdio.h>
 2 #include <signal.h>
 3 void signal_handler(int signal)
 4 {
 5     printf("Received signal %d\n", signal);
 6     printf("do something...\n");
 7     return;
 8 }
 9 int main(int argc, char *argv[])
10 {
11     signal(SIGHUP, signal_handler);
12     while(1)
13         sleep(2000);
14     return 0;
15 }

示例测试:

一个窗口背景挂历程运转 ./a.out &

开别的的窗口发送信号 kill -1 pid(a.out历程号)

第一个窗口收到将会收到 

Received signal 1 

do something...

3、回调函数

        实在在信号注册中我们就运用了回调函数,然则此回调函数不是我们本身定义的范例,本身用来挪用实行,

我们这里做一个回调函数的挪用示例,差异就在于回调函数的定义与挪用机遇,依据本身的现实需要定义就能够。

 1 #include <stdio.h>
 2 
 3 /* 定义一个函数指针 肯定入介入返回值范例 */
 4 typedef int (* MyCallbak)(int PanJinLian, int XiMengQin);
 5 /* 完成一个与上面定义的函数指针入介入返回值范例雷同的函数 */
 6 int ThisMyFunc(int PanJinLian, int XiMengQin)
 7 {
 8     printf("PanJinLian is %d\n", PanJinLian);
 9     printf("XiMengQin is %d\n", XiMengQin);
10     printf("do something...\n");
11     return 0;
12 }
13 int main(int argc, char *argv[])
14 {
15     int P_adrenaline = 99;
16     int X_adrenaline = 101;
17     MyCallbak CallbakPointer;/* 定义一个函数指针变量 */
18     CallbakPointer = ThisMyFunc;/* 将函数地点给予定义的指针 也叫挂钩子*/
19     int ret = CallbakPointer(P_adrenaline, X_adrenaline);/* 挪用函数,实行回调 */
20     printf("ret is %d\n", ret);
21     return 0;
22 }

实行返回

1 PanJinLian is 99
2 XiMengQin is 101
3 do something...
4 ret is 0

4、线程建立

       线程主假如用来壅塞接收异步音讯,或许完成耗时与周期性的使命,重点需要关注的是线程完毕时线程资本的接纳题目,

许多人会疏忽这部份,会用到 pthread_detach 或许 pthread_join(壅塞守候线程完毕并接纳资本); 多线程势必引入同步与

互斥题目,则关于全局变量,必需要加锁庇护,数据流防备丧失我们会用到行列。

1 #include <pthread.h>
2 int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
3                     void *(*start_routine) (void *), void *arg)
4 //Compile and link with -pthread.

参数申明

thread:指向线程标识符的指针。

attr:用来设置线程属性。

start_routine:线程运转函数的肇端地点。

arg:运转函数的参数。

样例代码:

 1 #include<stdio.h>
 2 #include <pthread.h>
 3 static void mythreadfun( void *arg )
 4 {
 5     /*这将该子线程的状况设置为detached,则该线程运转完毕后会自动开释一切资本*/
 6     pthread_detach(pthread_self());
 7     printf("arg is %s\n", (char *)arg);
 8     int i = 0;
 9     while(1)
10     {
11         printf("do something...\n");
12         if(i++ == 10)
13             break;
14         sleep(2);
15     }
16     return ;
17 }
18 
19 int main(int argc, char *argv[])
20 {
21     pthread_t pthreadid = 0;
22     int ret = 0;
23     char *param = "good";
24     /* 建立线程 */
25     ret = pthread_create(&pthreadid, NULL, (void *)mythreadfun, (void *)param);
26     if(ret != 0)
27     {
28         printf("create pthread failed.");
29         return;
30     }
31     printf("create pthread success.");
32     while(1)
33         sleep(2000);
34     return 0;
35 }

实行返回

1 ./a.out
2 create pthread success.arg is good
3 do something...
4 do something...
5 do something...
6 do something...

5、文件操纵,文件操纵很广泛,如纪录数据,读入数据等。

文件操纵平常要注意,明白操纵的fp在文件中的位置,fclose前革新缓存,对写入或许读出的返回做推断,非常或许完毕

操纵时封闭fp,一样另有open read write接口。二者区分:

1、缓冲文件体系与非缓冲体系的区分

缓冲文件体系(fopen):在内存为每一个文件拓荒一个缓存区,当实行读操纵,从磁盘文件将数据读入内存缓冲区,装满后从

内存缓冲区顺次读取数据。写操纵同理。

内存缓冲区的大小影响着现实操纵外存的次数,缓冲区越大,操纵外存的次数越少,实行速度快,效率高。缓冲区大小由机

器而定。借助文件构造体指针对文件治理,可读写字符串、花样化数据、二进制数据。

非缓冲文件体系(open):依靠操纵体系功用对文件读写,不设文件构造体指针,只能读写二进制文件。

2、open属于初级IO,fopen属于高等IO

3、open返回文件描述符,属于用户态,读写需举行用户态与内核态切换。  fopen返回文件指针

4、open是体系函数,不可移植  fopen是范例C函数,可移植

5、平常用fopen翻开一般文件,open翻开装备文件

6、假如递次接见文件,fopen比open快、 假如随机接见文件,open比fopen快

 1 #include <stdio.h>
 2 #include <string.h>
 3 int main()
 4 {
 5    FILE *fp;
 6    char *msg = "hello world";
 7    char buffer[20];
 8    fp = fopen("test.txt", "w+");/* 翻开文件用于读写 */
 9    fwrite(msg, strlen(msg) + 1, 1, fp);/* 写入数据到文件 */
10    fseek(fp, 0, SEEK_SET);/* 移动到文件的开首 */
11    fread(buffer, strlen(msg) + 1, 1, fp); /* 读取并显现数据 */
12    printf("%s\n", buffer);
13    fsync(fileno(fp));/* 革新缓存 */
14    fclose(fp);
15    return(0);
16 }

实行效果

1 hello world
2 cat test.txt    
3 hello world

6、历程间通讯:包含管道(pipe)、著名管道(named pipe)、信号量(semophore)、音讯行列(message queue)、

信号(signal)、同享内存(shared memory)、套接字(socket),这里只说下socket,tcp服务端与客户端的简朴编

码流程完成。

server端

 1 #include <stdio.h>
 2 #include <sys/socket.h>
 3 #include <sys/un.h>
 4 #define SERVER_SOCKET_FILE  "/tmp/server_socket"
 5 int main()
 6 {
 7     int ret = 0;
 8     int listen_fd = -1;
 9     int size = 0;
10     int conn_fd = -1;
11     int max_fd = 0;
12     fd_set reads;
13     struct sockaddr_un clt_addr;
14     socklen_t len = sizeof(clt_addr);
15     struct sockaddr_un srv_addr;
16     unsigned char buf[4096];
17 
18     listen_fd = socket(PF_UNIX, SOCK_STREAM, 0);
19     if(listen_fd < 0)
20     {
21         printf("can not create listen socket\n");
22         return -1;
23     }
24 
25     srv_addr.sun_family = AF_UNIX;
26     strncpy(srv_addr.sun_path, SERVER_SOCKET_FILE, sizeof(srv_addr.sun_path));
27     unlink(SERVER_SOCKET_FILE);
28     ret = bind(listen_fd,(struct sockaddr*)&srv_addr, sizeof(srv_addr));
29     if(ret < 0)
30     {
31         printf("can not bind server socket");
32         close(listen_fd);
33         return -1;
34     }
35 
36     ret = listen(listen_fd, 5);
37     if(ret < 0)
38     {
39         printf("can not listen the client");
40         close(listen_fd);
41         return -1;
42     }
43     while(1)
44     {
45         FD_ZERO(&reads);
46         FD_SET(listen_fd, &reads);
47         max_fd = listen_fd;
48         if(conn_fd > 0)
49         {
50             FD_SET(conn_fd, &reads);
51             if(conn_fd > max_fd)
52             {
53                 max_fd = conn_fd;
54             }
55         }
56         ret = select(max_fd+1, &reads, 0, 0, NULL);
57         if(ret <= 0)
58         {
59             perror("select fail\n");
60             return -1;
61         }
62         else
63         {
64             memset(buf, 0, sizeof(buf));
65             if(FD_ISSET(listen_fd, &reads))
66             {
67                 conn_fd = accept(listen_fd, (struct sockaddr*)&clt_addr, &len);
68             }
69             if(FD_ISSET(conn_fd, &reads))
70             {
71                 printf("recv client msg,conn_fd:%d\n",conn_fd);
72                 read(conn_fd, buf, sizeof(buf));
73                 sleep(3);
74                 write(conn_fd, "i am server", strlen("i am server"));
75             }
76         }
77     }
78 }

client端

 1 #include <stdio.h>
 2 #include <sys/socket.h>
 3 #include <sys/un.h>
 4 #define SERVER_SOCKET_FILE  "/tmp/server_socket"
 5 int main()
 6 {
 7     int ret = 0;
 8     int retry = 5;
 9     int i = 0;
10     int client_fd = 0;
11     struct sockaddr_un server_addr;
12     char buff[4096] = {0};
13     int  recv_data_len = 0;
14     struct sockaddr_un client_addr;
15     socklen_t sock_len = sizeof(client_addr);
16     if ((client_fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0)
17     {
18         printf("create sockfd failed\n");
19         return -1;
20     }
21     printf("update socket create success.\n");
22     memset(&server_addr,0x00,sizeof(server_addr));
23     server_addr.sun_family = AF_UNIX;
24     strncpy(server_addr.sun_path, SERVER_SOCKET_FILE, strlen(SERVER_SOCKET_FILE));
25     for(i = 0; i < retry; i++)
26     {
27         ret = connect(client_fd,(struct sockaddr*)&server_addr,sizeof(server_addr));
28         if(0 != ret)
29         {
30             printf("cannot connect to the server, retry %d time.\n", i);
31             sleep(1);
32             continue;
33         }
34         else
35         {
36             printf("connect server success.\n");
37             break ;
38         }
39     }
40     write(client_fd, "hello", strlen("hello"));
41     while(1)
42     {
43         memset(buff, 0, sizeof(buff));
44         recv_data_len = recvfrom(client_fd, buff, sizeof(buff), 0, (struct sockaddr *)&client_addr, &sock_len);
45         if(recv_data_len <= 0)
46         {
47             sleep(1); //sleep 100ms and receive from socket again
48             printf("recv_data_len is %d.\n", recv_data_len);
49 
50             /* 从新衔接 省略*/
51             close(client_fd);
52             continue;
53         }
54         printf("recv data [%s]\n", buff);
55         /* do something */
56         sleep(1);
57         write(client_fd, "recv data form server", strlen("recv data form server"));
58     }
59     return 0;
60 }

离别编译定名server client,先运转server 后运转client即能够下所示:

 

 

 以上就是linux c历程,会触及到的一些基础的操纵,另有许多的比较主要且基础的内容没有这里并没有讲到。

       打仗了不少项目,总结下来大型项目中触及多历程,多线程,难点在于弄清楚通讯音讯的流向、数据构造的奇妙定义。剩下

的实在就是特定使命的逻辑部份了,假如作者有很好的解释或许编码范例,那明白起来也是很快的,增加功用也是很轻易的事变。

万变不离其宗。搞清楚基础的内容、基础原理,我以为在手艺生长中很主要。

 

 关注微信民众号【嵌入式C部落】,猎取更多英华文章,海量编程材料,让我们一同提高,一同生长。 

  选择打赏方式
微信赞助

打赏

QQ钱包

打赏

支付宝赞助

打赏

  移步手机端
linux C历程经常使用操纵

1、打开你手机的二维码扫描APP
2、扫描左则的二维码
3、点击扫描获得的网址
4、可以在手机端阅读此文章
未定义标签

本文来源:搜奇网

本文地址:https://www.sou7.cn/282304.html

关注我们:微信搜索“搜奇网”添加我为好友

版权声明: 本文仅代表作者个人观点,与本站无关。其原创性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容、文字的真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。请记住本站网址https://www.sou7.cn/搜奇网。

发表评论

选填

必填

必填

选填

请拖动滑块解锁
>>