本文接 <c++實現的Mini Web Server,暫時當ftp使用> 給出Mini WebServer for Ftp的linux版本。
:
Linux版miniweb下載:miniweb_linux.tar.gz
關鍵代碼:
和Windows版的主要區別在於IoUtil.cpp檔案中關於檔案目錄資訊的讀取部分,其他地方只有細微的改動,在此只給出IoUtil.cpp的代碼:
#include "stdafx.h"<br />#include "IoUtil.h"<br />#include "Constant.h"<br />#if defined WIN32<br />#include <Windows.h><br />#else<br />#include <dirent.h><br />#include <sys/stat.h><br />#include <time.h><br />#endif<br />const char* MONTH_NAME[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",<br /> "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};<br />IoUtil::IoUtil(void)<br />{<br /> m_path = "";<br />}<br />IoUtil::IoUtil( const char* path )<br />{<br /> m_path = path;<br />}<br />IoUtil::~IoUtil(void)<br />{<br />}<br />int IoUtil::Dir( FILELIST_VECTOR& filelist )<br />{<br />#if defined WIN32<br /> filelist.clear();<br /> char pathMask[MAX_PATH_LENGTH];<br /> strcpy(pathMask, m_path.c_str());<br /> strcat(pathMask, "//*");<br /> WIN32_FIND_DATA fileData;<br /> HANDLE hSearch;<br /> bool fFinished = false;<br /> SYSTEMTIME systemtime;<br /> FILETIME filetime;<br /> long long filesize;<br /> FILE_INFO_ST fileitem;<br /> FILELIST_VECTOR tmpList;<br /> ///////<br /> hSearch = FindFirstFile( pathMask, &fileData );<br /> if(hSearch == INVALID_HANDLE_VALUE)<br /> return -1;<br /> while(!fFinished)<br /> {<br /> if(!(fileData.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM))<br /> {<br /> FileTimeToLocalFileTime(&fileData.ftLastWriteTime, &filetime);<br /> FileTimeToSystemTime(&filetime, &systemtime);<br /> filesize = fileData.nFileSizeHigh;<br /> filesize = filesize << 32;<br /> filesize = filesize + fileData.nFileSizeLow;<br /> if((filesize>>50) > 0)<br /> {<br /> long long modnum = filesize % 1024;<br /> long long decimal = (long long)(1.0 * modnum * 100 / (1024 * 1024 * 1024 * 1024 * 1024));<br /> sprintf(fileitem.filesize, "%I64d.%I64d PB", filesize>>50, decimal);<br /> }<br /> else if((filesize>>40) > 0)<br /> {<br /> long long modnum = filesize % 1024;<br /> long long decimal = (long long)(1.0 * modnum * 100 / (1024 * 1024 * 1024 * 1024));<br /> sprintf(fileitem.filesize, "%I64d.%I64d TB", filesize>>40, decimal);<br /> }<br /> else if((filesize>>30) > 0)<br /> {<br /> long long modnum = filesize % 1024;<br /> long long decimal = (long long)(1.0 * modnum * 100 / (1024 * 1024 * 1024));<br /> sprintf(fileitem.filesize, "%I64d.%I64d GB", filesize>>30, decimal);<br /> }<br /> else if((filesize>>20) > 0)<br /> {<br /> long long modnum = filesize % 1024;<br /> long long decimal = (long long)(1.0 * modnum * 100 / (1024 * 1024));<br /> sprintf(fileitem.filesize, "%I64d.%I64d MB", filesize>>20, decimal);<br /> }<br /> else if((filesize>>10) > 0)<br /> {<br /> long long modnum = filesize % 1024;<br /> long long decimal = (long long)(1.0 * modnum * 100 / (1024));<br /> sprintf(fileitem.filesize, "%I64d.%I64d KB", filesize>>10, decimal);<br /> }<br /> else<br /> sprintf(fileitem.filesize, "%I64d B", filesize);<br /> //sprintf(fileitem.filesize, "%I64d.%d", filesize>>10, decimal);<br /> sprintf(fileitem.lastmodifiedtime, "%02d-%s-%4d %02d:%02d",<br /> systemtime.wDay,<br /> MONTH_NAME[systemtime.wMonth - 1],<br /> systemtime.wYear,<br /> systemtime.wHour,<br /> systemtime.wMinute);<br /> sprintf(fileitem.filename, "%s", fileData.cFileName);<br /> if(fileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)<br /> {<br /> sprintf(fileitem.attribute, "%s", "DIR");<br /> filelist.push_back(fileitem);<br /> }<br /> else<br /> {<br /> sprintf(fileitem.attribute, "%s", "---");<br /> tmpList.push_back(fileitem);<br /> }<br /> }<br /> if(!FindNextFile(hSearch, &fileData))<br /> {<br /> if(GetLastError() == ERROR_NO_MORE_FILES)<br /> {<br /> fFinished = true;<br /> }<br /> }<br /> }<br /> FindClose(hSearch);<br /> for(size_t i = 0; i < tmpList.size(); i++)<br /> filelist.push_back(tmpList[i]);<br /> tmpList.clear();<br />#else<br /> FILE_INFO_ST fileitem;<br /> FILELIST_VECTOR tmpList;<br /> long long filesize;<br /> struct dirent* ent = NULL;<br /> DIR *pDir;<br /> filelist.clear();<br /> pDir = opendir(m_path.c_str());<br /> strcpy(fileitem.filename, "..");<br /> strcpy(fileitem.attribute, "DIR");<br /> filelist.push_back(fileitem);<br /> while ((ent = readdir(pDir))!=NULL)<br /> {<br /> if( strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)<br /> {<br /> continue;<br /> }<br /> struct stat buf;<br /> char tmpFn[MAX_PATH_LENGTH];<br /> memset(tmpFn, 0, MAX_PATH_LENGTH);<br /> strcpy(tmpFn, m_path.c_str());<br /> strcat(tmpFn, "/");<br /> strcat(tmpFn, ent->d_name);<br /> lstat(tmpFn, &buf);<br /> filesize = (unsigned long)buf.st_size;<br /> if((filesize>>50) > 0)<br /> {<br /> long long modnum = filesize % 1024;<br /> long long decimal = (long long)(1.0 * modnum * 100 / (1024 * 1024 * 1024 * 1024 * 1024));<br /> sprintf(fileitem.filesize, "%Ild.%Ild PB", filesize>>50, decimal);<br /> }<br /> else if((filesize>>40) > 0)<br /> {<br /> long long modnum = filesize % 1024;<br /> long long decimal = (long long)(1.0 * modnum * 100 / (1024 * 1024 * 1024 * 1024));<br /> sprintf(fileitem.filesize, "%Ild.%Ild TB", filesize>>40, decimal);<br /> }<br /> else if((filesize>>30) > 0)<br /> {<br /> long long modnum = filesize % 1024;<br /> long long decimal = (long long)(1.0 * modnum * 100 / (1024 * 1024 * 1024));<br /> sprintf(fileitem.filesize, "%Ild.%Ild GB", filesize>>30, decimal);<br /> }<br /> else if((filesize>>20) > 0)<br /> {<br /> long long modnum = filesize % 1024;<br /> long long decimal = (long long)(1.0 * modnum * 100 / (1024 * 1024));<br /> sprintf(fileitem.filesize, "%Ild.%Ild MB", filesize>>20, decimal);<br /> }<br /> else if((filesize>>10) > 0)<br /> {<br /> long long modnum = filesize % 1024;<br /> long long decimal = (long long)(1.0 * modnum * 100 / (1024));<br /> sprintf(fileitem.filesize, "%Ild.%Ild KB", filesize>>10, decimal);<br /> }<br /> else<br /> sprintf(fileitem.filesize, "%Ild B", filesize);<br /> struct tm* tm = gmtime(&buf.st_mtime);<br /> sprintf(fileitem.lastmodifiedtime, "%02d-%s-%4d %02d:%02d", tm->tm_mday,<br /> MONTH_NAME[tm->tm_mon], tm->tm_year + 1900, tm->tm_hour, tm->tm_min);<br /> sprintf(fileitem.filename, ent->d_name);<br /> if(ent->d_type == DT_DIR )<br /> {<br /> sprintf(fileitem.attribute, "%s", "DIR");<br /> filelist.push_back(fileitem);<br /> }<br /> else<br /> {<br /> sprintf(fileitem.attribute, "%s", "---");<br /> tmpList.push_back(fileitem);<br /> }<br /> }<br /> for(size_t i = 0; i < tmpList.size(); i++)<br /> filelist.push_back(tmpList[i]);<br /> tmpList.clear();<br />#endif<br /> return 0;<br />}<br />void IoUtil::GetFileSize( char* filesizeStr )<br />{<br />#if defined WIN32<br /> WIN32_FIND_DATA fileData;<br /> HANDLE hSearch;<br /> long long filesize;<br /> ///////<br /> hSearch = FindFirstFile( m_path.c_str(), &fileData );<br /> if(hSearch == INVALID_HANDLE_VALUE)<br /> return ;<br /> filesize = fileData.nFileSizeHigh;<br /> filesize = filesize << 32;<br /> filesize = filesize + fileData.nFileSizeLow;<br /> sprintf(filesizeStr, "%I64d", filesize);<br /> FindClose(hSearch);<br />#else<br /> struct stat buf;<br /> stat(m_path.c_str(), &buf);<br /> sprintf(filesizeStr, "%lld", buf.st_size);<br />#endif<br />}<br />bool IoUtil::SendFile( SOCKET socket, long long seekpos )<br />{<br />#if defined WIN32<br /> char buffer[1025];<br /> DWORD dwRead;<br /> HANDLE hFile = NULL;<br /> for(int i = 0; i < 20; i++)<br /> {<br /> hFile = ::CreateFile(m_path.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);<br /> if(hFile)<br /> break;<br /> Sleep(200);<br /> }<br /> if(!hFile)<br /> return false;<br /> else<br /> {<br /> LARGE_INTEGER lint ;<br /> lint.QuadPart = seekpos;<br /> SetFilePointer(hFile, lint.LowPart, &lint.HighPart, FILE_BEGIN);<br /> while(1)<br /> {<br /> dwRead = 0;<br /> bool bResult = ::ReadFile(hFile, buffer, 1024, &dwRead, NULL);<br /> if(!bResult)<br /> break;<br /> //end of file<br /> if((bResult) && (dwRead == 0))<br /> break;<br /> int nSend = Send(socket, buffer, dwRead);<br /> if(nSend < 0)<br /> break;<br /> }<br /> CloseHandle(hFile);<br /> return true;<br /> }<br />#else<br /> char buffer[1025];<br /> int dwRead;<br /> FILE* hFile = NULL;<br /> for(int i = 0; i < 20; i++)<br /> {<br /> hFile = fopen(m_path.c_str(), "rb");<br /> if(hFile)<br /> break;<br /> usleep(200000);<br /> }<br /> if(!hFile)<br /> return false;<br /> else<br /> {<br /> while(!feof(hFile))<br /> {<br /> dwRead = 0;<br /> dwRead = fread(buffer, sizeof(char), 1024, hFile);<br /> //end of file<br /> int nSend = Send(socket, buffer, dwRead);<br /> if(nSend < 0)<br /> break;<br /> }<br /> fclose(hFile);<br /> return true;<br /> }<br />#endif<br />}<br />int IoUtil::Send( SOCKET socket, const char* buffer, UINT len )<br />{<br /> long already_time = 0;<br /> fd_set fdset;<br /> struct timeval timeout;<br /> timeout.tv_sec = SELECT_WAIT_TIME;<br /> timeout.tv_usec = 0;<br /> size_t nSend = 0;<br /> size_t tLen = 0;<br /> while(1)<br /> {<br /> FD_ZERO(&fdset);<br /> FD_SET(socket, &fdset);<br /> int ret = select(socket + 1, NULL, &fdset, NULL, &timeout);<br /> switch(ret)<br /> {<br /> case 1:<br /> already_time = 0;<br /> tLen = send(socket, buffer, len - nSend, 0);<br /> nSend += tLen;<br /> if(nSend == len)<br /> return SOCKET_SENDRECV_OK;<br /> break;<br /> case 0:<br /> already_time += SELECT_WAIT_TIME;<br /> if(already_time >= MAX_WAIT_TIME_FOR_SENDRECV)<br /> {<br /> close(socket);<br /> return SOCKET_SENDRECV_TIMEOUT;<br /> }<br /> break;<br /> default:<br /> return SOCKET_SENDRECV_ERROR;<br /> }<br /> }<br />}<br />
另外附上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