本文接 <c++实现的Mini Web Server,暂时当ftp使用> 给出Mini WebServer for Ftp的linux版本。
效果图:
Linux版miniweb下载:miniweb_linux.tar.gz
关键代码:
和Windows版的主要区别在于IoUtil.cpp文件中关于文件目录信息的读取部分,其他地方只有细微的改动,在此只给出IoUtil.cpp的代码:
#include "stdafx.h" #include "IoUtil.h" #include "Constant.h" #if defined WIN32 #include <Windows.h> #else #include <dirent.h> #include <sys/stat.h> #include <time.h> #endif const char* MONTH_NAME[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; IoUtil::IoUtil(void) { m_path = ""; } IoUtil::IoUtil( const char* path ) { m_path = path; } IoUtil::~IoUtil(void) { } int IoUtil::Dir( FILELIST_VECTOR& filelist ) { #if defined WIN32 filelist.clear(); char pathMask[MAX_PATH_LENGTH]; strcpy(pathMask, m_path.c_str()); strcat(pathMask, "//*"); WIN32_FIND_DATA fileData; HANDLE hSearch; bool fFinished = false; SYSTEMTIME systemtime; FILETIME filetime; long long filesize; FILE_INFO_ST fileitem; FILELIST_VECTOR tmpList; /////// hSearch = FindFirstFile( pathMask, &fileData ); if(hSearch == INVALID_HANDLE_VALUE) return -1; while(!fFinished) { if(!(fileData.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM)) { FileTimeToLocalFileTime(&fileData.ftLastWriteTime, &filetime); FileTimeToSystemTime(&filetime, &systemtime); filesize = fileData.nFileSizeHigh; filesize = filesize << 32; filesize = filesize + fileData.nFileSizeLow; if((filesize>>50) > 0) { long long modnum = filesize % 1024; long long decimal = (long long)(1.0 * modnum * 100 / (1024 * 1024 * 1024 * 1024 * 1024)); sprintf(fileitem.filesize, "%I64d.%I64d PB", filesize>>50, decimal); } else if((filesize>>40) > 0) { long long modnum = filesize % 1024; long long decimal = (long long)(1.0 * modnum * 100 / (1024 * 1024 * 1024 * 1024)); sprintf(fileitem.filesize, "%I64d.%I64d TB", filesize>>40, decimal); } else if((filesize>>30) > 0) { long long modnum = filesize % 1024; long long decimal = (long long)(1.0 * modnum * 100 / (1024 * 1024 * 1024)); sprintf(fileitem.filesize, "%I64d.%I64d GB", filesize>>30, decimal); } else if((filesize>>20) > 0) { long long modnum = filesize % 1024; long long decimal = (long long)(1.0 * modnum * 100 / (1024 * 1024)); sprintf(fileitem.filesize, "%I64d.%I64d MB", filesize>>20, decimal); } else if((filesize>>10) > 0) { long long modnum = filesize % 1024; long long decimal = (long long)(1.0 * modnum * 100 / (1024)); sprintf(fileitem.filesize, "%I64d.%I64d KB", filesize>>10, decimal); } else sprintf(fileitem.filesize, "%I64d B", filesize); //sprintf(fileitem.filesize, "%I64d.%d", filesize>>10, decimal); sprintf(fileitem.lastmodifiedtime, "%02d-%s-%4d %02d:%02d", systemtime.wDay, MONTH_NAME[systemtime.wMonth - 1], systemtime.wYear, systemtime.wHour, systemtime.wMinute); sprintf(fileitem.filename, "%s", fileData.cFileName); if(fileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { sprintf(fileitem.attribute, "%s", "DIR"); filelist.push_back(fileitem); } else { sprintf(fileitem.attribute, "%s", "---"); tmpList.push_back(fileitem); } } if(!FindNextFile(hSearch, &fileData)) { if(GetLastError() == ERROR_NO_MORE_FILES) { fFinished = true; } } } FindClose(hSearch); for(size_t i = 0; i < tmpList.size(); i++) filelist.push_back(tmpList[i]); tmpList.clear(); #else FILE_INFO_ST fileitem; FILELIST_VECTOR tmpList; long long filesize; struct dirent* ent = NULL; DIR *pDir; filelist.clear(); pDir = opendir(m_path.c_str()); strcpy(fileitem.filename, ".."); strcpy(fileitem.attribute, "DIR"); filelist.push_back(fileitem); while ((ent = readdir(pDir))!=NULL) { if( strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0) { continue; } struct stat buf; char tmpFn[MAX_PATH_LENGTH]; memset(tmpFn, 0, MAX_PATH_LENGTH); strcpy(tmpFn, m_path.c_str()); strcat(tmpFn, "/"); strcat(tmpFn, ent->d_name); lstat(tmpFn, &buf); filesize = (unsigned long)buf.st_size; if((filesize>>50) > 0) { long long modnum = filesize % 1024; long long decimal = (long long)(1.0 * modnum * 100 / (1024 * 1024 * 1024 * 1024 * 1024)); sprintf(fileitem.filesize, "%Ild.%Ild PB", filesize>>50, decimal); } else if((filesize>>40) > 0) { long long modnum = filesize % 1024; long long decimal = (long long)(1.0 * modnum * 100 / (1024 * 1024 * 1024 * 1024)); sprintf(fileitem.filesize, "%Ild.%Ild TB", filesize>>40, decimal); } else if((filesize>>30) > 0) { long long modnum = filesize % 1024; long long decimal = (long long)(1.0 * modnum * 100 / (1024 * 1024 * 1024)); sprintf(fileitem.filesize, "%Ild.%Ild GB", filesize>>30, decimal); } else if((filesize>>20) > 0) { long long modnum = filesize % 1024; long long decimal = (long long)(1.0 * modnum * 100 / (1024 * 1024)); sprintf(fileitem.filesize, "%Ild.%Ild MB", filesize>>20, decimal); } else if((filesize>>10) > 0) { long long modnum = filesize % 1024; long long decimal = (long long)(1.0 * modnum * 100 / (1024)); sprintf(fileitem.filesize, "%Ild.%Ild KB", filesize>>10, decimal); } else sprintf(fileitem.filesize, "%Ild B", filesize); struct tm* tm = gmtime(&buf.st_mtime); sprintf(fileitem.lastmodifiedtime, "%02d-%s-%4d %02d:%02d", tm->tm_mday, MONTH_NAME[tm->tm_mon], tm->tm_year + 1900, tm->tm_hour, tm->tm_min); sprintf(fileitem.filename, ent->d_name); if(ent->d_type == DT_DIR ) { sprintf(fileitem.attribute, "%s", "DIR"); filelist.push_back(fileitem); } else { sprintf(fileitem.attribute, "%s", "---"); tmpList.push_back(fileitem); } } for(size_t i = 0; i < tmpList.size(); i++) filelist.push_back(tmpList[i]); tmpList.clear(); #endif return 0; } void IoUtil::GetFileSize( char* filesizeStr ) { #if defined WIN32 WIN32_FIND_DATA fileData; HANDLE hSearch; long long filesize; /////// hSearch = FindFirstFile( m_path.c_str(), &fileData ); if(hSearch == INVALID_HANDLE_VALUE) return ; filesize = fileData.nFileSizeHigh; filesize = filesize << 32; filesize = filesize + fileData.nFileSizeLow; sprintf(filesizeStr, "%I64d", filesize); FindClose(hSearch); #else struct stat buf; stat(m_path.c_str(), &buf); sprintf(filesizeStr, "%lld", buf.st_size); #endif } bool IoUtil::SendFile( SOCKET socket, long long seekpos ) { #if defined WIN32 char buffer[1025]; DWORD dwRead; HANDLE hFile = NULL; for(int i = 0; i < 20; i++) { hFile = ::CreateFile(m_path.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); if(hFile) break; Sleep(200); } if(!hFile) return false; else { LARGE_INTEGER lint ; lint.QuadPart = seekpos; SetFilePointer(hFile, lint.LowPart, &lint.HighPart, FILE_BEGIN); while(1) { dwRead = 0; bool bResult = ::ReadFile(hFile, buffer, 1024, &dwRead, NULL); if(!bResult) break; //end of file if((bResult) && (dwRead == 0)) break; int nSend = Send(socket, buffer, dwRead); if(nSend < 0) break; } CloseHandle(hFile); return true; } #else char buffer[1025]; int dwRead; FILE* hFile = NULL; for(int i = 0; i < 20; i++) { hFile = fopen(m_path.c_str(), "rb"); if(hFile) break; usleep(200000); } if(!hFile) return false; else { while(!feof(hFile)) { dwRead = 0; dwRead = fread(buffer, sizeof(char), 1024, hFile); //end of file int nSend = Send(socket, buffer, dwRead); if(nSend < 0) break; } fclose(hFile); return true; } #endif } int IoUtil::Send( SOCKET socket, const char* buffer, UINT len ) { long already_time = 0; fd_set fdset; struct timeval timeout; timeout.tv_sec = SELECT_WAIT_TIME; timeout.tv_usec = 0; size_t nSend = 0; size_t tLen = 0; while(1) { FD_ZERO(&fdset); FD_SET(socket, &fdset); int ret = select(socket + 1, NULL, &fdset, NULL, &timeout); switch(ret) { case 1: already_time = 0; tLen = send(socket, buffer, len - nSend, 0); nSend += tLen; if(nSend == len) return SOCKET_SENDRECV_OK; break; case 0: already_time += SELECT_WAIT_TIME; if(already_time >= MAX_WAIT_TIME_FOR_SENDRECV) { close(socket); return SOCKET_SENDRECV_TIMEOUT; } break; default: return SOCKET_SENDRECV_ERROR; } } }
另外附上socket相关程序在windows和linux下有所区别的地方:
1)头文件
windows下winsock.h/winsock2.h
linux下sys/socket.h
错误处理:errno.h
2)初始化
windows下需要用WSAStartup
linux下不需要
3)关闭socket
windows下closesocket(...)
linux下close(...)
4)类型
windows下SOCKET
linux下int
如用到的一些宏:
#ifdef WIN32
typedef int socklen_t;
typedef int ssize_t;
#endif
#ifdef __LINUX__
typedef int SOCKET;
typedef unsigned char BYTE;
typedef unsigned long DWORD;
#define FALSE 0
#define SOCKET_ERROR (-1)
#endif
5)获取错误码
windows下getlasterror()/WSAGetLastError()
linux下errno变量
6)设置非阻塞
windows下ioctlsocket()
linux下fcntl() <fcntl.h>
7)send函数最后一个参数
windows下一般设置为0
linux下最好设置为MSG_NOSIGNAL,如果不设置,在发送出错后有可 能会导致程序退出。
8)毫秒级时间获取
windows下GetTickCount()
linux下gettimeofday()
3、多线程
多线程: (win)process.h --〉(linux)pthread.h
_beginthread --> pthread_create
_endthread --> pthread_exit