unix环境编程练习 (1)

函数练习

1.对mmap映射地址操作

mmap(), fstat()

mmap(): 将文件和设备空间映射到内存中,内存操作比磁盘更快。映射成功返回内存地址,是被返回-1.之后可以直接对映射的地址进行操作。
fstat()获取文件的状态。

#include <stdio.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <errno.h>

int main(){
    int fd=open("doc1",O_RDONLY|O_CREAT,0755);
    if(fd == -1){
        perror("open ");
        exit(1);
    }
    struct stat info;
    fstat(fd,&info);
    /* start set NULL, means system set it. */
    /* PROT_READ means memory can be read. */
    /* MAP_PRIVATE means create a copy file, not influce origin file. */
    void *start=mmap(NULL,info.st_size,PROT_READ,MAP_PRIVATE,fd,0);
    if(start == MAP_FAILED) {
        perror("mmap ");
        exit(1);
    }
    printf("%s",(char *)start);
    munmap(start,info.st_size);
    close(fd);
    return 0;
}

本程序将打印文件的内容。如果文件的内容为空,那么将会出现,invalid argument的错误。

2.从标准输入到标准输出

read(), write()
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

int main(){
    int n;
    char buf[1000];
    while((n=read(STDIN_FILENO,buf,1000))>0){
        //printf("output: ");
        if(write(STDOUT_FILENO,buf,n)!=n){
             printf("write error\n");
        }
    }
    if(n<0) printf("read error\n");
    return 0;
}
/*
$ ./stdin_out 
I sf
I sf
sd
sd
sdfsdf
sdfsdf
//output: output: output: 
*/

read()函数是你输入什么,它读取什么的严格类函数。(除了ctrl+D,ctrl+C等特殊情况)

3.查看标准输入的读写属性

fcntl()

使用fcnt()查看文件的属性。

#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>

int main(){
    int flag=fcntl(STDIN_FILENO,F_GETFL,0);
    if(flag<0) {
        perror("error: ");
        return -1;
    }
    int result=flag & O_ACCMODE;
    if(result == O_RDONLY){
        printf("stdin read only\n");
    }
    else if(result == O_WRONLY){
        puts("stdin write only");
    }
    else if(result == O_RDWR){
        puts("stdin read and write");
    }
    else puts("stdin unknown mode");

    if(flag & O_APPEND) puts("stdin append");
    if(flag & O_NONBLOCK) puts("stdin nonblock");
    return 0;
}
/*
./F_GETFL 
stdin read and write
*/

4.终端交互,创建进程

fork(), fgets(), execlp()

使用fork()克隆一个新的进程。fork()有两个返回值,父进程中返回子进程的ID,子进程返回0。
for fgets():
出现换行字符、读到文件尾或是已读了size-1个字符才停止。最后会加上NULL作为字符串结束, 正常的返回值就是buf指针。
execlp():从PATH 环境变量中查找文件并执行
因为终端输入的命令实则是一个小程序,需要进程资源,所以在这里需要fork新的进程

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <string.h>

int main(){
    char buf[100];
    pid_t pid;
    int status;
    printf("%% "); //out put "%"
    while(fgets(buf,100,stdin)!=NULL){  // get cmd from stdin
         int len=strlen(buf);
         if(buf[len-1]=='\n') buf[len-1]=0;
         if((pid=fork())<0) puts("fork error");  //create new process 
         else if(pid==0){
             execlp(buf,buf,NULL);  //execute buf cmd in new process
             printf("could not execute %s",buf);
             exit(1);
         }
         if(pid=waitpid(pid,&status,0)<0) puts("waitpid error");
         printf("%%");
    }
    return 0;
}

/*
execute:
% ls
4.12.sh  dex.sh  doc3       for.sh   t.c  t
%date
Sat Aug 27 15:55:23 CST 2016
%who
root     pts/1        2016-08-27 10:10 (10.21.1.109)
root     pts/0        2016-08-27 09:33 (10.21.1.109)
%
*/

5.与文件的状态相关的写操作

fcntl()

在doc1文件中追加内容 “I love linux”

#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>

int main(){
    int fd=open("doc1",O_RDWR);
    int flag=fcntl(fd,F_GETFL,0);
    flag|=O_APPEND;
    flag=fcntl(fd,F_SETFL,&flag);  // 文件的偏移量到了doc1的末尾
    if(flag<0){
        perror("fcntl error: ");
        return -1;
    }
    char buff[]="I love linux";
    if(write(fd,buff,sizeof(buff))<0){
        perror("write error: ");
    }
    close(fd);
    return 0;
}

6.读取文件的内容到字符串中

system(), fopen(), fgetc()

system()在使用/bin/bash如果失败则会返回127
看到fopen()可以直接使用字符串打开文件,瞬间喜欢上了它。

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>

