计算机网络实验坑有点多,感谢同学的帮助。
1.使用Qt creator创建widgets application。
2.在项目中的.pro文件中添加一句
LIBS += -lpthread libwsock32 libws2_32
3.编写界面大致如图所示,然后就能开始代码编写了。
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
端口号