Linux多进程

来源:互联网 发布:ubuntu的apache服务器 编辑:程序博客网 时间:2024/06/06 08:16

将有关多进程的处理整理于此

1.IBM GDB

http://www.ibm.com/developerworks/cn/linux/l-cn-gdbmp/

2.在 Linux 上实现基于 Socket 的多进程实时通信

http://www.ibm.com/developerworks/cn/linux/l-socket-ipc/


3Linux多任务编程编写多进程程序及其代码

http://www.linuxidc.com/Linux/2013-06/85903p6.htm3.



//***************************************************************************************************************

实验目的

通过编写多进程程序,熟练掌握fork()、exec()、wait()和waitpid()等函数的使用,进一步理解在Linux中多进程编程的步骤。

实验内容

该实验有3个进程,其中一个为父进程,其余两个是该父进程创建的子进程,其中一个子进程运行“ls -l”指令,另一个子进程在暂停5s后异常退出。父进程先用阻塞方式等待第一个进程的结束,然后用非阻塞方式等待另一个子进程的退出,待收集到第2个子进程结束的消息后,父进程就返回。

实验步骤

该实验的流程图如下

实验源代码

先看一下下面的代码,这个程序能得到我们所希望的结果吗?它的运行会产生几个进程?

执行结果如下图

也有可能会出现下面的结果

分析执行结果可以指知道,这里其实是产生了3个子进程,在子进程2中又产生了一个子进程1。

下面咱们贴出正确的实验代码:

执行结果如下图

不论程序执行多少次,结果都是一样的。对比上一个结果,咱们就可以理解多进程该怎么创建了。一定要明确创建子进程的父进程是哪一个。

相关实验代码上传到网站,multi_proc_wrong.c下载,multi_proc.c下载

免费下载地址在 http://linux.linuxidc.com/

用户名与密码都是www.linuxidc.com

具体下载目录在 /2013年资料/6月/12日/Linux多任务编程



//***************************************************************************************************************

使用 GDB 调试多进程程序

GDB 是 linux 系统上常用的调试工具,本文介绍了使用 GDB 调试多进程程序的几种方法,并对各种方法进行比较。

田 强 (tianq@cn.ibm.com), 软件工程师, IBM中国软件开发中心

2007 年 7 月 30 日

  • +内容

GDB 是 linux 系统上常用的 c/c++ 调试工具,功能十分强大。对于较为复杂的系统,比如多进程系统,如何使用 GDB 调试呢?考虑下面这个三进程系统:

进程
进程

Proc2 是 Proc1 的子进程,Proc3 又是 Proc2 的子进程。如何使用 GDB 调试 proc2 或者 proc3 呢?

实际上,GDB 没有对多进程程序调试提供直接支持。例如,使用GDB调试某个进程,如果该进程fork了子进程,GDB会继续调试该进程,子进程会不受干扰地运行下去。如果你事先在子进程代码里设定了断点,子进程会收到SIGTRAP信号并终止。那么该如何调试子进程呢?其实我们可以利用GDB的特点或者其他一些辅助手段来达到目的。此外,GDB 也在较新内核上加入一些多进程调试支持。

接下来我们详细介绍几种方法,分别是 follow-fork-mode 方法,attach 子进程方法和 GDB wrapper 方法。

follow-fork-mode

在2.5.60版Linux内核及以后,GDB对使用fork/vfork创建子进程的程序提供了follow-fork-mode选项来支持多进程调试。

follow-fork-mode的用法为:

set follow-fork-mode [parent|child]

  • parent: fork之后继续调试父进程,子进程不受影响。
  • child: fork之后调试子进程,父进程不受影响。

因此如果需要调试子进程,在启动gdb后:

(gdb) set follow-fork-mode child

并在子进程代码设置断点。

此外还有detach-on-fork参数,指示GDB在fork之后是否断开(detach)某个进程的调试,或者都交由GDB控制:

set detach-on-fork [on|off]

  • on: 断开调试follow-fork-mode指定的进程。
  • off: gdb将控制父进程和子进程。follow-fork-mode指定的进程将被调试,另一个进程置于暂停(suspended)状态。

注意,最好使用GDB 6.6或以上版本,如果你使用的是GDB6.4,就只有follow-fork-mode模式。

