unix下的编程,初学篇

Posted on 2010-09-24 10:50 子期 阅读(341) 评论(0)  编辑  收藏

程序自动维护工具make

1.  UNIX运行程序的生成过程

C语言是UNIX环境下最主要的程序设计语言。UNIXC语言编译器cc能将C语言源程序、汇编程序和目标程序编译、链接成可执行文件。cc按文件后缀区分文件类别,常用的有:

l  .c为后缀的文件表示C语言源程序

l  .o为后缀的文件表示目标程序

l  .a为后缀的文件表示由目标程序构成的档案库

cc首先调用cpp进行预处理,将源程序编译成以.o为后缀的目标文件,最后调用ld命令将目标文件和档案库文件链接成可执行文件:

.c

 

.o

 

可执行文件

 
 

 

 


2.  make的基本工作原理

make首先从指定的文件(缺省为makefileMakefile)中获取可执行文件及程序模块间的相互关系的信息,然后根据各个文件的最后修改日期找出那些经过编译、但已经过时的模块(“过时”是指用来生成这些模块的源文件已经修改过,但这些模块本身却没有被更新),针对每一个过时的模块,按其相互关系中所给出的命令对该过时的模块进行更新操作。

 

3.  依赖关系描述

make中,目标和生成该目标的源文件之间的关系称为依赖关系。一个目标的状态取决于它所依赖的那些对象的状态,一旦依赖对象的状态发生改变,make就执行依赖关系中所定义的那组命令来重新生成该目标。在makefile中,其语法格式为:

object: source_list

        [cmd_list]

 

make有自己的内部转换规则,其作用是描述如何将一类源文件转换成另一类文件(目标文件)。

 

4.  一个简单的make文件

# cat makefile

all: t_fork t_signal

 

t_fork: t_fork.o

        cc -o t_fork t_fork.o

 

t_signal: t_signal.o

        cc -o t_signal t_signal.o

 

.c.o:

        cc -c $<

 

进程和信号

1.  进程和程序

进程是正在执行的一个程序的实例。

l  程序是静态概念,本身可以作为一种软件资源长期保存,进程是程序的执行过程,是动态概念,是动态地产生和消亡的;

l  进程不能脱离具体程序而虚设,程序规定了相应进程所要完成的动作;

l  进程由程序、数据集合和进程控制块组成。

 

2.  进程和子进程

子进程是由另外一个进程所产生的进程,产生子进程的进程为父进程。子进程继承父进程的环境。UNIX中创建子进程的方法是使用系统调用forkfork复制了父进程的数据段、堆栈段和进程环境,子进程共享父进程的代码段。

 

3.  信号

信号是送到进程的“软中断”,信号通知进程在它们的环境中出现了非正常的事件。对信号的处理有3种:

l  忽略:停止输送信号给进程。

l  捕捉:用户提供对该信号的处理函数。

l  缺省:信号的缺省功能。

 

4.  信号的发送

l  系统送出:比如“浮点溢出”等。

l  键盘送出:比如在键盘上键入“CTRL_C”等。

l  进程送出:kill系统调用,包括命令行的调用和用户进程的调用。

 

5.  例子:

# cat t_fork.c

#include <stdio.h>

main ()

{

  int pid;

  register i,j;

 

  printf ("main process begin ...\n");

  pid=fork ();

  if (pid<0) {

    perror ("fork error!");

    return (-1);

  }

 

  if (pid>0) /* parent process */

    printf ("\t\t\tin parent process ...\n");

  else /* child process */

    printf ("in child process ...\n");

 

  for (i=0;i<10000;i++)

    for (j=0;j<10000;j++)  ;

 

  if (pid>0) /* parent process */

    printf ("\t\t\tparent process over ...\n");

  else /* child process */

    printf ("child process over ...\n");

 

  exit (0);

}

 

 

# cat t_signal.c

#include <signal.h>

 

main ()

{

  void k_fun ();

  void i_fun ();

 

  signal (SIGTERM,k_fun);

  signal (SIGINT,i_fun);

  while (1) ;

}

void k_fun ()

{

  printf ("\nNOTE: I am killed !\n");

  exit (0);

}

void i_fun ()

{

  printf ("\nNOTE: I am interrupted !\n");

  exit (0);

}

 

上机练习:

1.    系统接收屏幕输入,若30秒内不能成功接收,则提示超时,并退出程序。

2.    父进程进行10000*10000次加法运算,子进程负责计时(在屏幕上显示用去的秒数),父进程完成运算后,先退出子进程,父进程最后退出。

