Skip to content

Commit

Permalink
1.2
Browse files Browse the repository at this point in the history
  • Loading branch information
Cormac315 committed Nov 2, 2024
1 parent 30a8b37 commit 92e5713
Show file tree
Hide file tree
Showing 7 changed files with 171 additions and 49 deletions.
56 changes: 25 additions & 31 deletions Server.cpp
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
#define _CRT_SECURE_NO_WARNINGS
#define WIN32_LEAN_AND_MEAN // 从 Windows 头文件中排除极少使用的内容
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include <sstream> // 字符串流
#include <winsock2.h> // Windows套接字库
#include <ws2tcpip.h> // Windows套接字库
#include <chrono> // 时间库
Expand Down Expand Up @@ -79,7 +80,7 @@ class TFTPHeader {
char data[BUFFER_SIZE - 4]; // 数据

TFTPHeader(uint16_t op = 0, uint16_t blockOrError = 0) : opcode(op), blockOrErrorCode(blockOrError) {
memset(data, 0, sizeof(data));
memset(data, 0, sizeof(data));
}

void setData(const std::string& str) {
Expand Down Expand Up @@ -138,18 +139,16 @@ class TFTPServer {
return;
}

serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(PORT);
serverAddr.sin_addr.s_addr = INADDR_ANY;

if (bind(sock, (sockaddr*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR) {
logMessage("绑定失败,请检查"+ std::to_string(PORT) + "端口是否已被占用", sockaddr_in{}, 1);
// 绑定监听套接字
std::string BindResult = BindSocketToInterface(&sock, interfaces[selectedInterfaceIdx].second.find(":") != std::string::npos, interfaces[selectedInterfaceIdx].second , PORT); // 绑定到特定的网络接口,端口为指定值
if (BindResult != "OK") {
logMessage("监听套接字绑定失败:"+ BindResult, sockaddr_in{}, 1);
closesocket(sock);
WSACleanup();
return;
}

logMessage("TFTP服务器启动,正在监听"+ std::to_string(PORT) +"端口...", sockaddr_in{}, 2);
logMessage("服务器启动成功,正在监听"+ interfaces[selectedInterfaceIdx].second + " : " + std::to_string(PORT), sockaddr_in{}, 2);


ServerRootDirectory = mainFrame->server_dir->GetPath().ToStdString();
Expand Down Expand Up @@ -180,10 +179,11 @@ class TFTPServer {
logMessage("服务器已关闭", sockaddr_in{}, 2);
if (is_console_mode) {
is_console_mode = false;
running = false;
}
running = false;
closesocket(sock);
WSACleanup();
g_mainFrame->Server_Switch->SetSelection(1);
}

// 监听套接字运行时
Expand Down Expand Up @@ -299,15 +299,12 @@ class TFTPServer {
u_long blockmode = 1;
ioctlsocket(dataSock, FIONBIO, &blockmode);

// 绑定传输套接字到动态分配的端口
sockaddr_in dataAddr = {};
dataAddr.sin_family = AF_INET;
dataAddr.sin_port = 0; // 动态分配,端口设置为0
dataAddr.sin_addr.s_addr = INADDR_ANY;
if (bind(dataSock, (sockaddr*)&dataAddr, sizeof(dataAddr)) == SOCKET_ERROR) {
logMessage("绑定数据传输套接字失败", clientAddr, 1);
closesocket(dataSock);
currentThreadCount--;
// 绑定传输套接字
std::string BindResult = BindSocketToInterface(&dataSock, interfaces[selectedInterfaceIdx].second.find(":") != std::string::npos , interfaces[selectedInterfaceIdx].second , 0);// 绑定到特定的网络接口,端口随机
if (BindResult != "OK") {
logMessage("RQQ传输套接字绑定失败:" + BindResult, sockaddr_in{}, 1);
closesocket(sock);
WSACleanup();
return;
}

Expand Down Expand Up @@ -520,15 +517,12 @@ class TFTPServer {
u_long blockmode = 1;
ioctlsocket(dataSock, FIONBIO, &blockmode);

// 绑定到动态分配的端口
sockaddr_in dataAddr = {};
dataAddr.sin_family = AF_INET;
dataAddr.sin_port = 0; // 动态分配端口
dataAddr.sin_addr.s_addr = INADDR_ANY;
if (bind(dataSock, (sockaddr*)&dataAddr, sizeof(dataAddr)) == SOCKET_ERROR) {
logMessage("绑定数据传输套接字失败", clientAddr, 1);
closesocket(dataSock);
currentThreadCount--;
// 绑定传输套接字
std::string BindResult = BindSocketToInterface(&dataSock, interfaces[selectedInterfaceIdx].second.find(":") != std::string::npos, interfaces[selectedInterfaceIdx].second, 0);// 绑定到特定的网络接口,端口随机
if (BindResult != "OK") {
logMessage("WRQ传输套接字绑定失败:" + BindResult, sockaddr_in{}, 1);
closesocket(sock);
WSACleanup();
return;
}

Expand All @@ -541,17 +535,17 @@ class TFTPServer {


// 文件写操作
std::ifstream existingFile(filePath);
std::ofstream file(filePath, mode == "netascii" ? std::ios::out : std::ios::binary);
if (!file.is_open()) {
if (!file.is_open() || existingFile) {
// 检查文件是否已存在
std::ifstream existingFile(filePath);
if (existingFile) {
sendError(clientAddr, 6, "File already exists");
logMessage("客户端尝试写入一个已存在的文件:" + filename, clientAddr, 1);
}
else {
sendError(clientAddr, 2, "Cannot create file");
logMessage("服务器无法创建文件,请使用管理员权限启动服务器", clientAddr, 1);
logMessage("无法写入文件,请检查权限或者线程冲突", clientAddr, 1);
}
closesocket(dataSock); // 关闭传输套接字
currentThreadCount--;
Expand Down
8 changes: 6 additions & 2 deletions TFTP.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,10 @@
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<IncludePath>C:\env\boost_1_86_0\stage\lib;$(IncludePath)</IncludePath>
<LibraryPath>C:\env\boost_1_86_0\stage\lib;$(LibraryPath)</LibraryPath>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
Expand Down Expand Up @@ -140,14 +144,14 @@
<PreprocessorDefinitions>NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpp17</LanguageStandard>
<AdditionalIncludeDirectories>$(WXWIN)\include;$(WXWIN)\include\msvc</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>C:\env\boost_1_86_0;$(WXWIN)\include;$(WXWIN)\include\msvc</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalLibraryDirectories>$(WXWIN)\lib\vc_x64_lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalLibraryDirectories>C:\env\boost_1_86_0\stage\lib;$(WXWIN)\lib\vc_x64_lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<UACExecutionLevel>RequireAdministrator</UACExecutionLevel>
</Link>
</ItemDefinitionGroup>
Expand Down
44 changes: 31 additions & 13 deletions UI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,16 @@ bool b_error_log_switch = error_log_switch;
wxString s_error_log_dir = wxString::FromUTF8(error_log_dir.c_str());
bool is_console_mode = false;
wxString s_PORT = wxString::Format(wxT("%d"), PORT);
//wxString s_TIMEOUT = wxString::Format(wxT("%d"), TIMEOUT); // 1.1更新
//wxString s_TIMEOUT = wxString::Format(wxT("%d"), TIMEOUT); // 暂不可用
int selectedInterfaceIdx = -1;
int TableRows = 16;
bool Remember_Minimize = false;
std::vector<std::pair<std::string, std::string>> interfaces = GetNetworkInterfaces();
///////////////////////////////////////////////////////////////////////////
enum
{
PU_RESTORE = 10001,
PU_EXIT,
PU_RESTORE = 10001, // 恢复
PU_EXIT // 退出
};
///////////////////////////////////////////////////////////////////////////
main::main(wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style) : wxFrame(parent, id, title, pos, size, style)
Expand Down Expand Up @@ -81,7 +83,7 @@ main::main(wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint
check_update = new wxButton(this, wxID_ANY, _("检查更新"), wxDefaultPosition, wxDefaultSize, 0);
buttons->Add(check_update, 0, wxALL | wxEXPAND, 5);

version = new wxStaticText(this, wxID_ANY, _("当前版本:1.1"), wxDefaultPosition, wxDefaultSize, 0);
version = new wxStaticText(this, wxID_ANY, _("当前版本:1.2"), wxDefaultPosition, wxDefaultSize, 0);
version->Wrap(-1);
version->SetForegroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT));

Expand All @@ -106,7 +108,6 @@ main::main(wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint
server_dir = new wxDirPickerCtrl(this, wxID_ANY, wxT("./File"), _("服务器目录"), wxDefaultPosition, wxDefaultSize, wxDIRP_DEFAULT_STYLE);
gSizer7->Add(server_dir, 0, wxALL | wxEXPAND, 5);


grid_server_dir->Add(gSizer7, 1, wxEXPAND, 5);

wxGridSizer* grid_sever_ip;
Expand All @@ -116,16 +117,22 @@ main::main(wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint
text_server_ip->Wrap(-1);
grid_sever_ip->Add(text_server_ip, 0, wxALL | wxALIGN_CENTER_VERTICAL, 5);

wxString choice_server_ipChoices[] = { _("本地环回地址(127.0.0.1)"), _("本机公网ip") };
int choice_server_ipNChoices = sizeof(choice_server_ipChoices) / sizeof(wxString);
choice_server_ip = new wxChoice(this, wxID_ANY, wxPoint(-1, -1), wxDefaultSize, choice_server_ipNChoices, choice_server_ipChoices, 0);
selectedInterfaceIdx = 0;
if (interfaces.empty()) {
console_log->AppendText("读取网卡失败,使用默认接口");
}
interfaces.insert(interfaces.begin(),std::make_pair(std::string("Default"), std::string("All")));

wxArrayString choices;
for (const auto& iface : interfaces) {
choices.Add(wxString::FromUTF8(iface.first + " - " + iface.second));
}
choice_server_ip = new wxChoice(this, wxID_ANY, wxPoint(-1, -1), wxDefaultSize, choices, 0);
choice_server_ip->SetSelection(0);
grid_sever_ip->Add(choice_server_ip, 0, wxALL | wxEXPAND, 5);


grid_server_dir->Add(grid_sever_ip, 1, wxEXPAND, 5);


main_grid->Add(grid_server_dir, 1, wxEXPAND, 5);

wxGridSizer* console_log_grid;
Expand All @@ -134,7 +141,6 @@ main::main(wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint
console_log = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE | wxTE_READONLY);
console_log_grid->Add(console_log, 0, wxALL | wxEXPAND, 5);


main_grid->Add(console_log_grid, 1, wxEXPAND, 5);

wxGridSizer* information_grid;
Expand Down Expand Up @@ -201,6 +207,7 @@ main::main(wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint
version->Connect(wxEVT_LEFT_DOWN, wxMouseEventHandler(main::OnVersionClick), NULL, this);
version->Bind(wxEVT_ENTER_WINDOW, &main::OnMouseEnter, this);
version->Bind(wxEVT_LEAVE_WINDOW, &main::OnMouseLeave, this);
choice_server_ip->Connect(wxEVT_CHOICE, wxCommandEventHandler(main::OnServerIPChanged), NULL, this);
this->Bind(wxEVT_CLOSE_WINDOW, &main::OnClose, this); // 关闭窗口事件
loadSettings("settings.conf"); // 读取配置文件
}
Expand Down Expand Up @@ -280,7 +287,7 @@ void main::OnCheckUpdateButtonClick(wxCommandEvent& event)
wxMessageBox(_("版本检查程序Version.exe不存在"), _("错误"), wxOK | wxICON_ERROR);
return;
}
std::string version = "1.1"; // 当前版本号
std::string version = "1.2"; // 当前版本号
std::string command = "Version.exe " + version;
system(command.c_str());

Expand Down Expand Up @@ -390,7 +397,7 @@ void main::TableStatus(int row, bool success)

void main::OnVersionClick(wxMouseEvent& event)
{
wxMessageBox(_("1.1更新\n- 修复了异常情况不能正常重传的bug\n- 传输使用非阻塞模式和Select方法,提升了性能\n- 表格现在可以动态更新行数\n- 优化计时器逻辑\n更新计划:\n- 动态调整超时时间,并且可以手动设置\n- 减少冗余ACK的发送"), _("更新信息"), wxOK | wxICON_INFORMATION, this);
wxMessageBox(_("1.2更新\n- 添加选择网络接口功能\n- 优化套接字绑定失败错误信息\n更新计划:\n- 动态调整超时时间,并且可以手动设置\n- 减少冗余ACK的发送"), _("更新信息"), wxOK | wxICON_INFORMATION, this);
}

void main::OnMouseEnter(wxMouseEvent& event)
Expand Down Expand Up @@ -448,6 +455,17 @@ void main::OnClose(wxCloseEvent& event)
// 如果用户选择取消,则不执行任何操作
}

void main::OnServerIPChanged(wxCommandEvent& event)
{
if (running) {
wxMessageBox("服务器启动时禁止更改此选项,请先关闭服务器。", "非法操作", wxICON_ERROR);
choice_server_ip->SetSelection(selectedInterfaceIdx);
}
else {
selectedInterfaceIdx = choice_server_ip->GetSelection(); // 获取选择的网卡
}
}


main::~main()
{
Expand Down
1 change: 1 addition & 0 deletions UI.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ class main : public wxFrame
void OnMouseEnter(wxMouseEvent& event);
void OnMouseLeave(wxMouseEvent& event);
void loadSettings(const std::string& configFilePath);
void OnServerIPChanged(wxCommandEvent& event);

// 维护表格信息
void AddClientInfo(const std::string& ip, const std::string& file, const std::string& startTime);
Expand Down
99 changes: 98 additions & 1 deletion api.cpp
Original file line number Diff line number Diff line change
@@ -1,8 +1,20 @@
#define _CRT_SECURE_NO_WARNINGS
#include "api.h"
#include <iomanip>
#include <sstream>
#include <winsock2.h> // Windows套接字库
#include <Windows.h>
#include <iphlpapi.h>
#include <boost/asio.hpp>
#include <vector>
#include <string>
#include "shared.h"
#include <wx/msgdlg.h>
#include <locale>
#include <iostream>
#include <codecvt>

#pragma comment(lib, "iphlpapi.lib")
#pragma comment(lib, "ws2_32.lib")

Timer::Timer() : isRunning(false) {}

Expand Down Expand Up @@ -81,3 +93,88 @@ void CloseConsoleWindow() {
FreeConsole();
}


std::string ConvertWStringToString(const std::wstring& wstr) {
int size_needed = WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), (int)wstr.size(), nullptr, 0, nullptr, nullptr);
std::string str(size_needed, 0);
WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), (int)wstr.size(), &str[0], size_needed, nullptr, nullptr);
return str;
}

// 获取网卡信息
std::vector<std::pair<std::string, std::string>> GetNetworkInterfaces() {
std::vector<std::pair<std::string, std::string>> interfaces;
ULONG bufferSize = 15000;
PIP_ADAPTER_ADDRESSES addresses = (IP_ADAPTER_ADDRESSES*)malloc(bufferSize);

if (GetAdaptersAddresses(AF_UNSPEC, 0, nullptr, addresses, &bufferSize) == ERROR_BUFFER_OVERFLOW) {
free(addresses);
addresses = (IP_ADAPTER_ADDRESSES*)malloc(bufferSize);
}

if (GetAdaptersAddresses(AF_UNSPEC, 0, nullptr, addresses, &bufferSize) == NO_ERROR) {
for (PIP_ADAPTER_ADDRESSES addr = addresses; addr != nullptr; addr = addr->Next) {
std::string name = ConvertWStringToString(addr->FriendlyName);
for (PIP_ADAPTER_UNICAST_ADDRESS ua = addr->FirstUnicastAddress; ua != nullptr; ua = ua->Next) {
char ip[INET6_ADDRSTRLEN];
if (getnameinfo(ua->Address.lpSockaddr, ua->Address.iSockaddrLength, ip, sizeof(ip), nullptr, 0, NI_NUMERICHOST) == 0) {
interfaces.push_back(std::make_pair(name,ip));
}
}
}
}
free(addresses);
return interfaces;
}

std::string GetLastErrorAsString() {
// 获取错误代码
DWORD errorMessageID = WSAGetLastError();
if (errorMessageID == 0) {
return "端口被占用";
}

LPSTR messageBuffer = nullptr;
size_t size = FormatMessageA(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
nullptr, errorMessageID, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&messageBuffer, 0, nullptr);

std::string message(messageBuffer, size);

// 释放缓冲区
LocalFree(messageBuffer);

return message;
}

// 绑定套接字到特定的网络接口
std::string BindSocketToInterface(SOCKET* sock, bool isIPV6, const std::string& ipAddress, int port) {
struct sockaddr_in service;

// 设置套接字地址和端口
if (isIPV6) {
return "IPV6 is not supported";
}
else {
service.sin_family = AF_INET;
if (ipAddress == std::string("All"))service.sin_addr.s_addr = INADDR_ANY; // 所有接口
else if (InetPtonA(AF_INET, ipAddress.c_str(), &service.sin_addr) != 1) {
return "Invalid IPV4 address format : " + ipAddress;
}
service.sin_port = htons(port);
}

// 绑定套接字到特定的网络接口
if (bind(*sock, (SOCKADDR*)&service, sizeof(service)) == SOCKET_ERROR) {
closesocket(*sock);
WSACleanup();
return GetLastErrorAsString();
}
return "OK";
}






Loading

0 comments on commit 92e5713

Please sign in to comment.