follow-fork-mode/detach-on-fork的使用还是比较简单的,但由于其系统内核/gdb版本限制,我们只能在符合要求的系统上才能使用。而且,由于follow-fork-mode的调试必然是从父进程开始的,对于fork多次,以至于出现孙进程或曾孙进程的系统,例如上图3进程系统,调试起来并不方便。

Attach子进程

众所周知,GDB有附着(attach)到正在运行的进程的功能,即attach <pid>命令。因此我们可以利用该命令attach到子进程然后进行调试。

例如我们要调试某个进程RIM_Oracle_Agent.9i,首先得到该进程的pid

[root@tivf09 tianq]# ps -ef|grep RIM_Oracle_Agent.9inobody    6722  6721  0 05:57 ?        00:00:00 RIM_Oracle_Agent.9iroot      7541 27816  0 06:10 pts/3    00:00:00 grep -i rim_oracle_agent.9i

通过pstree可以看到,这是一个三进程系统,oserv是RIM_Oracle_prog的父进程,RIM_Oracle_prog又是RIM_Oracle_Agent.9i的父进程。

[root@tivf09 root]# pstree -H 6722
通过 pstree 察看进程
通过 pstree 察看进程

启动GDB,attach到该进程

用 GDB 连接进程
用 GDB 连接进程

现在就可以调试了。一个新的问题是,子进程一直在运行,attach上去后都不知道运行到哪里了。有没有办法解决呢?

一个办法是,在要调试的子进程初始代码中,比如main函数开始处,加入一段特殊代码,使子进程在某个条件成立时便循环睡眠等待,attach到进程后在该代码段后设上断点,再把成立的条件取消,使代码可以继续执行下去。

至于这段代码所采用的条件,看你的偏好了。比如我们可以检查一个指定的环境变量的值,或者检查一个特定的文件存不存在。以文件为例,其形式可以如下:

void debug_wait(char *tag_file){    while(1)    {        if (tag_file存在)            睡眠一段时间;        else            break;    }}

当attach到进程后,在该段代码之后设上断点,再把该文件删除就OK了。当然你也可以采用其他的条件或形式,只要这个条件可以设置/检测即可。

Attach进程方法还是很方便的,它能够应付各种各样复杂的进程系统,比如孙子/曾孙进程,比如守护进程(daemon process),唯一需要的就是加入一小段代码。

GDB wrapper

很多时候,父进程 fork 出子进程,子进程会紧接着调用 exec族函数来执行新的代码。对于这种情况,我们也可以使用gdb wrapper 方法。它的优点是不用添加额外代码。

其基本原理是以gdb调用待执行代码作为一个新的整体来被exec函数执行,使得待执行代码始终处于gdb的控制中,这样我们自然能够调试该子进程代码。

还是上面那个例子,RIM_Oracle_prog fork出子进程后将紧接着执行RIM_Oracle_Agent.9i的二进制代码文件。我们将该文件重命名为RIM_Oracle_Agent.9i.binary,并新建一个名为RIM_Oracle_Agent.9i的shell脚本文件,其内容如下:

[root@tivf09 bin]# mv RIM_Oracle_Agent.9i RIM_Oracle_Agent.9i.binary[root@tivf09 bin]# cat RIM_Oracle_Agent.9i#!/bin/shgdb RIM_Oracle_Agent.binary

当fork的子进程执行名为RIM_Oracle_Agent.9i的文件时,gdb会被首先启动,使得要调试的代码处于gdb控制之下。

新的问题来了。子进程是在gdb的控制下了,但还是不能调试:如何与gdb交互呢?我们必须以某种方式启动gdb,以便能在某个窗口/终端与gdb交互。具体来说,可以使用xterm生成这个窗口。

xterm是X window系统下的模拟终端程序。比如我们在Linux桌面环境GNOME中敲入xterm命令:

xterm
xterm

就会跳出一个终端窗口:

终端
终端

如果你是在一台远程linux服务器上调试,那么可以使用VNC(Virtual Network Computing) viewer从本地机器连接到服务器上使用xterm。在此之前,需要在你的本地机器上安装VNC viewer,在服务器上安装并启动VNC server。大多数linux发行版都预装了vnc-server软件包,所以我们可以直接运行vncserver命令。注意,第一次运行vncserver时会提示输入密码,用作VNC viewer从客户端连接时的密码。可以在VNC server机器上使用vncpasswd命令修改密码。

