winsock编程-使用Qt,多线程

计算机网络实验坑有点多,感谢同学的帮助。

1.使用Qt creator创建widgets application。

2.在项目中的.pro文件中添加一句

LIBS += -lpthread libwsock32 libws2_32

3.编写界面大致如图所示,然后就能开始代码编写了。

winsock编程-使用Qt,多线程_第1张图片

4.main.cpp

#include "mainwindow.h"

#include 

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.setWindowTitle("Web 服务器");
    w.show();
    return a.exec();
}

5. mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "waiting.h"
#include
#include 
#include
#include
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
}

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

void MainWindow::on_pushButton_clicked()
{
    if(ui->lineEdit->text()==""||ui->lineEdit_2->text()=="")
    {
        ui->textEdit->append("Warning,请输入IP地址和端口号!");
        return;
    }
    else if(ui->lineEdit_3->text()=="")
    {
        ui->textEdit->append("Warning,请输入文件路径!");
    }
    //验证版本
    int nRc = WSAStartup(0x0101, & wsaData);
    if(nRc)
    {
    //Winsock初始化错误
        return;
    }
    if(wsaData.wVersion != 0x0101)
    {
    //版本支持不够
    //报告错误给用户,清除Winsock,返回
        ui->textEdit->append("版本出现问题!");
        WSACleanup();
        return;
    }
    //创建套接字
    mysocket = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
    ui->textEdit->append("Socket 创建成功.");
    //bind
    sockaddr_in addr;
    addr.sin_family = AF_INET;

    //htons和htonl函数把主机字节顺序转换为网络字节顺序,分别用于//短整型和长整型数据
    addr.sin_port = htons(5050);
    addr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);

    // LPSOCKADDR类型转换是必须的
    nRc = bind(mysocket, LPSOCKADDR(&addr), sizeof(addr) );
    if(nRc == SOCKET_ERROR)
    {
        ui->textEdit->append("bind error!");
        return;
    }
    ui->textEdit->append("Bind 成功.");
    //listen
    listen(mysocket,10);
    ui->textEdit->append("Listen 成功.");
    //创建新线程
    waiting = new Waiting(mysocket,path);
    //当isMsg触发时即进行操作
    connect(waiting,&Waiting::isMsg,this,[=](QString msg){
        ui->textEdit->append(msg);
    });
    waiting->start();
}

void MainWindow::on_pushButton_2_clicked()
{
    waiting->terminate();
    waiting->quit();
    waiting->wait();
    delete waiting;
    ::closesocket(mysocket);
    ui->textEdit->setText("");
    ui->textEdit->append("Socket clossed.");
}

void MainWindow::on_toolButton_clicked()
{
    path=QFileDialog::getExistingDirectory(this, "打开文件", "‪.");
    ui->lineEdit_3->setText(path);
}

6.mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include"waiting.h"
#include 
#include
#include 
#include 
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();
private slots:

    void on_pushButton_clicked();

    void on_pushButton_2_clicked();

    void on_toolButton_clicked();

private:
    Ui::MainWindow *ui;
    WSADATA wsaData;
    SOCKET mysocket = INVALID_SOCKET;
    Waiting *waiting;
    QString path;
};
#endif // MAINWINDOW_H

7.waiting.cpp

#include "waiting.h"

Waiting::Waiting(SOCKET mySocket,QString path,QWidget *parent):QThread(parent)
{
    this->mySocket = mySocket;
    this->parent = parent;
    this->path=path;
}
Waiting::~Waiting(){
    closesocket(mySocket);
    emit isClose();
}
void Waiting::run()
{
    SOCKET client;
    sockaddr_in addr;
    int addrlen = sizeof (addr);
    while(!isInterruptionRequested()){
        memset(&addr,0,sizeof (addr));
        client = accept(mySocket,(SOCKADDR*)&addr,&addrlen);
        QTime time = QTime::currentTime();
        QString timestr = time.toString("hh:mm:ss");
        char* clientIp = inet_ntoa(addr.sin_addr);
        int clientPort = ntohs(addr.sin_port);
        //处理报文
        char data[1024];
        int ret = recv(client,data,1024,0);
        if(ret>0){
            char first[100] = {'\0'};
            char url[100] = {'\0'};
            unsigned int i = 0,j = 0;
            //提取第一个单词
            while (data[j] != ' ' && (i < sizeof(first) - 1))
            {
                first[i] = data[j];
                i++;
                j++;
            }
            first[i] = '\0';
            //提取url
            i = 0;
            while ((data[j] == ' ') && (j < sizeof(data)-1))
                j++;
            while (data[j] != ' ' && (i < sizeof(data) - 1) && (j < sizeof(data)-1))
            {
                url[i] = data[j];
                i++;
                j++;
            }
            url[i] = '\0';
            //更新主界面
            QString msg=QString("%1:收到一个客户端连接请求,地址为:%2,端口号为%3,请求为%4 %5")
                        .arg(timestr).arg(clientIp).arg(clientPort)
                        .arg(first).arg(url);
            emit isMsg(msg);

            //传输数据
            QString filepath = path +url;
            Send *send = new Send(client,addr,filepath,parent);
            send->start();
            connect(send,&Send::sMsg,this,[=](QString smsg){
                emit isMsg(smsg);
            });
            connect(send,&Send::isClose,this,[=](){
                send->terminate();
                send->quit();
                delete send;
                closesocket(client);
            });
        }
        else{
            continue;
        }

    }
}

