查看: 6461|回复: 0
打印 上一主题 下一主题

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

[复制链接]
跳转到指定楼层
1#
发表于 2007-9-17 20:20:50 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
台州网址导航
套接口(Socket)为目前 Linux 上最为广泛使用的一种的进程间通信机制。但是它不能直接用来多进程之间的相互实时通信。本文提出一个基于 Socket 的多进程之间通信的实现方法,并给出样本程序的实现和说明。
套接口(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。


QUOTE:
#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监视集合中。


QUOTE:
        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。


QUOTE:
                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中


QUOTE:
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.module_id == dst_module_id)
                                        dst_fd=        cli_info_t.cli_sock_fd;        
                                 if(cli_info_t.cli_sock_fd==watch_fd_list[ ci ])
                                src_module_id=        cli_info_t.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';既可。


QUOTE:
#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] 4303
ClientA::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 5
ClientB::succeed in connecting with server
SERVER::char=1 to  Client B on socket5
ClientB::char from  Client A =1
SERVER::char=2 to  Client A on socket4
ClientA::char from  Client B =2

程序清单下载:server.c:http://www-128.ibm.com/developer ... socket-ipc/server.c
clientA.c:http://www-128.ibm.com/developer ... ocket-ipc/clientA.c
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 转播转播 分享分享 分享淘帖
台州维博网络(www.tzweb.com)专门运用PHP+MYSQL/ASP.NET+MSSQL技术开发网站门户平台系统等。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

网站推广
关于我们
  • 台州朗动科技(Tzweb.com)拥有多年开发网站平台系统门户手机客户端等业务的成功经验。主要从事:政企网站,系统平台,微信公众号,各类小程序,手机APP客户端,浙里办微应用,浙政钉微应用、主机域名、虚拟空间、后期维护等服务,满足不同企业公司的需求,是台州地区领先的网络技术服务商!

Hi,扫描关注我

Copyright © 2005-2026 站长论坛 All rights reserved

Powered by 站长论坛 with TZWEB Update Techonolgy Support

快速回复 返回顶部 返回列表