[root@tivf09 root]# vncserver New 'tivf09:1 (root)' desktop is tivf09:1Starting applications specified in /root/.vnc/xstartupLog file is /root/.vnc/tivf09:1.log[root@tivf09 root]#[root@tivf09 root]# ps -ef|grep -i vncroot     19609     1  0 Jun05 ?        00:08:46 Xvnc :1 -desktop tivf09:1 (root)   -httpd /usr/share/vnc/classes -auth /root/.Xauthority -geometry 1024x768   -depth 16 -rfbwait 30000 -rfbauth /root/.vnc/passwd -rfbport 5901 -pnroot     19627     1  0 Jun05 ?        00:00:00 vncconfig -iconicroot     12714 10599  0 01:23 pts/0    00:00:00 grep -i vnc[root@tivf09 root]#

Vncserver是一个Perl脚本,用来启动Xvnc(X VNC server)。X client应用,比如xterm,VNC viewer都是和它通信的。如上所示,我们可以使用的DISPLAY值为tivf09:1。现在就可以从本地机器使用VNC viewer连接过去:

VNC viewer:输入服务器
VNC viewer:输入服务器

输入密码:

VNC viewer:输入密码
VNC viewer:输入密码

登录成功,界面和服务器本地桌面上一样:

VNC viewer
VNC viewer

下面我们来修改RIM_Oracle_Agent.9i脚本,使它看起来像下面这样:

#!/bin/shexport DISPLAY=tivf09:1.0; xterm -e gdb RIM_Oracle_Agent.binary

如果你的程序在exec的时候还传入了参数,可以改成:

#!/bin/shexport DISPLAY=tivf09:1.0; xterm -e gdb --args RIM_Oracle_Agent.binary $@

最后加上执行权限

[root@tivf09 bin]# chmod 755 RIM_Oracle_Agent.9i

现在就可以调试了。运行启动子进程的程序:

[root@tivf09 root]# wrimtest -l 9i_linuxResource Type  : RIMResource Label : 9i_linuxHost Name      : tivf09User Name      : mdstatusVendor         : OracleDatabase       : rimDatabase Home  : /data/oracle9i/920Server ID      : rimInstance Home  : Instance Name  : Opening Regular Session...

程序停住了。从VNC viewer中可以看到,一个新的gdb xterm窗口在服务器端打开了

gdb xterm 窗口
gdb xterm窗口
[root@tivf09 root]# ps -ef|grep gdbnobody   24312 24311  0 04:30 ?        00:00:00 xterm -e gdb RIM_Oracle_Agent.binarynobody   24314 24312  0 04:30 pts/2    00:00:00 gdb RIM_Oracle_Agent.binaryroot     24326 10599  0 04:30 pts/0    00:00:00 grep gdb

运行的正是要调试的程序。设置好断点,开始调试吧!

注意,下面的错误一般是权限的问题,使用 xhost 命令来修改权限:

xterm 错误
xterm 错误
[root@tivf09 bin]# export DISPLAY=tivf09:1.0[root@tivf09 bin]# xhost +access control disabled, clients can connect from any host

xhost + 禁止了访问控制,从任何机器都可以连接过来。考虑到安全问题,你也可以使用xhost + <你的机器名>。

小结

上述三种方法各有特点和优劣,因此适应于不同的场合和环境:

  • follow-fork-mode方法:方便易用,对系统内核和GDB版本有限制,适合于较为简单的多进程系统
  • attach子进程方法:灵活强大,但需要添加额外代码,适合于各种复杂情况,特别是守护进程
  • GDB wrapper方法:专用于fork+exec模式,不用添加额外代码,但需要X环境支持(xterm/VNC)。
//********************************************************************************************************************************

在 Linux 上实现基于 Socket 的多进程实时通信

套接口(Socket)为目前 Linux 上最为广泛使用的一种的进程间通信机制。但是它不能直接用来多进程之间的相互实时通信。本文提出一个基于 Socket 的多进程之间通信的实现方法,并给出样本程序的实现和说明。

周欣 (jones_zhou@yahoo.com.cn), 软件工程师

2005 年 3 月 01 日

  • +内容

套接口(Socket)为目前Linux上最为广泛使用的一种的进程间通信机制,与其他的Linux通信机制不同之处在于除了它可用于单机内的进程间通信以外,还可用于不同机器之间的进程间通信。但是由于Socket本身不支持同时等待和超时处理,所以它不能直接用来多进程之间的相互实时通信。

