Qt之进程间通信(本地套接字)

Posted TechNomad

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Qt之进程间通信(本地套接字)相关的知识,希望对你有一定的参考价值。

一、QLocalServer

QLocalServer是Qt框架中的一个类,用于创建本地套接字服务器。它可以用于在同一台计算机上的进程之间进行通信,而无需通过网络。

下面是使用QLocalServer的源码:

MainWindow::MainWindow(QWidget *parent)
    : QWidget(parent)

    //创建QLocalServer对象
    m_local_server = new QLocalServer(this);
    //连接QLocalServer的newConnection()信号到一个槽函数,以处理新连接
    connect(m_local_server, &QLocalServer::newConnection, this, &MainWindow::on_new_connected);
    //设置服务器名字
    m_local_server->listen("monitor_server");


//在槽函数中,接受新的连接并处理数据
void MainWindow::on_new_connected()

    QLocalSocket *local_client = m_local_server->nextPendingConnection();
    connect(local_client, &QLocalSocket::readyRead, this, &MainWindow::on_socket_readyRead);


void MainWindow::on_socket_readyRead()

    QLocalSocket *clientSocket = nullptr;
    clientSocket = qobject_cast<QLocalSocket*>(sender());
    if (clientSocket) 
        // 处理接收到的数据
        QByteArray data = clientSocket->readAll();
        qDebug() << data;
    

二、QLocalSocket

QLocalSocket是Qt框架中的一个类,用于与QLocalServer建立本地套接字连接,并进行通信。

下面是使用QLocalSocket的源码:

MainWindow::MainWindow(QWidget *parent)
    : QWidget(parent)

    //创建QLocalSocket对象
    m_local_client = new QLocalSocket(this);
    connect(m_local_client, &QLocalSocket::connected, this, &MainWindow::on_socket_connected);
    connect(m_local_client, &QLocalSocket::disconnected, this, &MainWindow::on_socket_disconnected);
    //连接到QLocalServer(monitor_server是server的名称)
    m_local_client->connectToServer("monitor_server");


void MainWindow::on_socket_connected()

    qDebug() << "local server socket connected";
    // 连接成功,可以发送数据
    m_local_client->write(QString("Hello Server").toLatin1());
    m_local_client->flush();


void MainWindow::on_socket_disconnected()

    qDebug() << "local server socket disconnected";

 

linux高级编程之socket进程通信

Socket套接字不仅可以用于网络通信和局域网通信还可以用于本地的进程通信。
创建套接字时使用本地协议PF_UNIX,套接字分为流失套接字,数据报套接字。
Socket本地进程通信较其他的进程间通信方式(管道,system Ⅴ,BSD)使用更加方便、效率。
本地地址结构:
Struct  sockaddr_un   //<sys/un.h>
{
   Sa_family_t sun_family;
  Char sun_path[108]; //套接字的文件路径
}
填充地址结构:
1、定义:struct sockaddr_un myaddr;
2、置零:bzero(&myaddr,sizeof(myaddr));
3、配置:
myadd.sun_family=AF_UNIX;
strcpy(myadd.sun_path,”mysock”);//名字可以随意命名
一、UNIX域流式套接字服务器端的创建过程:
Socket(AF_UNIX,SOCK_STREAM,0)
Bind(,本地地址,)
Listen(,)
Accept(,,)
Recv()/send()
UNIX域流式套接字客户端的创建过程:
Socket(AF_UNIX,SOCK_STREAM,0)
Bind(,本地地址,)//可选
Connect(,,)
Recv()/send()
 ↓
…….
以下为创建的服务器端和客户端实现简单的进程间的通信:
服务器端:
      Server.c
#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<errno.h>
#include<string.h>
#include<sys/un.h>
 
 
 
int main(int argc, const char *argv[])
{
     int n,sockfd,length,connfd;
     struct sockaddr_un  myaddr,clientaddr;
     char buf[128];
// 创建套接字
     sockfd=socket(PF_UNIX,SOCK_STREAM,0);
     if(sockfd<0)
     {
       perror("socket");
       return -1;
     }
//置零
     bzero(&myaddr,sizeof(myaddr));
//配置套接字
     myaddr.sun_family=AF_UNIX;
     strcpy(myaddr.sun_path,"mysocket");
//绑定套接字
     if((bind(sockfd,(struct sockaddr*)&myaddr,sizeof(myaddr)))<0)
         {
           perror("bind");
           return -1;
         }
//监听套接字
     if((listen(sockfd,10))<0)
     {
         perror("listen");
         return -1;
 
     }
     length=sizeof(clientaddr);
     while(1)
     {
         connfd=accept(sockfd,(struct sockaddr*)&clientaddr,&length);
          if(connfd<0)
          {
            perror("accept");
            return -1;
          }
          while((n=recv(connfd,buf,127,0))>0)
          {
              buf[n]=‘\\0‘;
 
                 
          printf("receive:%s\\n",buf);
          send(connfd,buf,strlen(buf),0);
          }
         
            if(strncmp(buf,"quit",4)==0)
            {
               break ;
            }
        close(connfd);    //关闭套接字
    }
    
    return 0;
}
客户端:
Client.c
#include<stdio.h>
#include<stdlib.h>
#include<errno.h>
#include<sys/types.h>
#include<sys/un.h>
#include<sys/socket.h>
#include<string.h>
 
 
int main(int argc, const char *argv[])
{
 int n,sockfd,length;
char buf[128];
 struct sockaddr_un myaddr;
//创建套接字
   sockfd=socket(AF_UNIX,SOCK_STREAM,0);
 if(sockfd<0)
{
perror("socket");
return -1;
 }
//置零
bzero(&myaddr,sizeof(myaddr));
//配置套接字
myaddr.sun_family=AF_UNIX;
 strcpy(myaddr.sun_path,"mysocket");
//链接客户端
if (connect(sockfd, (struct sockaddr *)&myaddr, sizeof(myaddr)) < 0)
 {
perror("connect");
exit(-1);
}
 do
{
fgets(buf,128,stdin);
length=strlen(buf)+1;
if (send(sockfd, buf, length, 0) < 0)
{
perror("send");
exit(-1);
}
memset(buf, 0, sizeof(buf));
length = recv(sockfd, buf, 128, 0);
if (length <= 0)
 {
break;
}
buf[length] = ‘\\0‘;
printf("receive:%s\\n", buf);
}
while(strncmp(buf,"quit",4)!=0);   //当输入quit时退出客户端
close(sockfd);//关闭套接字
 return 0;
}
编译执行后,效果如图所示:
技术分享

 

 
技术分享
二、UNIX域用户数据报套接字服务器端的创建过程:
UNIX域用户数据报套接字服务器的创建过程:、
Socket(AF_UNIX,SOCK_STREAM,0)
Bind(,本地地址,)//可选
                 Recvfrom()           ←
                         ↓                     ↑
