Linux 上实现双向进程间通信管道

技术要点:

1. 使用命名管道,实现进程间管道的访问

2. 管道操作使用长连接

3. 使用信号量共享key实现进程锁

      Linux管道是单向的,要实现进程间双向通讯,需要使用两个管道:一个负责Client发送数据到server,另一个负责server返回数据到Client;对于一个client访问server的情况(相当于一个进程访问server),Client发送与接收数据不会有问题;对于多个Clinet访问server的情况(相当于多个进程访问server),此时,各个client发送数据没有问题,接收数据错乱,原因为没有保证每个进程发送与接收的同步,解决方法,使用进程锁

见代码

//server
#include <QCoreApplication>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <iostream>
#include <unistd.h>
#include <pthread.h>
#include <string>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
using namespace std;

volatile int sem_id;
struct sembuf sem_op;

union semun
{
        int              val;    /* Value for SETVAL */
        struct semid_ds *buf;    /* Buffer for IPC_STAT, IPC_SET */
        unsigned short  *array;  /* Array for GETALL, SETALL */
        struct seminfo  *__buf;  /* Buffer for IPC_INFO
                                    (Linux-specific) */
};

void sem_lock(int sem_id, struct sembuf *sem_op)
{
    // P operate
      sem_op->sem_num = 0;
      sem_op->sem_op = -1;
      sem_op->sem_flg = 0;
      semop(sem_id,sem_op,1);  //P operate add - 1 per time
}

void sem_unlock(int sem_id, struct sembuf *sem_op)
{
    // V operate
    sem_op->sem_num = 0;
    sem_op->sem_op = 1;
    sem_op->sem_flg = 0;
    semop(sem_id,sem_op,1);  //V operate add + 1 per time
}


#define PIPE_NAME_ONE "/tmp/snbc1_fifo"
#define PIPE_NAME_TWO "/tmp/snbc2_fifo"

pthread_mutex_t g_mutex;
pthread_mutex_t g_threadMutex;
volatile int nRetPipe1 = 0;
volatile int nRetPipe2 = 0;

void *ReadAndWriteTread(void* arg);
void *WritePipe(void* data);

void *ConnectThread(void* arg)
{
           cout << "[%s]线程开始启动"<< __FUNCTION__ << endl;
           if(-1 == access(PIPE_NAME_ONE,F_OK) )
            {
                remove(PIPE_NAME_ONE);
                nRetPipe1= mkfifo(PIPE_NAME_ONE,O_CREAT|O_RDWR|0666);
                if(0 > nRetPipe1)
                {
                    cout << "线程创建PIPE1 fail" << endl;
                }
           }

           if(-1 == access(PIPE_NAME_TWO,F_OK) )
            {
                remove(PIPE_NAME_TWO);
                int nPipe2= mkfifo(PIPE_NAME_TWO,O_CREAT|O_RDWR|0666);
                if(0 > nPipe2)
                {
                     cout << "线程创建PIPE fail" << endl;
                }
           }

            cout << "线程开始打开PIPE1" << endl;
            nRetPipe1 = open(PIPE_NAME_ONE,O_RDONLY);
            nRetPipe2 = open(PIPE_NAME_TWO,O_WRONLY | O_TRUNC);   
            if(nRetPipe1 > 0 && nRetPipe2 > 0)
            {
                cout << "线程开始打开PIPE1成功" << endl;
                pthread_t pThread = 0;
                void *res;
                int nLRet = 0;
                nLRet = pthread_create(&pThread, NULL,ReadAndWriteTread, (void*)&nRetPipe1);
                if(0 != nLRet)
                {
                    cout << "创建线程InstanceThread失败!" << endl;
                }
                nLRet = pthread_join(pThread,&res);
                if(0 != nLRet)
                {
                    cout << "创建线程InstanceThread失败!" <<  endl;
                }
                cout << "线程执行完成退出 " << endl;
             }
            else
            {
                cout << "打开PIPE1失败!" <<endl;
                close(nRetPipe1);
                close(nRetPipe2);
            }

         cout << "线程正常退出" << endl;
        return 0;
}

void *ReadAndWriteTread(void* arg)
{
    int hTmpPipe = *((int*) arg);
    while(1)
    {
        unsigned char  ucRequest[1024] = {0};
        unsigned char  ucReply[1024]   = {0};
        long dwRequestLen    = 0;
        long dwReplyLen      = 0;
        if(hTmpPipe < 0)
        {
            hTmpPipe = open(PIPE_NAME_ONE,O_RDONLY);
        }
        if(hTmpPipe > 0)
        {
            dwRequestLen = read(hTmpPipe, ucRequest, sizeof(ucReply));
            if(-1 == dwRequestLen || 0 == dwRequestLen )
            {
                cout << "读取数据失败或数据为空 "<<endl;
            }
            else
            {
               cout << "读取管道一的数据dwRequestLen = %d"<< dwRequestLen<< endl;
               cout << "读取管道一的数据ucRequest =%s" << ucRequest <<endl;
               pthread_mutex_lock(&g_mutex);
               usleep(100);
               pthread_mutex_unlock(&g_mutex);

               WritePipe((void*)ucRequest);
            }
        }
        else
         {
               close(hTmpPipe);
        }
   }
}