本文提出一个基于Socket的多进程之间通信的实现方法。原理是建立一个进程专门用来做为通信服务器(server)来中转各个进程之间的通信。它首先启动一个用来监视连接要求的listening Socket,并把它的描述(Descriptor)号加入到一个事先定义好的fd_set的集合中,这个fd_set的集合用来存放listening Socket和后来生成的通信Socket的描述号。Server运用system call select来实时检查是否有数据到达这个集合中的任何一个socket,如果有数据到达listening Socket,则这一定是客户端发起的连接请求,于是生成一个新的通信Socket与该客户端连接,将生成的Socket描述号加入到fd_set的集合中,将客户端的ID号和与之对应的Socket的描述号记录在ID登记表中。如果有数据到达某个通信Socket,则这一定是某个客户端发起的通信请求,读出数据并取出收信客户端ID号,在ID登记表中找到与之对应的Socket描述号,将数据通过对应Socket传送到收信客户端。

其他各进程作为客户端(client)。客户端的动作是首先建立通信Socket连接服务器端,然后通过通信Socket进行送信和收信。

下面给出具体的程序实现和说明,

首先给出Server端的程序,在这里假设有两个客户端要进行实时通信,ClientA向ClientB发送字符1,ClientB向ClientA发送字符2。

  #include  <sys/types.h>#include <sys/socket.h>#include <stdio.h>#include <sys/un.h>#include <sys/time.h>#include <sys/ioctl.h>#include <unistd.h>#include <netinet/in.h>int main(){  int        rcd ;  struct sockaddr_un  server_sockaddr ;  int        backlog ;  ushort        ci ;  int        watch_fd_list[3] ;  fd_set        catch_fd_set ;  fd_set        watchset ;  int    new_cli_fd ;  int   maxfd;  int    socklen ,server_len;  struct sockaddr_un  cli_sockaddr ;  struct {    char  module_id ;  /* Module ID    */    int  cli_sock_fd ;  /* Socket ID    */  } cli_info_t[2] ;    for (ci=0;ci<=1;ci++)    cli_info_t[ci].cli_sock_fd=-1;      for (ci=0;ci<=2;ci++)    watch_fd_list[ci]=-1;        int server_sockfd,client_sockfd;    server_sockfd = socket( AF_UNIX, SOCK_STREAM, 0 ) ;  server_sockaddr.sun_family = AF_UNIX ;  strcpy( server_sockaddr.sun_path, "server_socket" ) ;  server_len=sizeof(server_sockaddr);  rcd = bind( server_sockfd, ( struct sockaddr * )&server_sockaddr, server_len ) ;    backlog = 5 ;  rcd = listen( server_sockfd, backlog ) ;  printf("SERVER::Server is  waitting on socket=%d \n",server_sockfd);  watch_fd_list[0]=server_sockfd;  FD_ZERO( &watchset ) ;  FD_SET( server_sockfd, &watchset ) ;  maxfd=watch_fd_list[0];

在上面的程序中,Server生成listening Socket(server_sockfd),初始化Socket监视集合(watchset),并将listening Socket放入Socket监视集合中。

