树莓派和上位机使用TCP通信

系统介绍

下位机: 树莓派作为下位机,IP地址为192.168.199.206,作为tcp的客户端(c实现),通信端口号为8888,

上位机: Ubuntu(虚拟机)作为上位机,作为tcp的服务端(Qt实现),Qt版本为5.12,IP地址为192.168.199.149,通信端口为8888

注意:

  • 该系统为单向通信,只能由客户端发送到服务端,发信数据类型为字符串或图像数据
  • 此项目需要在Qt设计师中添加一个Label控件,用于显示文本和图像

字符串通信

树莓派具体实现代码:

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <arpa/inet.h>

int main(int argc,char *argv[])
{
    int sockfd,numbytes;
    char buf[BUFSIZ];
    struct sockaddr_in their_addr;
    while((sockfd = socket(AF_INET,SOCK_STREAM,0)) == -1);
    printf("We get the sockfd~\n");
    their_addr.sin_family = AF_INET;
    their_addr.sin_port = htons(8888);
    their_addr.sin_addr.s_addr=inet_addr("192.168.199.149");
    bzero(&(their_addr.sin_zero), 8);			//清空数据中前8位
    
    while(connect(sockfd,(struct sockaddr*)&their_addr,sizeof(struct sockaddr)) == -1);
    printf("Get the Server~Cheers!\n");
    buf[numbytes]='\0';  
    while(1)
    {
        printf("Entersome thing:");
        scanf("%s",buf);
        numbytes = send(sockfd, buf, strlen(buf), 0);
    }
    close(sockfd);
    return 0;
}

Qt具体实现代码:

Qt如果需要使用socket通信,需要在pro文件中添加以下语句:

QT       += network

头文件

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QTcpServer>
#include <QTcpSocket>
#include <QDebug>

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

private:
    Ui::MainWindow *ui;

    QTcpServer *tcpServer = new QTcpServer();   //Tcp服务端对象
    QTcpSocket *tcpSocket = new QTcpSocket();   //Tcp连接socket

    void initWindow();                          //初始化窗体
    void setNetwork();                          //设置网络信息

private slots:
    void serverNewConnect();                    //新的网络连接响应
    void serverReadData();                      //服务端读取数据
    void serverDisconnection();                 //服务端断开连接
};

#endif // MAINWINDOW_H

实现文件

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    initWindow();
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::initWindow()
{
    //初始化窗体
    connect(tcpServer, SIGNAL(newConnection()), this, SLOT(serverNewConnect()));
    setNetwork();
}

void MainWindow::setNetwork()
{
    //开启网络服务
    int port = 8888;                //Tcp端口号为8888
    if(!tcpServer->listen(QHostAddress::Any, port))
    {
        qDebug() << "服务器端监听失败!!!";
        return;
    }else
    {
        qDebug() << "服务器端监听成功!!!";
    }
}

void MainWindow::serverNewConnect()
{
    //服务端新连接槽函数
    tcpSocket = tcpServer->nextPendingConnection();
    if(!tcpSocket)
    {
        qDebug() << "未能成功获取客户端连接!!!";
    }else
    {
        qDebug() << "成功建立连接!!!";
        connect(tcpSocket, SIGNAL(readyRead()), this, SLOT(serverReadData()));
        connect(tcpSocket, SIGNAL(disconnected()), this, SLOT(serverDisconnection()));
    }
}

void MainWindow::serverReadData()
{
    //服务器接收数据函数
    ui->label->setText((QString)tcpSocket->readAll());
}

void MainWindow::serverDisconnection()
{
    //服务端断开连接
    qDebug() << "与客户端断开连接!!!";
    return;
}

程序执行

  • 打开上位机中Qt程序,使得服务器监测客户端的连接
  • 执行客户端,可以看到服务端输出连接成功提示语句
  • 在客户端中输入字符,以回车结束,服务端即可打印出相应字符