8.waiting.h

#ifndef WAITING_H
#define WAITING_H
#include
#include
#include
#include
#include 
#include
#include
#include"send.h"
class Waiting : public QThread
{
    Q_OBJECT
public:
    explicit Waiting(SOCKET mySocket,QString path,QWidget *parent = nullptr);
    void run();
    ~Waiting();
signals:
    void isMsg(QString msg);
    void isClose();
private:
    SOCKET mySocket;
    QWidget *parent;
    QString path;
    char file[200] = {'\0'};
};

#endif // WAITING_H

9.send.cpp

#include "send.h"
#include

Send::Send(SOCKET client,sockaddr_in addr,QString filepath,QWidget *parent):QThread(parent)
{
    this->client = client;
    this->addr = addr;
    this->parent = parent;
    this->filepath = filepath;
}
Send::~Send(){

}
void Send::run(){
    QByteArray filepathb = filepath.toLatin1();
    char *file = filepathb.data();
    QString msg;
    char buf[1024];
    FILE *f = fopen(file,"rb");
    if(f == nullptr){
        NotFound();
        msg = QString("没有找到文件!");
        emit sMsg(msg);
    }
    else{
        //构造报头
        char senddata[1024]="HTTP/1.1 200 OK\r\n";
        if(filepath.endsWith(".html")){
            strcat(senddata, "Content-Type: text/html\r\n");
        }
        else if(filepath.endsWith(".jpg")){
            strcat(senddata,"Content-Type: image/jpeg\r\n");
        }
        else if(filepath.endsWith(".css")){
            strcat(senddata,"Content-Type: text/css\r\n");
        }
        fseek(f,0,SEEK_END);
        int flen = ftell(f);
        QString lenstr = QString::number(flen);
        char * str = ((QString("Content-Length: %1\r\n").arg(lenstr)).toLatin1()).data();
        strcat(senddata,str);
        strcat(senddata,"\r\n");
        //发送报头
        send(client,senddata,strlen(senddata),0);
        qDebug()<404 Not Found");
    send(client, senddata, strlen(senddata), 0);
}

10.send.h

#ifndef SEND_H
#define SEND_H

#include
#include
#include
#include

class Send:public QThread
{
    Q_OBJECT
public:
    explicit Send (SOCKET client,sockaddr_in addr,QString filePath,QWidget *parent = nullptr);
    ~Send();
    void run();
public slots:
    void NotFound();
signals:
    void sMsg(QString);
    void isClose();
private:
    SOCKET client;
    sockaddr_in addr;
    QString filepath;
    QWidget *parent;
};

#endif // SEND_H

11.XXX.pro

QT       += core gui
LIBS += -lpthread libwsock32 libws2_32
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

CONFIG += c++11

# The following define makes your compiler emit warnings if you use
# any Qt feature that has been marked deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS

# You can also make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0

SOURCES += \
    main.cpp \
    mainwindow.cpp \
    send.cpp \
    waiting.cpp

HEADERS += \
    mainwindow.h \
    send.h \
    waiting.h

FORMS += \
    mainwindow.ui

# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target

12.mainwindow.ui



 MainWindow
 
  
   
    0
    0
    800
    600
   
  
  
   MainWindow
  
  
   
    
     
      370
      360
      101
      41
     
    
    
     开启服务器
    
   
   
    
     
      30
      20
      701
      201
     
    
   
   
    
     
      470
      240
      201
      31
     
    
    
     127.0.0.1
    
   
   
    
     
      470
      280
      201
      31
     
    
    
     5050
    
   
   
    
     
      470
      320
      161
      31
     
    
    
     H:/
    
   
   
    
     
      580
      360
      91
      41
     
    
    
     关闭服务器
    
   
   
    
     
      630
      320
      41
      31
     
    
    
     ...
    
   
   
    
     
      390
      240
      71
      31
     
    
    
     IP地址
    
   
   
    
     
      390
      290
      61
      31
     
    
    
     端口号
    
   
  
 
 
 

 

你可能感兴趣的:(网络,winsock,socket,qt,网络)