while (1){char ch;int fd;int nread;catch_fd_set=watchset;rcd = select( maxfd+1, &catch_fd_set, NULL, NULL, (struct timeval *)0 ) ;

在上面的程序中,Server运用系统调用函数 select来实时检查是否有数据到达Socket监视集合中的任何一个socket。

        if ( rcd < 0 ) {      printf("SERVER::Server 5 \n");      exit(1);    }    if ( FD_ISSET( server_sockfd, &catch_fd_set ) ) {      socklen = sizeof( cli_sockaddr ) ;      new_cli_fd = accept( server_sockfd, ( struct sockaddr * )        &( cli_sockaddr ), &socklen ) ;      printf(" SERVER::open communication with  Client %s on socket %d\n",            cli_sockaddr.sun_path,new_cli_fd);          for (ci=1;ci<=2;ci++){        if(watch_fd_list[ci] != -1) continue;        else{            watch_fd_list[ci] = new_cli_fd;          break;        }        }        FD_SET(new_cli_fd , &watchset ) ;      if ( maxfd < new_cli_fd ) {        maxfd = new_cli_fd ;      }            for ( ci=0;ci<=1;ci++){        if(cli_info_t[ci].cli_sock_fd == -1) {          cli_info_t[ci].module_id=cli_sockaddr.sun_path[0];          cli_info_t[ci].cli_sock_fd=new_cli_fd;          break;        }          }              continue;      }

在上面的程序中,Server运用系统调用函数FD_ISSET来检查是否有客户端的连接请求到达Listening Socket, 如果返回值大于0,Server生成一个新的通信Socket (new_cli_fd)与客户端连接。将新生成的通信Socket放入Socket监视集合中(FD_SET)。将客户端的信息(ID号和Socket描述号)保存在注册表cli_info_t中

    for ( ci = 1; ci<=2 ; ci++ ) {      int      dst_fd = -1 ;      char      dst_module_id;      char       src_module_id;      int    i;      if (watch_fd_list[ ci ]==-1) continue;      if ( !FD_ISSET( watch_fd_list[ ci ], &catch_fd_set ) ) {        continue ;      }      ioctl(watch_fd_list[ ci ],FIONREAD,&nread);      if (nread==0){        continue;      }        read( watch_fd_list[ ci ], &dst_module_id, 1 ) ;      for (i=0;i<=1;i++){        if(cli_info_t[i].module_id == dst_module_id)           dst_fd=  cli_info_t[i].cli_sock_fd;           if(cli_info_t[i].cli_sock_fd==watch_fd_list[ ci ])         src_module_id=  cli_info_t[i].module_id;          }      read( watch_fd_list[ ci ], &ch, 1 ) ;      printf("SERVER::char=%c to  Client %c on socket%d\n",ch, dst_module_id,dst_fd);        write(dst_fd,&src_module_id, 1 ) ;      write(dst_fd,&ch, 1 ) ;    }  }  }

在上面的程序中,如果有数据到达某个通信Socket,Server则读出数据并取出收信客户端ID号。在ID登记表中找到收信客户端对应的Socket描述号。并将数据通过对应Socket传送到收信客户端

给出客户端 ClientA的程序

ClientB的程序只需将 char dst_module_id='B'; 改为char dst_module_id='A';char ch='1'; 改为char char ch='2';既可。

#include  <sys/types.h>#include <sys/socket.h>#include <stdio.h>#include <sys/un.h>#include <unistd.h>#include <netinet/in.h>#include <arpa/inet.h>int main(){int client_sockfd;int len;struct sockaddr_un server_sockaddr,cli_sockaddr;int result;char dst_module_id='B';char ch='1';char src_module_id;client_sockfd= socket(AF_UNIX,SOCK_STREAM,0);cli_sockaddr.sun_family = AF_UNIX ;strcpy( cli_sockaddr.sun_path, "A" ) ;bind(client_sockfd,(struct sockaddr * )&cli_sockaddr, sizeof( cli_sockaddr ) ) ;server_sockaddr.sun_family=AF_UNIX;strcpy( server_sockaddr.sun_path, "server_socket" ) ;len=sizeof(server_sockaddr);result = connect(client_sockfd,( struct sockaddr * )&server_sockaddr,len);if (result <0){printf("ClientA::error on connecting \n");exit(1);}printf("ClientA::succeed in connecting with server\n");sleep(10);write(client_sockfd,&dst_module_id,1);write(client_sockfd,&ch,1); read (client_sockfd,&src_module_id,1); read (client_sockfd,&ch,1); printf("ClientA::char from  Client %c =%c\n", src_module_id,ch);close (client_sockfd);}

下面是样本程序的执行结果

[root@zhou test]# ./server &[3] 4301[root@zhou test]# SERVER::Server is  waitting on socket=3./clientA & ./clientB &[4] 4302[5] 4303ClientA::succeed in connecting with server SERVER::open communication with  Client A on socket 4[root@zhou test]#  SERVER::open communication with  Client B on socket 5ClientB::succeed in connecting with serverSERVER::char=1 to  Client B on socket5ClientB::char from  Client A =1SERVER::char=2 to  Client A on socket4ClientA::char from  Client B =2

程序清单下载:server.c,clientA.c

#include  <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <sys/un.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <netinet/in.h>