程序执行效果如下:
在这里插入图片描述

图像发送

树莓派具体实现代码:

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#define MAXSIZE 1024*1024

int main(int argc,char *argv[])
{
    int sockfd,len;
    char buffer[MAXSIZE];
    struct sockaddr_in their_addr;
    FILE *fq;

    while((sockfd = socket(AF_INET,SOCK_STREAM,0)) == -1);

    printf("We get the sockfd~\n");
    their_addr.sin_family = AF_INET;
    their_addr.sin_port = htons(8888);
    their_addr.sin_addr.s_addr=inet_addr("192.168.199.149");
    bzero(&(their_addr.sin_zero), 8);
    
    while(connect(sockfd,(struct sockaddr*)&their_addr,sizeof(struct sockaddr)) == -1);
      
    //需要确保当前目录下有相应图像文件
    if((fq = fopen("./luo.jpg","rb") ) == NULL ){
        printf("File open.\n");
        close(sockfd);
        exit(1);
    }

    while(!feof(fq)){
        len = fread(buffer, 1, sizeof(buffer), fq);
        printf("len is : %d\n", len);
        if(len != write(sockfd, buffer, len)){
            break;
        }
    }
    
    close(sockfd);
    fclose(fq);
    return 0;
}

Qt具体实现代码:

Qt如果需要使用socket通信,需要在pro文件中添加以下语句:

QT       += network

头文件

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QTcpServer>
#include <QTcpSocket>
#include <QBuffer>
#include <QDebug>

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

private:
    Ui::MainWindow *ui;

    QByteArray array;                           //图像文件
    QTcpServer *tcpServer = new QTcpServer();   //Tcp服务端对象
    QTcpSocket *tcpSocket = new QTcpSocket();   //Tcp连接socket

    void initWindow();                          //初始化窗体
    void setNetwork();                          //设置网络信息

private slots:
    void serverNewConnect();                    //新的网络连接响应
    void serverReadData();                      //服务端读取数据
    void serverDisconnection();                 //服务端断开连接
};

#endif // MAINWINDOW_H

实现文件

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    initWindow();
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::initWindow()
{
    //初始化窗体
    connect(tcpServer, SIGNAL(newConnection()), this, SLOT(serverNewConnect()));
    setNetwork();
}

void MainWindow::setNetwork()
{
    //开启网络服务
    int port = 8888;                //Tcp端口号为8888
    if(!tcpServer->listen(QHostAddress::Any, port))
    {
        qDebug() << "服务器端监听失败!!!";
        return;
    }else
    {
        qDebug() << "服务器端监听成功!!!";
    }
}

void MainWindow::serverNewConnect()
{
    //服务端新连接槽函数
    tcpSocket = tcpServer->nextPendingConnection();
    if(!tcpSocket)
    {
        qDebug() << "未能成功获取客户端连接!!!";
    }else
    {
        qDebug() << "成功建立连接!!!";
        connect(tcpSocket, SIGNAL(readyRead()), this, SLOT(serverReadData()));
        connect(tcpSocket, SIGNAL(disconnected()), this, SLOT(serverDisconnection()));
    }
}

void MainWindow::serverReadData()
{
    //服务器接收数据函数
    array.append((QByteArray)tcpSocket->readAll());
}

void MainWindow::serverDisconnection()
{
    //服务端断开连接
    qDebug() << "与客户端断开连接!!!";

    QBuffer buffer(&array);
    buffer.open(QIODevice::ReadOnly);
    QPixmap picture;
    picture.loadFromData(array, "jpg");
    ui->label->setPixmap(picture);

    return;
}

程序执行

  • 打开上位机中Qt程序,使得服务器监测客户端的连接
  • 执行客户端,可以看到服务端输出连接成功提示语句(首先需要确保在客户端路径下有相应图像文件)
  • 在客户端会输出图像文件尺寸,在服务端会将图像展示到label控件中

执行效果如下:

在这里插入图片描述