3.    makefile中完成上述两个程序的编译、链接,并运行通过。

 

(相关函数:signalforkwaitkillsleep

共享内存通信

1.  UNIX系统进程间通信机制

消息、信号灯、共享内存是UNIX主机中各进程间常用的三种通信机制。

l  消息允许进程将格式化的数据流发到任何别的进程;

l  信号灯用来保持进程之间的同步运行;

l  共享内存允许多个进程共享其虚拟地址空间中的部分区域。

共享内存是UNIX系统上最快的通信方式。

另外还可以利用管道进行同步通信。

 

2.  利用共享内存进行进程间通信

# cat t_shm_serv.c

#include <stdio.h>

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/shm.h>

 

main ()

{

  char   c;

  int    shmid;

  key_t  key;

  void  *shmat ();

  char  *shm, *s;

  struct shmid_ds buf;

 

  key= ftok ("my_shm_key",1);

 

  if ((shmid=shmget (key,27,IPC_CREAT|0666))<0) {

    perror ("shmget error!");

    exit (-1);

  }

 

  if ((shm=shmat (shmid,NULL,0))==NULL) {

    perror ("shmat error!");

    exit (-1);

  }

 

  s=shm;

  for (c='a';c<='z';c++)

    *s++=c;

 

  *s=0;

 

  printf ("waiting for client ...");

  fflush (stdout);

  while (*shm!='*')

sleep (1);

  printf ("\nclient arrived !\n");

 

  shmdt (shm);

  shmctl (shmid,IPC_RMID,&buf);

  exit (0);

}

 

# cat t_shm_cli.c

#include <stdio.h>

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/shm.h>

 

main ()

{

  char   c;

  int    shmid;

  key_t  key;

  char  *shm,*s;

 

  key=ftok ("my_shm_key",1);

 

  if ((shmid=shmget (key,27,0666))<0) {

    perror ("shmget error!\n");

    exit (-1);

  }

 

  if ((shm=shmat (shmid,NULL,0))==NULL) {

    perror ("shmat error!\n");

exit (-1);

  }

 

  for (s=shm;*s!=0;s++)

    printf ("%c",*s);

  printf ("\n");

  *shm='*';

  shmdt (shm);

  exit (0);

}

 

3.  利用信号灯进行同步

# cat t_sem_w.c

#include <stdio.h>

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/sem.h>

 

main ()

{

    struct sembuf sem1_p = { 0, -1, 0 };

    struct sembuf sem2_v = { 1,  1, 0 };

    int         i,sem_id,sem_val;

    key_t       _ipc_key;

    int         val;

  union semum {

    int val;

    struct semid_ds *buf;

    ushort *arry;

  } semctl_arg;

 

  _ipc_key=ftok ("my_sem_key",1);

 

  sem_id=semget (_ipc_key,2,0666|IPC_CREAT);

  semctl_arg.val=1;

  semctl (sem_id,0,SETVAL,semctl_arg);

  semctl_arg.val=0;

  semctl (sem_id,1,SETVAL,semctl_arg);

 

  for (i=1;i<=10;i++) {

    semop (sem_id, &sem1_p, 1 );

    printf ("This [%d]",i);

    fflush (stdout);

    semop (sem_id, &sem2_v, 1 );

  }

 

  semctl (sem_id,0,IPC_RMID,0);

 

  return (0);

}

 

# cat t_sem_r.c

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/sem.h>

 

main ()

{

    struct sembuf sem1_v = { 0,  1, 0 };

    struct sembuf sem2_p = { 1, -1, 0 };

    int         i,sem_id,sem_val;

    key_t       _ipc_key;

    int         val;

  union semum {

    int val;

    struct semid_ds *buf;

    ushort *arry;

  } semctl_arg;

  char t_buf[50];

 

  _ipc_key=ftok ("my_sem_key",1);

 

  sem_id=semget (_ipc_key,2,0666|IPC_EXCL);

 

  for (i='a';i<='j';i++) {

    semop (sem_id, &sem2_p, 1 );

    memset (t_buf,0,sizeof t_buf);

    sprintf (t_buf,"echo \"          This [%c]\" >/dev/ttyp0",i);

    system (t_buf);

    sleep (1);

    semop (sem_id, &sem1_v, 1 );

  }

 

  return (0);

}

 

上机练习:

1.    从一个进程通过共享内存发送若干字符串给第二个进程,第二个进程每接收一个就在屏幕上显示一次,直到接收到“-o-”为止。

2.    考虑共享内存中最多可以容纳5个字符串的情况。

 

 

 

 

 

 

 

 

 

socket与网络通信

1.  socket通信机制

socket(套接字)提供了进程间通信的一般方法,并允许使用复杂的通信协议。其核心结构包括三部分:套接字层、协议层、设备层。

 

 

 

 

 


Socket支持UNIX系统域,在socket()系统调用中用关键字AF_UNIX表示,socket也支持互连网域,用关键字AF_INET表示。

常用的socket有两种类型,虚电路和数据报,其关键字分别为SOCK_STREAMSOCK_DGRAM。虚电路(又称流)提供双向、可靠、有序的通信,而数据报不能保证顺序传递信息,而且可能丢失信息。

 

2.  配置文件

/etc/hosts

 

3.  一个简单的例子

# cat t_tcp_serv.c

#include <stdio.h>

#include <signal.h>

#include <sys/types.h>

#include <sys/socket.h>

#include <netinet/in.h>

#include <netdb.h>

 

main ()

{

  int cc,len,sd,sdc,sum;

  char hostname[21];

  struct hostent     *host;

  struct sockaddr_in sock;

  char buf[100];

 

  sd=socket (AF_INET,SOCK_STREAM,0);

  if (sd<0)

    perror ("socket error!");

 

  gethostname (hostname,20);

  host=gethostbyname (hostname);

  if (host==NULL)

perror ("gethostbyname error !");

 

  sock.sin_family=AF_INET;

  memcpy ((char *)&sock.sin_addr,host->h_addr,host->h_length);

  sock.sin_port=htons (7500);

 

  if (bind (sd,(struct sockaddr *)&sock,sizeof (sock))<0) {

    perror ("bind error !");

    close (sd);

    exit (0);

  }

 

  printf ("Port# %d\n", ntohs (sock.sin_port));

  printf ("... waiting for connection ...\n");

 

  if (listen (sd,1)<0) {

    perror ("listen error !");

    close (sd);

    exit (0);

  }

 

  len=sizeof (sock);

  sdc=accept (sd,(struct sockaddr *)&sock,&len);

  if (sdc<0) {

    perror ("accept error !");

    close (sd);

    exit (0);

  }

 

  printf ("Connected to client !\n");

 

  while (1) {

    if (cc=recv (sdc,buf,sizeof (buf)-1,0)) {

      buf[cc]=0;

      printf ("%s",buf);

      fflush (stdout);

    }

    else if (cc==0) {

      printf ("Received over !\n");

      close (sdc);

      close (sd);

      printf ("... server disconnected ...\n");

      exit (0);

    }

    else {

      perror ("receive error !\n");

      exit (-1);

    }

  }

}

 

# cat t_tcp_cli.c

#include <stdio.h>

#include <signal.h>

#include <sys/types.h>

#include <sys/socket.h>

#include <netinet/in.h>

#include <netdb.h>

 

main ()

{

  int cc,len,sd,sdc,sum;

  char hostname[21];

  struct hostent     *host;

  struct sockaddr_in sock;

  char buf[100];

 

  sd=socket (AF_INET,SOCK_STREAM,0);

  if (sd<0) {

    perror ("socket error !");

    exit (0);

  }

 

  strcpy (hostname,"opentp");

  host=gethostbyname (hostname);

 

  sock.sin_family=AF_INET;

  memcpy ((char *)&sock.sin_addr,host->h_addr,host->h_length);

  sock.sin_port=htons (7500);

 

  if (connect (sd,(struct sockaddr *)&sock,sizeof (sock))<0) {

    perror ("connect error !");

    close (sd);

    exit (0);

  }

 

  printf ("connect to server [%s] ...\n",hostname);

  printf ("Type in messages: (CTRL-D to exit)\n");

 

  while (1) {

    memset (buf,0,sizeof buf);

    cc=read (0,buf,sizeof (buf)-1);

    if (send (sd,buf,cc,0)<0)

      printf ("Send [%s] error !\n",buf);

    if (cc==0)

      break;

  }

 

  close (sd);

  printf ("... client disconnected ...\n");

  exit (0);

}

 

上机练习:

1.    从一台UNIX服务器向另一台UNIX服务器发送信息,接收到后发送响应给发送方。

2.    从一台UNIX服务器向另一台UNIX服务器发送一个文件。

 


只有注册用户登录后才能发表评论。


网站导航:
 

posts - 0, comments - 0, trackbacks - 0, articles - 16

Copyright © 子期