int main(){
    int cmd=system("pwd > pwd_r");
    if(cmd==127 || cmd==-1){
        perror("system error: ");
        return -1;
    }
    FILE *file=fopen("pwd_r","r");
    if(file==NULL) {
        perror("open file error: ");
        return -1;
    }
    char buff[1005],ch;
    int top=0;
    while((ch=fgetc(file))!=EOF){
        buff[top++]=ch;
    }
    buff[top]=0;
    fclose(file);
    printf("%s",buff);
    return 0;
}
/*
$ ./fopen_write 
/home/wei/mycode/test
*/

7.使用管道,父进程给子进程写一条消息“hello world.”

pipe(), fork(), read, write()
#include <unistd.h>
#include <sys/types.h>
#include <stdio.h>
#include <string.h>

int main(){
    int fd[2]; // 0: read 1: write
    char buff[50]="hello world";
    int result=pipe(fd);
    if(result==-1){
        perror("create pipe error: ");
        return -1;
    }
    pid_t pid=fork();
    if(pid==-1){
        perror("fork error: ");
        return -1;
    }
    if(pid>0){   // if this is old process 
        result=write(fd[1],buff,strlen(buff));
        printf("id: %d\n",getpid());
        return 0;
    }
    else {   // new process 
        read(fd[0],buff,sizeof(buff));
        printf("id: %d  string: %s\n",getpid(),buff);
    }
    return 0;
}
/*
$ ./pipe
id: 26517
id: 26518  string: hello world
*/

8.阻塞的管道

fork()

观察下面的程序:

#include <unistd.h>
#include <stdio.h>
#include <string.h>

int main(){
    char buff[]="this message is sent by child process.";
    int fd[2];
    int result=pipe(fd);
    if(result<0) {
        perror("pipe error: ");
        return -1;
    }
    pid_t pid=fork();
    if(pid<0){
        perror("create process error: ");
        return -1;
    }
    else if(pid==0){
        close(fd[0]);
        int len=strlen(buff);
        while(len>0){
            int rd=write(fd[1],buff,len);
            len-=rd;
            if(rd<0){
                perror("write error: ");
                return -1;
            }
            else {
                printf("has wrote data: %d left data: %d\n",rd,len);
            }
            sleep(3);
            if(len==0) {
                    printf("write finished.\n");      
            }
        }
    }
    else {
        close(fd[1]);
        char readbuff[105];
        while(1){
            int get=read(fd[0],readbuff,105);
            if(get<0){
                perror("read : ");
                return -1;
            }
            else if(get==0) {
                printf("here is no contents.\n");
                break;
            }
            else {
                printf("data : %s\n",readbuff);
            }
        }
    }
    return 0;
}

/*
$ ./wait_pipe 
has wrote data: 38 left data: 0    #子进程写入数据
data : this message is sent by child process.  #父进程读入数据
write finished.    #回到了子进程
here is no contents.   #这是父进程

//如果我们没有sleep(3)
has wrote data: 38 left data: 0   #子进程
write finished.   #子进程
data : this message is sent by child process. #父进程
here is no contents.    #父进程
*/

9.消息队列send and recv message.

ftok(), msgget(), fgets()

key_t ftok( const char * fname, int id )
fname是指定的文件名(已经存在的文件名),一般使用当前目录,如:
key_t key = ftok(“.”, 1); id是子序号。只使用8bits(1-255)。
用于保证两个不同用户下的两组相同程序获得互不干扰的IPC键值。
msgget()用于chungking或者打开消息队列。

//send.c:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/msg.h>
#include <sys/types.h>
#include <sys/ipc.h>
#define Max 105
typedef struct msgmbuf{
    int msg_type;
    char msg_text[Max];
}MsgBuf;
int main(){
    printf("send process start: %d\n",getpid());
    printf("enter your message to send, and \"end\" will kill both process.\n");
    char buff[Max];
    MsgBuf sendmsg;
    char *msgpath="./me";   // the path of create message
    key_t key=ftok(msgpath,'a');
    if(key==-1) {
        perror("create key error: ");
        return -1;
    }
    int msgid=msgget(key,IPC_CREAT|0777);
    if(msgid==-1){
        perror("msgget error: ");
        return -1;
    }
    while(1){
        printf("please enter msg: ");
        fgets(buff,Max,stdin); //file enter contents
        sendmsg.msg_type=1;
        strcpy(sendmsg.msg_text,buff);
        if(msgsnd(msgid,(void *)&sendmsg,Max,0)){
            perror("msgsnd error: ");
            return -1;
        }
        if(strcmp(buff,"end\n")==0){
            printf("send process end.\n");
            return 0;
        }
    }
    return 0;
}

//recv.c:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/types.h>
#include <sys/msg.h>
#define Max 105
typedef struct msgmbuf{
    int msg_type;
    char msg_text[Max];
}MsgBuf;