void *WritePipe(void* data)
{
    cout <<"WritePipeThread 线程开始执行" <<endl;
    cout << data <<endl;

       if(nRetPipe2 < 0)
       {
              nRetPipe2 = open(PIPE_NAME_TWO,O_WRONLY | O_TRUNC);
       }
        if(nRetPipe2 > 0)
        {
            cout << "打开PIPE2成功" <<endl;
            long dwRequestLen = 1024;
            long dwWritten = 0;
            dwWritten = write(nRetPipe2, data, dwRequestLen );
            if(-1 == dwWritten || dwRequestLen != dwWritten)
            {
                 cout << " 写入数据出错或无数据写入!!!!!" << endl;
            }
            else
            {
                cout << "写入PIPE2成功" << endl;
            }
        }
        else
        {
            cout << "打开PIPE2失败" << endl;
            close(nRetPipe2);
        }

    cout << "执行完成"<<endl;
    return 0;
}

bool initSemIDAndSemVal(union semun sem_val)
{
    int rc = 0;
    key_t sem_key;
    sem_key = ftok("/dev/null",1);
    if(-1 == sem_key)
    {
        cout << "Create sem_key fail" <<endl;
        return false;
    }
    sem_id = semget(sem_key,1,IPC_CREAT | 0600);
    if(-1 == sem_id)
    {
        cout << "Create sem_id fail" <<endl;
        return false;
    }

   sem_val.val = 1;
   rc = semctl(sem_id,0,SETVAL,sem_val);
   if(-1 == rc)
   {
       cout << "Create semctl fail" <<endl;
       return false;
   }
   return true;
}

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    pthread_mutex_init(&g_mutex,0);
    pthread_mutex_init(&g_threadMutex,0);

    struct sembuf sem_op;
    union semun sem_val;

    if(initSemIDAndSemVal(sem_val))
    {
        cout << "initSemIDAndSemVal success" <<endl;
    }
    else
    {
        cout << "initSemIDAndSemVal fail" <<endl;
    }

    pthread_t hConnectThread = NULL;
    int nRet = 0;
    nRet = pthread_create(&hConnectThread,NULL,ConnectThread,NULL);
    if(0 != nRet)
    {
        cout << "Create ConnectThread fail" << endl;
    }
    pthread_mutex_destroy(&g_mutex);
    pthread_mutex_destroy(&g_threadMutex);
    return a.exec();
}
//Client1
#include <QCoreApplication>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <iostream>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>

using namespace std;

#define PIPE_NAME_ONE "/tmp/snbc1_fifo"
#define PIPE_NAME_TWO "/tmp/snbc2_fifo"

#define TestCount  10000

union semun {
            int              val;    /* Value for SETVAL */
            struct semid_ds *buf;    /* Buffer for IPC_STAT, IPC_SET */
            unsigned short  *array;  /* Array for GETALL, SETALL */
            struct seminfo  *__buf;  /* Buffer for IPC_INFO
                                        (Linux-specific) */
        };

volatile int  sem_id;

int get_sem_val(int sid, int semnum)
{
    return (semctl(sid,semnum,GETVAL,0));
}

void sem_lock(int sem_id, struct sembuf *sem_op)
{
    // P operate
      sem_op->sem_num = 0;
      sem_op->sem_op = -1;
      sem_op->sem_flg = 0;
      semop(sem_id,sem_op,1);  //V operate add + 1 per time
}

void sem_unlock(int sem_id, struct sembuf *sem_op)
{
    // V operate
    sem_op->sem_num = 0;
    sem_op->sem_op = 1;
    sem_op->sem_flg = 0;
    semop(sem_id,sem_op,1);  //V operate add + 1 per time
}

