目录
一、基础知识复习
这部分内容前面讲的比较详细,现在就是简单复习一下。
两台主机之间通信要经过封包他有一堆包头
TCP、UDP都是基于套接字,C写我感觉已经挺简单了,老师说C++更简单,我们往下学学看。
二、UDP
网络编程这块要在工程文件中加上network
服务器是被动套接字,客户端是主动套接字
客户端:
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QTextEdit>
#include <QLineEdit>
#include <QPushButton>
#include <QUdpSocket>
#include <QHostAddress>
class Widget : public QWidget
{
Q_OBJECT
public slots:
void senddata()
{
udpsock->writeDatagram(le->text().toStdString().c_str(), QHostAddress("192.168.3.27"), 8888);
}
void recvdata()
{
QByteArray datagram;
datagram.resize(udpsock->pendingDatagramSize());
QHostAddress sender;
quint16 senderPort;
udpsock->readDatagram(datagram.data(), datagram.size(),
&sender, &senderPort);
te->append(datagram);
}
public:
Widget(QWidget *parent = 0);
~Widget();
private:
QTextEdit *te;
QLineEdit *le;
QPushButton *pb;
QUdpSocket *udpsock;
};
#endif // WIDGET_H
#include "widget.h"
#include <QVBoxLayout>
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
te = new QTextEdit;
le = new QLineEdit;
pb = new QPushButton("send");
QVBoxLayout *vbox = new QVBoxLayout;
vbox->addWidget(te);
vbox->addWidget(le);
vbox->addWidget(pb);
setLayout(vbox);
udpsock = new QUdpSocket;
connect(pb, SIGNAL(clicked(bool)), this, SLOT(senddata()));
connect(udpsock, SIGNAL(readyRead()), this, SLOT(recvdata()));
}
Widget::~Widget()
{
}
服务器:
#ifndef UDPSERVER_H
#define UDPSERVER_H
#include <QObject>
#include <QUdpSocket>
#include <QDebug>
class udpServer : public QObject
{
Q_OBJECT
public:
explicit udpServer(QObject *parent = 0);
void init()
{
udpSocket = new QUdpSocket(this);
udpSocket->bind(QHostAddress::AnyIPv4, 8888);
connect(udpSocket, SIGNAL(readyRead()),
this, SLOT(readPendingDatagrams()));
qDebug()<<"init....";
}
signals:
public slots:
void readPendingDatagrams()
{
while (udpSocket->hasPendingDatagrams()) {
QByteArray datagram;
datagram.resize(udpSocket->pendingDatagramSize());
QHostAddress sender;
quint16 senderPort;
udpSocket->readDatagram(datagram.data(), datagram.size(),
&sender, &senderPort);
//processTheDatagram(datagram);
qDebug()<<"recv: "<<datagram;
udpSocket->writeDatagram(datagram.data(), datagram.size(),
sender, senderPort);
}
}
private:
QUdpSocket *udpSocket;
};
#endif // UDPSERVER_H
两个程序的工程文件中一定要加入network
三、TCP
服务器:
#ifndef TCPSERVER_H
#define TCPSERVER_H
#include <QObject>
#include <QTcpServer>
#include <QTcpSocket>
#include <QDebug>
class tcpServer : public QObject
{
Q_OBJECT
public:
explicit tcpServer(QObject *parent = 0);
signals:
public slots:
void newconnected()
{
qDebug()<<"connected";
clientsock = ser->nextPendingConnection();
connect(clientsock, SIGNAL(readyRead()), this, SLOT(readdata()));
}
void readdata()
{
QByteArray buf = clientsock->readAll();
qDebug()<<"recv: "<<buf;
clientsock->write(buf);
}
private:
QTcpServer *ser;
QTcpSocket *clientsock;
};
#endif // TCPSERVER_H
#include "tcpserver.h"
#include <QHostAddress>
tcpServer::tcpServer(QObject *parent) : QObject(parent)
{
ser = new QTcpServer;
ser->listen(QHostAddress::AnyIPv4, 8888);
connect(ser, SIGNAL(newConnection()), this, SLOT(newconnected()));
ser->waitForNewConnection();
}
客户端:
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QTextEdit>
#include <QLineEdit>
#include <QPushButton>
#include <QTcpSocket>
class Widget : public QWidget
{
Q_OBJECT
public slots:
void senddata()
{
tcpsocket->write(le->text().toStdString().c_str());
}
void recvdata()
{
QByteArray buf = tcpsocket->readAll();
te->append(buf);
}
public:
Widget(QWidget *parent = 0);
~Widget();
private:
QTextEdit *te;
QLineEdit *le;
QPushButton *pb;
QTcpSocket *tcpsocket;
};
#endif // WIDGET_H
#include "widget.h"
#include <QVBoxLayout>
#include <QHostAddress>
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
te = new QTextEdit;
le = new QLineEdit;
pb = new QPushButton("send");
QVBoxLayout *vbox = new QVBoxLayout;
vbox->addWidget(te);
vbox->addWidget(le);
vbox->addWidget(pb);
setLayout(vbox);
tcpsocket = new QTcpSocket;
//connect to server
tcpsocket->connectToHost(QHostAddress("192.168.3.27"), 8888);
connect(pb, SIGNAL(clicked(bool)), this, SLOT(senddata()));
connect(tcpsocket, SIGNAL(readyRead()), this, SLOT(recvdata()));
}
Widget::~Widget()
{
}
四、小项目
实现一个类似于监控的东西
就是把传输内容换成了照片
客户端:
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QLabel>
#include <QLineEdit>
#include <QTcpSocket>
#include <QPushButton>
#include <QHostAddress>
#include <QDebug>
#include <QPixmap>
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = 0);
~Widget();
public slots:
void startv()
{
readsize = true;
sockv = new QTcpSocket(this);
connect(sockv, SIGNAL(readyRead()), this, SLOT(recv_show()));
sockv->connectToHost(QHostAddress(leip->text()), atoi(leport->text().toStdString().c_str()));
btstart->setText("STOP");
leip->setDisabled(true);
leport->setDisabled(true);
disconnect(btstart, SIGNAL(clicked()), this, SLOT(startv()));
connect(btstart, SIGNAL(clicked()), this, SLOT(stop()));
}
void stop()
{
sockv->close();
sockv->deleteLater();
disconnect(btstart, SIGNAL(clicked()), this, SLOT(stop()));
connect(btstart, SIGNAL(clicked()), this, SLOT(startv()));
leip->setDisabled(false);
leport->setDisabled(false);
btstart->setText("START");
}
void recv_show()
{
if(readsize){ //接收图片大小
char buf[10] = {0};
sockv->read(buf, 10);
picsize = atoi(buf); //转成整形大小值
// qDebug()<<picsize;
readsize = false;
}
else
{
if(sockv->bytesAvailable() < picsize) //等待图片内容接收完整
return;
char buf[640*480*3];
sockv->read(buf, picsize);
QPixmap pix;
pix.loadFromData((uchar*)buf, picsize, "jpeg");
lbvideo->setPixmap(pix);//切换照片
readsize = true;
}
}
private:
QLabel *lbvideo, *lbip, *lbport;
QLineEdit *leip, *leport;
QPushButton *btstart;
QTcpSocket *sockv;
bool readsize;
int picsize;
};
#endif // WIDGET_H
#include "widget.h"
#include <QHBoxLayout>
#include <QVBoxLayout>
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
lbvideo = new QLabel;
lbvideo->setFixedSize(640,480);
lbvideo->setScaledContents(true);
lbip = new QLabel("IP");
lbport = new QLabel("PORT");
leip = new QLineEdit("192.168.3.27");
leport = new QLineEdit("8888");
btstart = new QPushButton("START");
QHBoxLayout *hbox = new QHBoxLayout;
hbox->addWidget(lbip);
hbox->addWidget(leip);
hbox->addWidget(lbport);
hbox->addWidget(leport);
hbox->addWidget(btstart);
QVBoxLayout *vbox = new QVBoxLayout;
vbox->addLayout(hbox);
vbox->addWidget(lbvideo);
setLayout(vbox);
connect(btstart, SIGNAL(clicked()), this, SLOT(startv()));
}
Widget::~Widget()
{
}
服务器:
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QCamera>
#include <QCameraViewfinder>
#include <QCameraImageCapture>
#include <QLabel>
#include <QTimerEvent>
#include <QDebug>
#include <QPixmap>
#include <QTcpServer>
#include <QTcpSocket>
#include <QTemporaryFile>
#include <QFile>
#include <QBuffer>
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = 0);
~Widget();
public slots:
void show_pic(int i, QImage img)
{
QPixmap pix(1920, 1080);
#if 1
pix.fill(Qt::red);
pix = pix.fromImage(img);
lb_pic->setPixmap(pix);
#else
lb_pic->setPixmap(QPixmap::fromImage(img));
#endif
// qDebug()<<i;
if(client&&client->isWritable())
{
// qDebug()<<"sending "<<pix.size();
#if 0
pix.save("tem.jpg","jpeg");
// qDebug()<<"saveed";
QFile tem("tem.jpg");
tem.open(QIODevice::ReadOnly);
#else
QBuffer tem;
pix.save(&tem, "jpeg");
#endif
char buf[10] = {0};
// qDebug()<<"size: "<<buf;
sprintf(buf, "%d", tem.size());
// qDebug()<<"size: "<<buf;
client->write(buf, 10);//发大小(大小值先转换成字符串装在固定的10个字节的buff中发送)
// qDebug()<<"size ok";
#if 0
QByteArray data = tem.readAll();
#else
QByteArray data(tem.buffer());
#endif
client->write(data);//发图片内容
// qDebug()<<"finish";
tem.close();
}
}
void accept_client()
{
if(NULL != client)
{
client->close();
client->deleteLater();
}
client = myserver->nextPendingConnection();
connect(client, SIGNAL(disconnected()), this, SLOT(client_close()));
}
void client_close()
{
client->close();
client->deleteLater();
client = NULL;
}
protected:
virtual void
timerEvent(QTimerEvent *event)
{
imageCapture->capture();
// qDebug()<<"tttt";
}
private:
QCamera *camera;
QCameraViewfinder *viewfinder;
QCameraImageCapture *imageCapture;
QLabel *lb_pic;
QTcpServer *myserver;
QTcpSocket *client;
};
#endif // WIDGET_H
#include "widget.h"
#include <QHBoxLayout>
#include <QHostAddress>
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
camera = new QCamera("/dev/video0"); //"/dev/video0" 摄像头设备文件,视情况而定
viewfinder = new QCameraViewfinder(this);
viewfinder->setFixedSize(640,480);
viewfinder->show();
lb_pic = new QLabel(this);
myserver = new QTcpServer(this);
client = NULL;
camera->setViewfinder(viewfinder);
QHBoxLayout *hbox = new QHBoxLayout;
hbox->addWidget(viewfinder);
hbox->addWidget(lb_pic);
this->setLayout(hbox);
imageCapture = new QCameraImageCapture(camera);
camera->setCaptureMode(QCamera::CaptureStillImage);
connect(imageCapture, SIGNAL(imageCaptured(int,QImage)), this, SLOT(show_pic(int,QImage)));
connect(myserver, SIGNAL(newConnection()), this, SLOT(accept_client()));
this->startTimer(3);
myserver->listen(QHostAddress::AnyIPv4, 8888);
camera->start();
}
Widget::~Widget()
{
}
---------------------------------------------------------------------------------------------------------------------------------
发文不通过只能写点”废话“了。学了一个星期的QT感觉其实不难,就是把一些封装好的类组合起来形成一些图形化界面。感觉还是挺好用,起码和C有相通性,唯一的难点应该在C++的语法上。所以会C++的同学应该更加的得心应手。挺好玩的,等学完驱动试试拿QT开发两个项目练练手。比如电视剧里男主给女主写的那个小猪闹钟,非常可爱以前不知道怎么下手做,学完QT我好像知道应该怎么写了。然后我还想做一个类似于QQ微信这种的聊天工具,可惜还不知道怎么用私网和私网通信。难道和女神之间搞点浪漫的东西还要租两台云服务器嘛,那也太扫兴了。现在这ip都是192.168开头的不能直接通信。听朋友说java有个内网透传技术是干这个的。不知道用C怎么实现。不过服务器我虽然买不起但是我打算自己买点件搭建一个服务器。应该会很有意思。
---------------------------------------------------------------------------------------------------------------------------------