int main()
{
    int                rcd ;
    struct sockaddr_un    server_sockaddr ;
    int                backlog ;
    ushort                ci ;
    int                watch_fd_list[3] ;
    fd_set                catch_fd_set ;
    fd_set                watchset ;
    int    new_cli_fd ;
    int     maxfd;
    int    socklen,server_len;
    struct sockaddr_un    cli_sockaddr ;
    struct {
        char        module_id ;        /* Module ID            */
        int        cli_sock_fd ;    /* Socket ID        */
    } cli_info_t[2] ;
    
    for (ci=0;ci<=1;ci++)
        cli_info_t[ci].cli_sock_fd=-1;
        
    for (ci=0;ci<=2;ci++)
        watch_fd_list[ci]=-1;    
        
    int server_sockfd,client_sockfd;
    
    server_sockfd = socket( AF_UNIX, SOCK_STREAM, 0 ) ;
    server_sockaddr.sun_family = AF_UNIX ;
//    server_sockaddr.sin_addr.s_addr=htonl(INADDR_ANY);
//    server_sockaddr.sin_port=htons(9734);
    strcpy( server_sockaddr.sun_path, "server_socket" ) ;
    server_len=sizeof(server_sockaddr);
    rcd = bind( server_sockfd, ( struct sockaddr * )&server_sockaddr, server_len ) ;
    
    backlog = 5 ;
    rcd = listen( server_sockfd, backlog ) ;
    printf("SERVER::Server is  waitting on socket=%d \n",server_sockfd);

    watch_fd_list[0]=server_sockfd;
    FD_ZERO( &watchset ) ;
    FD_SET( server_sockfd, &watchset ) ;
    maxfd=watch_fd_list[0];
    
    while (1){
        char ch;
        int fd;
        int nread;
        
        catch_fd_set=watchset;
        rcd = select( maxfd+1, &catch_fd_set, NULL, NULL, (struct timeval *)0 ) ;
        if ( rcd < 0 ) {
            printf("SERVER::Server 5 \n");
            exit(1);
        }

        if ( FD_ISSET( server_sockfd, &catch_fd_set ) ) {
            socklen = sizeof( cli_sockaddr ) ;
            new_cli_fd = accept( server_sockfd, ( struct sockaddr * )&( cli_sockaddr ), &socklen ) ;
            printf(" SERVER::open communication with  Client %s on socket %d\n", cli_sockaddr.sun_path,new_cli_fd);    
    
            for (ci=1;ci<=2;ci++){
                if(watch_fd_list[ci] != -1) continue;
                else{    
                    watch_fd_list[ci] = new_cli_fd;
                    break;
                }    
            }    
            FD_SET(new_cli_fd , &watchset ) ;
            if ( maxfd < new_cli_fd ) {
                maxfd = new_cli_fd ;
            }
            
            for ( ci=0;ci<=1;ci++){
                if(cli_info_t[ci].cli_sock_fd == -1) {
                    cli_info_t[ci].module_id=cli_sockaddr.sun_path[0];
                    cli_info_t[ci].cli_sock_fd=new_cli_fd;
                    break;
                }        
            }
               


----------------------------------

#include  <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <sys/un.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>

int main(){
    
    int client_sockfd;
    int len;
    struct sockaddr_un server_sockaddr,cli_sockaddr;
    int result;
    char dst_module_id='B';
    char ch='1';
    char src_module_id;
    
    
    client_sockfd= socket(AF_UNIX,SOCK_STREAM,0);
    
//    memset( &cli_sockaddr, 0, sizeof( cli_sockaddr) ) ;
    cli_sockaddr.sun_family = AF_UNIX ;
    strcpy( cli_sockaddr.sun_path, "A" ) ;
    bind( client_sockfd, ( struct sockaddr * )&cli_sockaddr, sizeof( cli_sockaddr ) ) ;

    server_sockaddr.sun_family=AF_UNIX;
//    server_sockaddr.sin_addr.s_addr=htonl(INADDR_ANY);
//    server_sockaddr.sin_port=htons(9734);
    strcpy( server_sockaddr.sun_path, "server_socket" ) ;
    len=sizeof(server_sockaddr);
    
    result = connect(client_sockfd,( struct sockaddr * )&server_sockaddr,len);
    if (result <0){
        printf("ClientA::error on connecting \n");    
//        exit(1);
    }
    
    printf("ClientA::succeed in connecting with server\n");
    sleep(10);
    write(client_sockfd,&dst_module_id,1);
    write(client_sockfd,&ch,1);
    read (client_sockfd,&src_module_id,1);
    read (client_sockfd,&ch,1);
    printf("ClientA::char from  Client %c =%c\n", src_module_id,ch);    
    close (client_sockfd);
    
}



0 0
原创粉丝点击