bool initSemID()
{
    int rc = 0;
    key_t sem_key;
    sem_key = ftok("/dev/null",1);
    if(-1 == sem_key)
    {
        cout << "Create sem_key fail" <<endl;\
        return false;
    }
    sem_id = semget(sem_key,1,IPC_CREAT | 0600);
    if(-1 == sem_id)
    {
        cout << "Create sem_id fail" <<endl;
        return false;
    }
    return true;
}

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    struct sembuf sem_op;
    union semun sem_val;
    if(initSemID())
    {
        cout << "initSendID success" << endl;
    }
    else
    {
        cout << "initSendID fail" <<endl;
    }

    int fd1=-1, fd2 = -1, fd3= -1 ;
    char buf[1024] = "";
    char bufSmall[20]="";
    char bufWrite[1024] = "";
    cout << "Clent Open Start"<< endl;

    char tempPipeName2[64] ={0};

    if((fd1 = open(PIPE_NAME_ONE,O_WRONLY | O_TRUNC) )< 0)
    {
        cout << "Client open PIPE_NAME_ONE failed " << endl;
        return -1;
    }

    if((fd2 = open(PIPE_NAME_TWO,O_RDONLY)) < 0)
    {
        cout << "Open PIPE_NAME_TWO failed" << endl;
    }

    for(int i = 0; i < TestCount; i++)
    {
        cout << sem_id <<endl;
        sem_lock(sem_id, &sem_op);
        cout << "Client1 start getLock" <<endl;
        cout << "线程创建PIPE2完成" << endl;
        if(fd1 < 0)
        {
              fd1 = open(PIPE_NAME_ONE,O_WRONLY | O_TRUNC) ;
        }

        sprintf(bufWrite,"Hello Server, I am client1 Data is %d", i);
        cout <<"Send: "<<bufWrite << endl;
        if((write(fd1,bufWrite ,strlen(bufWrite))) < 0)
        {
            cout << "write buf failed" <<endl;
            return -1;
        }
        if(fd2 < 0)
        {
            fd2 = open(PIPE_NAME_TWO,O_RDONLY);
        }
        int nRet = 0;
        nRet = read(fd2,buf,1024);
        cout << "Receive: "<<buf <<endl;
        sem_unlock(sem_id,&sem_op);
        cout << "Client1 unLock" <<endl;
    }

    close(fd1);
    close(fd2);
    return a.exec();
}
//Client2
#include <QCoreApplication>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <iostream>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <fcntl.h>
#include <sys/stat.h>

using namespace std;

#define PIPE_NAME_ONE "/tmp/snbc1_fifo"
#define PIPE_NAME_TWO "/tmp/snbc2_fifo"

#define TestCount   10000

union semun
{
        int              val;    /* Value for SETVAL */
        struct semid_ds *buf;    /* Buffer for IPC_STAT, IPC_SET */
        unsigned short  *array;  /* Array for GETALL, SETALL */
        struct seminfo  *__buf;  /* Buffer for IPC_INFO
                                    (Linux-specific) */
};

volatile int sem_id;

void sem_lock(int sem_id, struct sembuf *sem_op)
{
    // P operate
      sem_op->sem_num = 0;
      sem_op->sem_op = -1;
      sem_op->sem_flg = 0;
      semop(sem_id,sem_op,1);  //P operate add - 1 per time
}

void sem_unlock(int sem_id, struct sembuf *sem_op)
{
    // V operate
    sem_op->sem_num = 0;
    sem_op->sem_op = 1;
    sem_op->sem_flg = 0;
    semop(sem_id,sem_op,1);  //V operate add + 1 per time
}

bool initSemID()
{
    cout << "read data" << endl;
    int rc = 0;
    key_t sem_key;
    sem_key = ftok("/dev/null",1);
    if(-1 == sem_key)
    {
        cout << "Create sem_key fail" <<endl;
        return false;
    }
    sem_id = semget(sem_key,1,IPC_CREAT | 0600);
    if(-1 == sem_id)
    {
        cout << "Create sem_id fail" <<endl;
        return false;
    }
    return true;
}

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    struct sembuf sem_op;
    union semun sem_val;

    if(initSemID())
    {
        cout << "initSendID success" << endl;
    }
    else
    {
        cout << "initSendID fail" <<endl;
    }

    int fd1 = -1, fd2 = -1;
    char buf[1024] = "";
    char bufSmall[20]="";
    char bufWrite[1024] = "";

    if((fd1 = open(PIPE_NAME_ONE,O_WRONLY | O_TRUNC) )< 0)
    {
        cout << "Client open PIPE_NAME_ONE failed " << endl;
        return -1;
    }

    if((fd2 = open(PIPE_NAME_TWO,O_RDONLY)) < 0)
    {
        cout << "Open PIPE_NAME_TWO failed" << endl;
        return -1;
    }

    for(int i = 0; i < TestCount; i++)
    {
        cout << sem_id <<endl;
        sem_lock(sem_id,&sem_op);
        cout << "Client2 start Lock" <<endl;
        sprintf(bufWrite,"Hello Server, I am client2 Data is %d",i);

        if(fd1 < 0)
        {
           fd1 = open(PIPE_NAME_ONE,O_WRONLY | O_TRUNC) ;
        }

        cout <<"Send: "<< bufWrite <<endl;
        if((write(fd1, bufWrite,strlen(bufWrite))) < 0)
        {
            cout << "write buf failed" <<endl;
            return -1;
        } 

        if(fd2 < 0)
        {
            fd2 = open(PIPE_NAME_TWO,O_RDONLY);
        }

        int nRet = 0;
        nRet = read(fd2,buf,1024);
        cout <<"Receive: "<<buf <<endl;
        sem_unlock(sem_id,&sem_op);
        cout << "Client2 unLock" <<endl;
    }

    close(fd1);
    close(fd2);
    return a.exec();
}

 

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值