Sendto()          ↑
↓      →        →  ↑
UNIX域用户数据报套接字客户端的创建过程:
Socket(AF_UNIX,SOCK_STREAM,0)
Bind(,本地地址,)//可选
Recvfrom()/sendto()
 ↓
……
客户端:
Server.c
#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<errno.h>
#include<string.h>
#include<sys/un.h>
 
 
 
int main(int argc, const char *argv[])
{
     int n,sockfd;
     socklen_t slength;
     struct sockaddr_un  myaddr,clientaddr;
     char buf[128];
//创建套接字
     sockfd=socket(PF_UNIX,SOCK_DGRAM,0);
     if(sockfd<0)
     {
       perror("socket");
       return -1;
     }
//置零
     bzero(&myaddr,sizeof(myaddr));
  //配置套接字    
myaddr.sun_family=AF_UNIX;
     strcpy(myaddr.sun_path,"mysocket");
//绑定套接字
     if((bind(sockfd,(struct sockaddr*)&myaddr,sizeof(myaddr)))<0)
         {
           perror("bind");
           return -1;
         }
    
     slength=sizeof(clientaddr);
     while(1)
     {
         if((n=recvfrom(sockfd,buf,127,0,(struct sockaddr*)&clientaddr,&slength))>0)
         
          {
           buf[n]=‘\\0‘;
          printf("receive:%s\\n",buf);
          sendto(sockfd,buf,strlen(buf),0,(struct sockaddr*)&clientaddr,sizeof(clientaddr));
          }
       if(strncmp(buf,"quit",4)==0)
            {
             break ;
            }     
    }
     close(sockfd);
    return 0;
}
客户端:
Client.c
#include<stdio.h>
#include<stdlib.h>
#include<errno.h>
#include<sys/types.h>
#include<sys/un.h>
#include<sys/socket.h>
#include<string.h>
 
 
int main(int argc, const char *argv[])
{
    int n,m,sockfd,length;
    socklen_t slength;
    char buf[128];
struct sockaddr_un temp,myaddr;
//创建套接字
    sockfd=socket(AF_UNIX,SOCK_DGRAM,0);
    if(sockfd<0)
    {
      perror("socket");
      return -1;
   
    }
    //置零服务器套接字内存空间
   memset(&temp, 0, sizeof(temp));
//配置套接字
temp.sun_family = AF_UNIX;
strcpy(temp.sun_path, "mysocket");
//置零客户端套接字内存空间
    bzero(&myaddr,sizeof(myaddr));
    myaddr.sun_family=AF_UNIX;
strcpy(myaddr.sun_path,"mysock");
//绑定
    if((bind(sockfd,(struct sockaddr*)&myaddr,sizeof(myaddr)))<0)
    {
      perror("bind");
      return -1;
    }
    slength=sizeof(temp);
 
    do
    {
        fgets(buf,128,stdin);
        buf[strlen(buf)-1]=0;
        if (sendto(sockfd, buf, strlen(buf)+1, 0,(struct sockaddr*)&temp,sizeof(temp)) < 0)
        {
                     perror("send");
                     exit(-1);
}
memset(buf, 0, sizeof(buf));
       
length = recvfrom(sockfd,buf,128,0,(struct sockaddr*)&temp,&slength);
              if (length  <= 0)
        {
                     break;
              }
              buf[length] = ‘\\0‘;
              printf("receive:%s\\n", buf);
   
    }while(strncmp(buf,"quit",4)!=0);
    close(sockfd);
    return 0;
}
执行后:
技术分享

 

技术分享
总结:
看似unix的流式套接字和用户数据报套接字的区别不大,但是在实际操作的过程中,却有着非常大的区别,在本文中,unix用户数据报套接字在客户端中再次绑定了和设置了一个套接字,这样做的目的在于如果不创建这个套接字,服务器发送给客户端时由于是UDP协议没有确定的地址,导致服务器无法找到接受的那个客户端以至于无法发送信息过去。

以上是关于Qt之进程间通信(本地套接字)的主要内容,如果未能解决你的问题,请参考以下文章

Qt基础之二十:进程间通信

Qt基础之二十:进程间通信

Qt基础之二十一:QtRO(Qt Remote Object)实现进程间通信

Qt基础之二十一:QtRO(Qt Remote Object)实现进程间通信

操作系统之 进程间通信的方式都有哪些

进程间通信(IPC)之共享内存