int main(){
    printf("recv process start: %d\n",getpid());
    char buff[Max];
    char *msgpath="./me";
    key_t key=ftok(msgpath,'a');
    int msgid=msgget(key,IPC_CREAT|0777);
    if(msgid==-1){
        perror("msgget error: ");
        return -1;
    }
    MsgBuf recmsg;
    while(1){
        if(msgrcv(msgid,(void *)&recmsg,Max,0,0)==-1){
            perror("msgrcv error: ");
            return -1;
        }
        if(strcmp(recmsg.msg_text,"end\n")==0){
            printf("recv process end.\n");
            break;
        }
        printf("recv msg: %s",recmsg.msg_text);
    }
    return 0;
}

/*
$ ./send
send process start: 20436
enter your message to send, and "end" will kill both process.
please enter msg: hehe
please enter msg: I love you
please enter msg: end
send process end.
./recv
recv process start: 20437
recv msg: hehe
recv msg: I love you
recv process end.
*/

10.不同进程利用共享内存通信

shmget(), shmctl()
// myshm.h 
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/shm.h>
#include <sys/ipc.h>
#include <string.h>

#define Size 105

// shm.c
#include "myshm.h"

int main(){
    key_t key=ftok("./doc",'a');
    int shmid=shmget(key,Size,IPC_CREAT|IPC_EXCL|0777);
    if(shmid==-1){
        puts("shmared memory exit. here is client.");
        if((shmid=shmget(key,Size,0))==-1){ //the third number is 0 means we can get the exit memory id.
            perror("shmget error: ");
            return -1;
        }
    }
    else puts("created new shared memory");
    char buff[105], *content=NULL;
    printf("If you enter \"read\", we can get contents, or \"enter\", you can input new things into shared memory.\
Other words will kill process. \n");
    while(1){
        printf("%% ");
        if(fgets(buff,Size,stdin)<0){
            perror("fgets error: ");
            return -1;
        }
        content=(char *)shmat(shmid,0,0);
        if(content == (char *)-1){
            perror("shmat: ");
            return -1;
        }
        if(strncmp(buff,"read",4)==0){
            printf("data: \n%s",content);
        }
        else if(strncmp(buff,"enter",5)==0){
            fgets(buff,Size,stdin);
            strcat(content,buff);
            printf("wrote it.");
        }
        else {
            /*IPC_RMID 命令实际上不从内核删除一个段,而是仅仅把这个段标记为删除,\
             * 实际的删除发生在最后一个进程离开这个共享段时。*/
            shmctl(shmid,IPC_RMID,0);
            printf("the process end, By.\n");
            break;
        }
    }
    return 0;
}

/*
./shm
created new shared memory
If you enter "read", we can get contents, or "enter", you can input new things into shared memory.Other words will kill process. 
% enter
I love you
wrote it.% read
data: 
I love you
% enter 
hello world 
wrote it.% s
the process end, By.

./shm
shmared memory exit. here is client.
If you enter "read", we can get contents, or "enter", you can input new things into shared memory.Other words will kill process. 
% read
data: 
I love you
% read
data: 
I love you
hello world
% s
the process end, By.
*/

11.自定义中断信号SIGINT的处理函数

signal()
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>

void stop(int sig){
    printf("ctrl + c stops it!\n");
    exit(0);
}
int main(){
    signal(SIGINT,stop);
    while(1){
        puts("hello world");
    }
    return 0;
}
/*
./signal
hello world
hello world
hello world
hello world
hello world
hello world^Chello world
ctrl + c stops it!
*/

12.线程创建与等待

pthread_create(), pthread_join(), pthread_self()
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>

void *thread_show(void *args){
    int *thread_arg=(int *)args;
    printf("I'm thread %lu, counter is %d\n",pthread_self(),*thread_arg); // g(long int)syscall(178),gettid() means syscall(178) 
    sleep(1);
}
int main(){
    int i,ret;
    pthread_t thread[6];
    for(i=0;i<6;i++){
        printf("here is thread: %d\n",i);
        ret=pthread_create(&thread[i],NULL,thread_show,&i); 
        // 第三个参数是线程的运行函数,第四个参数是运行函数的参数
        if(ret!=0) printf("error: %d thread can't be created.\n",i);
    }
    for(i=0;i<6;i++){  //等待着线程结束,此时的i等于0
        pthread_join(thread[i],NULL);
    }
    return 0;
}
/*
./pthread 
here is thread: 0
here is thread: 1
here is thread: 2
I'm thread 140437552871168, counter is 2
I'm thread 140437544478464, counter is 2
here is thread: 3
here is thread: 4
here is thread: 5
I'm thread 140437527693056, counter is 4
I'm thread 140437519300352, counter is 5
I'm thread 140437536085760, counter is 3
I'm thread 140437510907648, counter is 0
*/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值