• 广州市第十五届人大常委会会议网络直播 2019-04-20
  • “西瓜足迹”瞎掰与“晒的虚荣” 2019-04-20
  • 习近平两会“典”亮新时代 2019-04-07
  • 中国足球,就是笑博士的“责权利平滑对接”改革的必然结果! 2019-04-03
  • 重庆高校陆续公布招生计划、专业设置情况和新政策 2019-04-03
  • 新时代 新气象 新作为 2019-03-30
  • 《中国地方志佛道教文献汇纂》——开辟佛道教研究新领域 2019-03-29
  • 拉萨市墨竹工卡县全力打造“绿色矿山” 2019-03-29
  • 习近平要求把这项工作作为重大政治任务 2019-03-24
  • 充分发挥重要平台和有效载体作用 以特色小镇建设促进乡村振兴 2019-03-18
  • 脸每天都洗,但你真的洗对了吗? 2019-03-18
  • 港珠澳大桥珠海口岸停车场智慧停车系统启用在即 2019-03-14
  • 以实际行动诠释忠诚 以实干实政维护核心 2019-03-14
  • 天津市津南区严打校园周边“五毛食品” 2019-03-11
  • 设计众议院:新时代消费观念造就的全新第八代凯美瑞 2019-03-11
  • 批处理新手入门导读[视频教程]批处理基础视频教程[视频教程]VBS基础视频教程
    [批处理文件精品]批处理版照片整理器[批处理文件精品]纯批处理备份&还原驱动在线第三方下载
    返回列表 发帖

    广东十一选五倍数:跨平台安全服务器 msp

    本帖最后由 happy886rr 于 2017-8-25 22:51 编辑

    msp安全服务器重构的内核架构,几乎实现了完整的http各类返回值200、404、403、301、304、500、100,包括对多种http请求头If-Modified-Since", "Cache-Control", "Accept-Language", "Connection", "Keep-Alive", "Close", "Timeout的参数支持。增加安全模式、日志打印模式。增加抗DDOS攻击,IP黑名单等智能拉黑技术??缮柚肐P网段限制、各类参数都已开放修改。性能是misv的10倍,可承受15000并发,单日800万次访问量的繁重任务,性能略强于apache,不及nginx水平。但已经达到商用级别。

    msp意在打造安全牢固的web服务器,这是最难被黑客攻破的服务器。对路径渗透,文件渗透都坚决拒之门外。除非你在服务器上操作,否则任何远程操作都无法攻破改服务器的安全壁垒。任何恶意请求,恶意DDOS,瞬间封杀IP,为每个访问的IP建立点击档案,如果被系统认定为黑客行为、或恶意频繁请求,自动永久封禁IP。

    源码发行,跨平台代码,各平台均可编译。推荐使用gcc编译,windows下可用vs编译。
    默认限制IP网段 192.168.0.1~8.可自行修改ip限制范围。
     广东十一选五计划软件 www.qe-ar.com 
    1. /*
    2. WEB SERVER&INTERPRETER, MSP @[email protected]~2019 BY HAPPY, VERSION 1.0
    3. FRI AUG 22 2017 21:10:16 GMT+0800
    4. **********************************************************************
    5. gcc msp.c -lWs2_32  -o msp.exe       REM For Windows
    6. gcc msp.c -lpthread -o msp           REM For Linux
    7. gcc msp.c -o msp                     REM For Android
    8. cl  msp.cpp /MD /Ox /out:msp.exe     REM For VS
    9. **********************************************************************
    10. */
    11. // 服务器模式配置
    12. #define USE_SAFE_MODE           1
    13. #define USE_LOGS_MODE           1
    14. // 服务器参数设置
    15. #define HTTP_SERVER_NAME       "Msp"
    16. #define HTTP_SERVER_PORT        80
    17. #define HTTP_SERVER_ROOT       "www"
    18. #define HTTP_SERVER_PAGE       "index.html"
    19. // 服务器性能配置
    20. #define MAX_BACKLOG_SIZE        1024*4
    21. #define MAX_THREAD_NUMBER       512
    22. #define KEEP_ALIVE_TIMEOUT      3
    23. #define MIN_HTTP_RPS            1
    24. // 服务器建档配置
    25. #define IP_RPS_LEN              1024
    26. #define MAX_REQUESTS_PER_SECOND 128
    27. #define MIN_REQUESTS_PER_SECOND 8
    28. // 服务器静态标量
    29. #define MAX_BUFF_SIZE           1024*4
    30. #define MIN_BUFF_SIZE           1024
    31. #define MAX_PATH_SIZE           1024
    32. #define HTTP_GENERAL_ERROR      1
    33. #define FILE_SEND_ERROR         1
    34. // 服务器网段屏蔽(IP黑名单)
    35. static const char* HTTP_SHILEDING_IPRange[][2] =
    36. {
    37.     {"192.168.0.5", ""},
    38.     {"192.168.0.1", "192.168.0.8"}
    39. };
    40. #if defined(_MSC_VER)
    41. #pragma comment(lib,"Ws2_32.lib")
    42. #else
    43. #include <stdbool.h>
    44. #endif
    45. #if defined(_MSC_VER)
    46. // 定义VS控制台启动方式(对VS编译器,改后缀为.cpp编译时,实现无窗化启动)
    47. #pragma comment(linker, "/subsystem:\"windows\" /entry:\"mainCRTStartup\"")
    48. #endif
    49. #include <stdio.h>
    50. #include <stdlib.h>
    51. #include <string.h>
    52. #include <time.h>
    53. #if defined(WIN32) || defined(_WIN32) || defined(__MINGW32__) || defined(_MSC_VER)
    54. #include <direct.h>
    55. #include <Winsock2.h>
    56. #include <sys\stat.h>
    57. #define HTTP_SERVER_PATHCHARACTER "\\"
    58. #else
    59. #include <sys/socket.h>
    60. #include <sys/types.h>
    61. #include <sys/stat.h>
    62. #include <netinet/in.h>
    63. #include <arpa/inet.h>
    64. #include <pthread.h>
    65. #include <unistd.h>
    66. #define HTTP_SERVER_PATHCHARACTER "/"
    67. #define INVALID_SOCKET -1
    68. #define SOCKET_ERROR -1
    69. typedef int SOCKET;
    70. typedef unsigned long DWORD;
    71. typedef void *LPVOID;
    72. typedef const struct sockaddr *LPSOCKADDR;
    73. #endif
    74. #ifndef NULL
    75. #define NULL (void*)0
    76. #endif
    77. #ifndef byte
    78. typedef unsigned char byte;
    79. #endif
    80. // 跨平台宏函数
    81. #if defined(WIN32) || defined(_WIN32) || defined(__MINGW32__) || defined(_MSC_VER)
    82. #if defined(_MSC_VER)
    83. #define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
    84. #define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
    85. #endif
    86. #define SLEEP(x) Sleep(x)
    87. #define CLOSESOCKET closesocket
    88. #else
    89. #define SLEEP(x) usleep(x*1000)
    90. #define CLOSESOCKET close
    91. #endif
    92. // 判断小写字母宏函数
    93. #define ISLOWERLETTER(x) ('a'<=(x)&&(x)<='z')
    94. // 反转UINT宏函数
    95. #define REVUINT(x) (unsigned int)(((x)&0x000000FF)<<24|((x)&0x0000FF00)<<8|((x)&0x00FF0000)>>8|((x)&0xFF000000)>>24)
    96. // HTTP请求头关键词
    97. static const char* HEADER_KEY_WORDS[] = {"GET", "POST", "HEAD", "EDIT", "If-Modified-Since", "Cache-Control", "Accept-Language", "Connection", "Keep-Alive", "Close", "Timeout", NULL};
    98. #if defined(USE_SAFE_MODE)
    99. // 在开启安全模式下,服务器允许的文件后缀
    100. static const char* HTTP_SAFE_SUFFIX[] = {".html", ".htm", ".shtml", ".css", ".js", ".png", ".jpg", ".jpeg", ".gif", ".svg", ".ico", ".bmp", ".swf", ".mp3", ".wma", ".wav", ".mp4", ".txt", ".xml", ".pdf", ".doc", ".xls", ".ppt", NULL};
    101. static const int   HTTP_SAFE_CTYPEV[] = {      0,      0,        0,      1,     2,      3,      4,       4,      5,      6,      7,     8,       9,     10,     11,     12,     13,     14,     15,     16,     17,     18,     19,    0};
    102. static const char* HTTP_CONTENT_TYPE[] = {"text/html", "text/css", "application/javascript", "image/png", "image/jpeg", "image/gif", "image/svg+xml", "image/x-icon", "application/x-bmp", "application/x-shockwave-flash", "audio/mp3", "audio/x-ms-wma", "audio/wav", "video/mpeg4", "text/plain", "text/xml", "application/pdf", "application/msword", "application/x-xls", "application/x-ppt", NULL};
    103. // 独立IP 建档数组
    104. static unsigned int IPRequestsPerSecond[IP_RPS_LEN][2];
    105. // IPulong辅助数组
    106. static unsigned long HTTP_SHILEDING_IPulongRange[sizeof(HTTP_SHILEDING_IPRange) / sizeof(HTTP_SHILEDING_IPRange[0])][2];
    107. #define SHILEDING_IPRANGE_LEN (sizeof(HTTP_SHILEDING_IPRange)/sizeof(HTTP_SHILEDING_IPRange[0]))
    108. #endif
    109. // 时间戳全局变量
    110. static char nowTime[MIN_BUFF_SIZE];
    111. static const char* timeFormatGMT = "%a, %d %b %Y %H:%M:%S GMT";
    112. // 当前线程数全局变量
    113. static unsigned int nowThreadNumber = 0;
    114. // 定义通用返回页面
    115. static const char responseErrorPage[] =
    116.     "<html>"
    117.     "<head>"
    118.     "</head>"
    119.     "<title>%d %s</title>"
    120.     "<body>"
    121.     "  <h1 align='center'><font color=#FF1493>Sorry,%d Error!</font></h1>"
    122.     "    <script>"
    123.     "      document.write('<hr/>' + '<font color=#9400D3>' + new Date() + '</font>' + '<hr/>' + '<font color=#FF1493>' + 'The %s server responded \"%s\".' + '</font>');"
    124.     "  </script>"
    125.     "</body>"
    126.     "</html>";
    127. // 通用关键词识别函数
    128. int HTTP_IdentifyKey(char* inStr, char** inKeyWords, const char* endChars, int SN)
    129. {
    130.     if (inStr == NULL)
    131.     {
    132.         return -1;
    133.     }
    134.     while(inKeyWords[SN] != NULL)
    135.     {
    136.         char *op=inStr, *kp=inKeyWords[SN];
    137.         while(*kp != '\0')
    138.         {
    139.             if(
    140.                 ((ISLOWERLETTER(*op))?(*op-32):(*op)) != ((ISLOWERLETTER(*kp))?(*kp-32):(*kp))
    141.             )
    142.             {
    143.                 break;
    144.             }
    145.             op++;
    146.             kp++;
    147.         }
    148.         if(*kp == '\0')
    149.         {
    150.             if(*op == '\0')
    151.             {
    152.                 return SN;
    153.             }
    154.             while(*endChars != '\0')
    155.             {
    156.                 if(*op == *(endChars++))
    157.                 {
    158.                     return SN;
    159.                 }
    160.             }
    161.         }
    162.         SN ++;
    163.     }
    164.     return -1;
    165. }
    166. // 错误打印函数
    167. int HTTP_PrintError(char* perr)
    168. {
    169. #if defined(WIN32) || defined(_WIN32) || defined(__MINGW32__) || defined(_MSC_VER)
    170.     fprintf(stderr, "%s: %d\n", perr, WSAGetLastError());
    171. #else
    172.     perror(perr);
    173. #endif
    174.     return 0;
    175. }
    176. // HTTP通用错误报头模板
    177. int HTTP_ResponseGeneral(SOCKET soc, int responseNumber, const char* responseText, int httpMethodValue)
    178. {
    179.     char responseBuf[MIN_BUFF_SIZE];
    180.     sprintf
    181.     (
    182.         responseBuf
    183.         ,
    184.         "HTTP/1.1 %d %s\r\n"
    185.         "Date: %s\r\n"
    186.         "Server: %s\r\n\r\n"
    187.         ,
    188.         responseNumber, responseText, nowTime, HTTP_SERVER_NAME
    189.     );
    190.     send(soc, responseBuf, strlen(responseBuf), 0);
    191.     if (httpMethodValue == 0)
    192.     {
    193.         sprintf
    194.         (
    195.             responseBuf
    196.             ,
    197.             responseErrorPage
    198.             ,
    199.             responseNumber, responseText, responseNumber, HTTP_SERVER_NAME, responseText
    200.         );
    201.         send(soc, responseBuf, strlen(responseBuf), 0);
    202.     }
    203.     return 0;
    204. }
    205. // 发送200 成功报头
    206. int HTTP_Response200(SOCKET soc, int contentLength, int contentTypeValue, bool connectionFlag, const char* serverModifiDateStr)
    207. {
    208.     char responseBuf[MIN_BUFF_SIZE];
    209.     sprintf
    210.     (
    211.         responseBuf
    212.         ,
    213.         "HTTP/1.1 200 OK\r\n"
    214.         "Date: %s\r\n"
    215.         "Server: %s\r\n"
    216.         "Content-Length: %d\r\n"
    217.         "Connection: %s\r\n"
    218.         "Last-Modified: %s\r\n"
    219. #if defined(USE_SAFE_MODE)
    220.         "Content-Type: %s\r\n\r\n"
    221.         ,
    222.         nowTime, HTTP_SERVER_NAME, contentLength, (connectionFlag)?"Keep-Alive":"Close", serverModifiDateStr, HTTP_CONTENT_TYPE[HTTP_SAFE_CTYPEV[contentTypeValue]]
    223. #else
    224.         "Content-Type: text/html\r\n\r\n"
    225.         ,
    226.         nowTime, HTTP_SERVER_NAME, contentLength, (connectionFlag)?"Keep-Alive":"Close", serverModifiDateStr
    227. #endif
    228.     );
    229.     send(soc, responseBuf, strlen(responseBuf), 0);
    230.     return 0;
    231. }
    232. // 发送301 重定向报头
    233. int HTTP_Response301(SOCKET soc, const char* newURL, const char* suffixStr, bool connectionFlag)
    234. {
    235.     char responseBuf[MIN_BUFF_SIZE];
    236.     sprintf
    237.     (
    238.         responseBuf
    239.         ,
    240.         "HTTP/1.1 301 Moved Permanently\r\n"
    241.         "Date: %s\r\n"
    242.         "Server: %s\r\n"
    243.         "Location: %s%s\r\n"
    244.         "Connection: %s\r\n"
    245.         "Content-Type: text/html\r\n\r\n"
    246.         ,
    247.         nowTime, HTTP_SERVER_NAME, newURL, suffixStr, (connectionFlag)?"Keep-Alive":"Close"
    248.     );
    249.     send(soc, responseBuf, strlen(responseBuf), 0);
    250.     return 0;
    251. }
    252. // 发送304 未修改报头
    253. int HTTP_Response304(SOCKET soc, const char* serverModifiDateStr, bool connectionFlag)
    254. {
    255.     char responseBuf[MIN_BUFF_SIZE];
    256.     sprintf
    257.     (
    258.         responseBuf
    259.         ,
    260.         "HTTP/1.1 304 Not Modified\r\n"
    261.         "Date: %s\r\n"
    262.         "Server: %s\r\n"
    263.         "Connection: %s\r\n"
    264.         "Last-Modified: %s\r\n\r\n"
    265.         ,
    266.         nowTime, HTTP_SERVER_NAME,  (connectionFlag)?"Keep-Alive":"Close", serverModifiDateStr
    267.     );
    268.     send(soc, responseBuf, strlen(responseBuf), 0);
    269.     return 0;
    270. }
    271. // 发送请求的资源
    272. int HTTP_SendFile(SOCKET soc, FILE *fp)
    273. {
    274.     // 重置文件流位置
    275.     rewind(fp);
    276.     // 分配数据拾取器
    277.     byte pickUpBuf[MIN_BUFF_SIZE];
    278.     size_t freadSize = 0;
    279.     // 发送文件二进制数据
    280.     while (!feof(fp))
    281.     {
    282.         freadSize = fread(pickUpBuf, sizeof(byte), MIN_BUFF_SIZE, fp);
    283.         if (send(soc, (const char*)pickUpBuf, freadSize, 0) == SOCKET_ERROR)
    284.         {
    285.             return FILE_SEND_ERROR;
    286.         }
    287.     }
    288.     return 0;
    289. }
    290. // 服务器核心函数
    291. DWORD
    292. #if defined(WIN32) || defined(_WIN32) || defined(__MINGW32__) || defined(_MSC_VER)
    293. WINAPI
    294. #endif
    295. HTTP_ServerCore(LPVOID lpvsoc)
    296. {
    297.     // 线程计数器
    298.     nowThreadNumber ++;
    299.     DWORD ret = 0;
    300.     SOCKET soc = (SOCKET)lpvsoc;
    301.     // 是否启用Keep-Alive模式
    302.     bool connectionFlag = true, timeoutAlready = false;
    303.     // 分配接受缓存容器
    304.     char receiveBuf[MIN_BUFF_SIZE];
    305. // 设置Keep-Alive 超时时间
    306. struct timeval timeoutKeepAlive = {KEEP_ALIVE_TIMEOUT, 0};
    307.     // 设置soc超时时间
    308.     setsockopt(soc, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeoutKeepAlive, sizeof(struct timeval));
    309.     while(true)
    310.     {
    311.         // 接受客户端请求
    312.         int receiveCount = recv(soc, receiveBuf, MIN_BUFF_SIZE-1, 0);
    313.         if (receiveCount == SOCKET_ERROR)
    314.         {
    315.             // 发送100报头,客户必须继续发出请求
    316.             HTTP_ResponseGeneral(soc, 100, "Needs Request", 2);
    317.             ret = HTTP_GENERAL_ERROR;
    318.             break;
    319.         }
    320.         else
    321.         {
    322.             // 置结束符 '\0'
    323.             receiveBuf[receiveCount]='\0';
    324.         }
    325.         // 要提取的参数
    326.         int  httpMethodValue = -1;
    327.         char httpURL[MIN_BUFF_SIZE];
    328.         char clientModifiDateStr[MIN_BUFF_SIZE];
    329.         // 字符数组置零
    330.         httpURL[0]='\0', clientModifiDateStr[0]='\0';
    331.         // 解析 HTTP请求头
    332.         int headerKeyBeginIndex = 0;
    333.         char cacheLine[MIN_BUFF_SIZE], *pBuf = receiveBuf, *tPer = NULL;
    334.         while((*pBuf != '\0') && (*pBuf != '\r') && (*pBuf != '\n'))
    335.         {
    336.             char *pLine=(char*)cacheLine;
    337.             while((*pBuf != '\0') && (*pBuf != '\r') && (*pBuf != '\n'))
    338.             {
    339.                 *(pLine ++) = *(pBuf ++);
    340.             }
    341.             // 置结束符
    342.             *pLine = '\0';
    343.             // 过滤尾部"\r\n"
    344.             if (*pBuf=='\r')
    345.             {
    346.                 pBuf ++;
    347.             }
    348.             if (*pBuf=='\n')
    349.             {
    350.                 pBuf ++;
    351.             }
    352.             int headerKeyValue = HTTP_IdentifyKey(cacheLine, (char**)HEADER_KEY_WORDS, ": \t", headerKeyBeginIndex);
    353.             if (headerKeyValue == -1 && headerKeyBeginIndex == 0)
    354.             {
    355.                 // 发送400报头,请求格式错误
    356.                 HTTP_ResponseGeneral(soc, 400, "Bad request", 2);
    357.                 // 释放 套接口,结束连接
    358.                 CLOSESOCKET(soc);
    359.                 nowThreadNumber --;
    360.                 return HTTP_GENERAL_ERROR;
    361.             }
    362.             else if (headerKeyValue < 3 && headerKeyBeginIndex == 0)
    363.             {
    364.                 // 获取HTTP协议值
    365.                 httpMethodValue = headerKeyValue;
    366.                 // 识别到请求协议,则后续比对关键词从第5个关键词开始,
    367.                 headerKeyBeginIndex = 4;
    368.                 // 分离请求的URL
    369.                 strtok(cacheLine, " \t");
    370.                 tPer = strtok(NULL, " \t");
    371.                 if(tPer != NULL)
    372.                 {
    373.                     strcpy(httpURL, tPer);
    374.                 }
    375.                 else
    376.                 {
    377.                     // 发送400报头,请求格式错误
    378.                     HTTP_ResponseGeneral(soc, 400, "Bad request", 2);
    379.                     // 释放套接口,结束连接
    380.                     CLOSESOCKET(soc);
    381.                     nowThreadNumber --;
    382.                     return HTTP_GENERAL_ERROR;
    383.                 }
    384.             }
    385.             else if (headerKeyValue == 4 && headerKeyBeginIndex != 0)
    386.             {
    387.                 tPer = cacheLine;
    388.                 if(*tPer != '\0')
    389.                 {
    390.                     while(*tPer!=':' && *tPer!='\0')
    391.                     {
    392.                         tPer ++;
    393.                     }
    394.                     if(*tPer==':')
    395.                     {
    396.                         tPer ++;
    397.                     }
    398.                     while(*tPer==' ' && *tPer!='\t')
    399.                     {
    400.                         tPer ++;
    401.                     }
    402.                     strcpy(clientModifiDateStr, tPer);
    403.                 }
    404.             }
    405.             else if (headerKeyValue == 7 && headerKeyBeginIndex != 0)
    406.             {
    407.                 tPer = cacheLine;
    408.                 if(*tPer != '\0')
    409.                 {
    410.                     while(*tPer!=':' && *tPer!='\0')
    411.                     {
    412.                         tPer ++;
    413.                     }
    414.                     if(*tPer==':')
    415.                     {
    416.                         tPer ++;
    417.                     }
    418.                     while(*tPer==' ' && *tPer!='\t')
    419.                     {
    420.                         tPer ++;
    421.                     }
    422.                     // 验证Connection: 后边跟的是不是Close
    423.                     if (HTTP_IdentifyKey(tPer, (char**)HEADER_KEY_WORDS, " \t,\0", 9) == 9)
    424.                     {
    425.                         connectionFlag = false;
    426.                     }
    427.                 }
    428.             }
    429.             else if (!timeoutAlready && connectionFlag && headerKeyValue == 8 && headerKeyBeginIndex != 0)
    430.             {
    431.                 tPer = cacheLine;
    432.                 if(*tPer != '\0')
    433.                 {
    434.                     while(*tPer!=':' && *tPer!='\0')
    435.                     {
    436.                         tPer ++;
    437.                     }
    438.                     if(*tPer==':')
    439.                     {
    440.                         tPer ++;
    441.                     }
    442.                     while(*tPer==' ' && *tPer!='\t')
    443.                     {
    444.                         tPer ++;
    445.                     }
    446.                     // 验证Keep-Alive,提取timeout值
    447.                     if (HTTP_IdentifyKey(tPer, (char**)HEADER_KEY_WORDS, " \t=", 10) == 10)
    448.                     {
    449.                         while(*tPer!='=' && *tPer!='\0')
    450.                         {
    451.                             tPer ++;
    452.                         }
    453.                         if(*tPer == '=')
    454.                         {
    455.                             // 设置Keep-Alive超时时间,不得大于KEEP_ALIVE_TIMEOUT
    456.                             timeoutKeepAlive.tv_sec = atoi(++ tPer) % KEEP_ALIVE_TIMEOUT;
    457.                             // 设置soc超时时间
    458.                             setsockopt(soc, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeoutKeepAlive, sizeof(struct timeval));
    459.                            
    460.                             //设置布尔标记
    461.                             timeoutAlready = true;
    462.                         }
    463.                     }
    464.                 }
    465.             }
    466.         }
    467.         // 置换指针
    468.         char* httpFilePath = (char*)httpURL;
    469.         char* p = httpFilePath;
    470. #if defined(USE_SAFE_MODE) || defined(WIN32) || defined(_WIN32) || defined(__MINGW32__) || defined(_MSC_VER)
    471.         while (*p != '\0')
    472.         {
    473. #if defined(USE_SAFE_MODE)
    474.             if (*p == '.' && *(p+1) == '.')
    475.             {
    476.                 // 发送403报头 服务器拒绝目录渗透
    477.                 HTTP_ResponseGeneral(soc, 403, "Forbidden Directory Penetration", httpMethodValue);
    478.                 // 释放 套接口,结束连接
    479.                 CLOSESOCKET(soc);
    480.                 nowThreadNumber --;
    481.                 return HTTP_GENERAL_ERROR;
    482.             }
    483. #endif
    484. #if defined(WIN32) || defined(_WIN32) || defined(__MINGW32__) || defined(_MSC_VER)
    485.             if (*p == '/')
    486.             {
    487.                 *p = (HTTP_SERVER_PATHCHARACTER)[0];
    488.             }
    489. #endif
    490.             p++;
    491.         }
    492. #endif
    493.         // 拼接 请求文件路径
    494.         char requestFilePath[MAX_PATH_SIZE];
    495.         sprintf
    496.         (
    497.             requestFilePath
    498.             ,
    499.             "%s%s%s%s%s"
    500.             ,
    501.             ".", HTTP_SERVER_PATHCHARACTER, HTTP_SERVER_ROOT, HTTP_SERVER_PATHCHARACTER, httpFilePath
    502.         );
    503.         // 对目录请求,则在路径之后追加默认主页(index.html)
    504. #if defined(USE_SAFE_MODE) || defined(WIN32) || defined(_WIN32) || defined(__MINGW32__) || defined(_MSC_VER)
    505.         if(*(p-1) == (HTTP_SERVER_PATHCHARACTER)[0])
    506.         {
    507. #else
    508.         if(*(requestFilePath + strlen(requestFilePath) -1) == (HTTP_SERVER_PATHCHARACTER)[0])
    509.         {
    510. #endif
    511.             strcat(requestFilePath, HTTP_SERVER_PAGE);
    512.         }
    513.         // 获取URI在服务器上的对应文件信息
    514.         struct stat fileStatBuf;
    515.         int rStat = stat(requestFilePath, &fileStatBuf);
    516.         // 如果请求的是目录
    517.         if (rStat == 0 && S_ISDIR(fileStatBuf.st_mode))
    518.         {
    519.             // 页面重定向到目录默认主页
    520.             HTTP_Response301(soc, (const char*)httpURL, "/", connectionFlag);
    521.             // 如果是Connection: close模式
    522.             if (connectionFlag == false)
    523.             {
    524.                 break;
    525.             }
    526.             continue;
    527.         }
    528.         // 声明 文件类型值变量
    529.         int contentTypeValue = 0;
    530. #if defined(USE_SAFE_MODE)
    531.         // 获取文件后缀
    532.         char* pSuffix = strrchr(requestFilePath, '.');
    533.         // 根据文件后缀 获取文件类型值
    534.         contentTypeValue = HTTP_IdentifyKey(pSuffix, (char**)HTTP_SAFE_SUFFIX, "\0", 0);
    535.         // 过滤文件类型,对非授权的文件格式禁止发送,以保证服务器资料安全
    536.         if (contentTypeValue == -1)
    537.         {
    538.             // 发送403报头 服务器拒绝请求该文件
    539.             HTTP_ResponseGeneral(soc, 403, "Forbidden", httpMethodValue);
    540.             // 结束连接
    541.             ret = HTTP_GENERAL_ERROR;
    542.             break;
    543.         }
    544. #endif
    545.         // 客户端缓存方案
    546.         char* serverModifiDateStr = nowTime;
    547.         // 如果请求的是文件
    548.         if (rStat == 0 && S_ISREG(fileStatBuf.st_mode))
    549.         {
    550.             char tmpModifiDate[MIN_BUFF_SIZE];
    551.             strftime(tmpModifiDate, sizeof(tmpModifiDate), timeFormatGMT, gmtime(&fileStatBuf.st_mtime));
    552.             serverModifiDateStr = (char*)tmpModifiDate;
    553.             // 比对客户端时间戳 与 服务器最后修改的时间戳
    554.             if(strcmp(clientModifiDateStr, serverModifiDateStr) == 0)
    555.             {
    556.                 // 如果时间戳一致,返回304未修改报头
    557.                 HTTP_Response304(soc, clientModifiDateStr, connectionFlag);
    558.                 // 如果是Connection: close模式
    559.                 if (connectionFlag == false)
    560.                 {
    561.                     break;
    562.                 }
    563.                 continue;
    564.             }
    565.         }
    566.         // 以二进制方式 打开服务器上被请求的文件
    567.         FILE* fp = fopen(requestFilePath, "rb");
    568.         // 如果 读取文件失败
    569.         if (fp == NULL)
    570.         {
    571.             // 发送404报头 找不到文件
    572.             HTTP_ResponseGeneral(soc, 404, "Not Found", httpMethodValue);
    573.             // 执行跳转,关闭连接
    574.             ret = HTTP_GENERAL_ERROR;
    575.             break;
    576.         }
    577.         // 提取要请求的文件长度
    578.         int fpSize = fileStatBuf.st_size;
    579.         // 发送200报头
    580.         HTTP_Response200(soc, fpSize, contentTypeValue, connectionFlag, serverModifiDateStr);
    581.         // 如果是GET方法则发送请求的资源
    582.         if (httpMethodValue == 0)
    583.         {
    584.             if (HTTP_SendFile(soc, fp) == FILE_SEND_ERROR)
    585.             {
    586.                 // 发送500报头,服务器内部错误
    587.                 // HTTP_ResponseGeneral(soc, 500, "Server Read Error", httpMethodValue);
    588.             }
    589.         }
    590.         // 释放文件流
    591.         fclose(fp);
    592. // 针对安卓非阻塞套接字,直接断开连接
    593. #if defined(ANDROID) || defined(_ANDROID) || defined(__ANDROID__)
    594.         break;
    595. #endif
    596.     }
    597.     // 释放 套接口
    598.     CLOSESOCKET(soc);
    599.     nowThreadNumber --;
    600.     return ret;
    601. }
    602. #if defined(USE_SAFE_MODE)
    603. // IPulong 初始化函数
    604. int initHTTP_SHILEDING_IPulongRange()
    605. {
    606.     // 转屏蔽网段为 ulong
    607.     struct in_addr tmpIPaddr;
    608.     unsigned int ulongTmp;
    609.     int i;
    610.     for(i=0; i<SHILEDING_IPRANGE_LEN; i++)
    611.     {
    612.         if(HTTP_SHILEDING_IPRange[i][0] == NULL)
    613.         {
    614.             return HTTP_GENERAL_ERROR;
    615.         }
    616.         tmpIPaddr.s_addr = inet_addr(HTTP_SHILEDING_IPRange[i][0]);
    617.         if (tmpIPaddr.s_addr == INADDR_NONE)
    618.         {
    619.             return HTTP_GENERAL_ERROR;
    620.         }
    621.         HTTP_SHILEDING_IPulongRange[i][0] = REVUINT(tmpIPaddr.s_addr);
    622.         if(*(HTTP_SHILEDING_IPRange[i][1]) == '\0')
    623.         {
    624.             HTTP_SHILEDING_IPulongRange[i][1] = 0;
    625.         }
    626.         else
    627.         {
    628.             tmpIPaddr.s_addr = inet_addr(HTTP_SHILEDING_IPRange[i][1]);
    629.             if
    630.             (
    631.                 tmpIPaddr.s_addr == INADDR_NONE ||
    632.                 HTTP_SHILEDING_IPulongRange[i][0] > REVUINT(tmpIPaddr.s_addr)
    633.             )
    634.             {
    635.                 return HTTP_GENERAL_ERROR;
    636.             }
    637.             HTTP_SHILEDING_IPulongRange[i][1] = REVUINT(tmpIPaddr.s_addr);
    638.         }
    639.     }
    640.     return 0;
    641. }
    642. // 检测IP是否包含在 IPulong数组值域内
    643. bool isBelongHTTP_SHILEDING_IPulongRange(unsigned long clientIPulong)
    644. {
    645.     int i;
    646.     for(i=0; i<SHILEDING_IPRANGE_LEN; i++)
    647.     {
    648.         if
    649.         (
    650.             (
    651.                 HTTP_SHILEDING_IPulongRange[i][1] == 0              &&
    652.                 clientIPulong == HTTP_SHILEDING_IPulongRange[i][0]
    653.             ) ||
    654.             (
    655.                 HTTP_SHILEDING_IPulongRange[i][0] <= clientIPulong  &&
    656.                 clientIPulong <= HTTP_SHILEDING_IPulongRange[i][1]
    657.             )
    658.         )
    659.         {
    660.             return true;
    661.         }
    662.     }
    663.     return false;
    664. }
    665. #endif
    666. // MAIN主函数
    667. int main()
    668. {
    669.     // 主程序返回值
    670.     int ret = 0;
    671.     // 获取服务器 当地时间
    672.     time_t timeServerStart = time((time_t*)0);
    673.     strcpy(nowTime, ctime(&timeServerStart));
    674.     // 显示 标头信息
    675.     fprintf
    676.     (
    677.         stdout,
    678.         "%s"
    679.         "[===* Welcome to use %s *===]\n"
    680.         "[>>>]\n"
    681.         ,
    682.         nowTime, HTTP_SERVER_NAME
    683.     );
    684. #if defined(USE_SAFE_MODE)
    685.     // 初始化 IPulong数组
    686.     if (initHTTP_SHILEDING_IPulongRange() == HTTP_GENERAL_ERROR)
    687.     {
    688.         fprintf(stdout, "Failed to init shileding IP\n");
    689.         ret = HTTP_GENERAL_ERROR;
    690.         return ret;
    691.     }
    692. #endif
    693. #if defined(USE_LOGS_MODE)
    694.     // 追加日志文件
    695.     FILE* fp = fopen("." HTTP_SERVER_PATHCHARACTER "server" ".log", "a");
    696.     if (fp == NULL)
    697.     {
    698.         fprintf(stdout, "Failed to create server log\n");
    699.         ret = HTTP_GENERAL_ERROR;
    700.         return ret;
    701.     }
    702.     unsigned long preClientSockS_addr = 0;
    703.     time_t preClientSockVistTime = 0;
    704. #endif
    705. #if defined(WIN32) || defined(_WIN32) || defined(__MINGW32__) || defined(_MSC_VER)
    706.     // 启动 安全套接字
    707.     WSADATA wsaData;
    708.     if (WSAStartup(MAKEWORD(2,2), &wsaData) != 0)
    709.     {
    710.         fprintf(stdout, "Failed to create win socket\n");
    711.         ret = HTTP_GENERAL_ERROR;
    712.         goto MAIN_END3;
    713.     }
    714. #endif
    715.     // 创建 监听套接口
    716.     SOCKET socListen;
    717.     socListen = socket(AF_INET, SOCK_STREAM, 0);
    718.     if(socListen == INVALID_SOCKET)
    719.     {
    720.         HTTP_PrintError("Creat listen socket failed");
    721.         ret = HTTP_GENERAL_ERROR;
    722.         goto MAIN_END2;
    723.     }
    724.     // 声明 服务器地址,客户端地址
    725.     struct sockaddr_in serverSockaddrIn, clientSockaddrIn;
    726.     int clientSockaddrInLen = sizeof(clientSockaddrIn);
    727.     // 配置 服务器信息
    728.     serverSockaddrIn.sin_family      = AF_INET;
    729.     serverSockaddrIn.sin_port        = htons(HTTP_SERVER_PORT);
    730.     serverSockaddrIn.sin_addr.s_addr = htonl(INADDR_ANY);
    731.     // 绑定 监听套接口 与 服务器地址
    732.     if (bind(socListen, (LPSOCKADDR)&serverSockaddrIn, sizeof(serverSockaddrIn)) == SOCKET_ERROR)
    733.     {
    734.         HTTP_PrintError("Blind server failed");
    735.         ret = HTTP_GENERAL_ERROR;
    736.         goto MAIN_END1;
    737.     }
    738.     // 通过 监听套接口监听
    739.     if (listen(socListen, MAX_BACKLOG_SIZE) == SOCKET_ERROR)
    740.     {
    741.         HTTP_PrintError("Listen socket failed");
    742.         ret = HTTP_GENERAL_ERROR;
    743.         goto MAIN_END1;
    744.     }
    745. #if defined(USE_SAFE_MODE) || defined(ANDROID) || defined(_ANDROID) || defined(__ANDROID__)
    746.     // 声明 计时器变量
    747.     clock_t preClock = clock();
    748.     int countTimes = 0;
    749.     int requestsPerSecond = 0;
    750. #endif
    751. #if defined(USE_LOGS_MODE)
    752.     // 打印启动日志
    753.     fprintf(fp, "[*]Server start at %s", nowTime);
    754.     fflush(fp);
    755. #endif
    756.     // 监听 网页资源请求
    757.     while(true)
    758.     {
    759. #if defined(USE_SAFE_MODE)
    760.         // 智能休眠,均衡线程
    761.         while(nowThreadNumber > MAX_THREAD_NUMBER)
    762.         {
    763.             SLEEP(1);
    764.         }
    765. #endif
    766.         // 建立客户连接套接口
    767.         SOCKET soc = accept(socListen, (struct sockaddr*)&clientSockaddrIn, &clientSockaddrInLen);
    768.         if (soc == INVALID_SOCKET)
    769.         {
    770.             HTTP_PrintError("Accept client failed");
    771.             // 防止恶意发包占用CPU
    772.             SLEEP(1);
    773.             continue;
    774.         }
    775.         // 更新时间戳
    776.         time_t timeNow = time((time_t*)0);
    777.         strftime(nowTime, sizeof(nowTime), timeFormatGMT, gmtime(&timeNow));
    778. #if defined(USE_SAFE_MODE)
    779.         // 为独立IP建档
    780.         bool alreadyFindClientIP = false, allowAcceptSocket = true, isBetterMarkI = false;
    781.         int i, markI=-1;
    782.         for(i=IP_RPS_LEN-1; i; i--)
    783.         {
    784.             if
    785.             (
    786.                 (markI == -1           && IPRequestsPerSecond[i][1] < MIN_REQUESTS_PER_SECOND) ||
    787.                 (isBetterMarkI = false && IPRequestsPerSecond[i][1] ==0)
    788.             )
    789.             {
    790.                 if (IPRequestsPerSecond[i][1] == 0)
    791.                 {
    792.                     isBetterMarkI = true;
    793.                 }
    794.                 markI = i;
    795.             }
    796.             if (IPRequestsPerSecond[i][0] == clientSockaddrIn.sin_addr.s_addr)
    797.             {
    798.                 alreadyFindClientIP = true;
    799.                 if (IPRequestsPerSecond[i][1] > MAX_REQUESTS_PER_SECOND)
    800.                 {
    801.                     allowAcceptSocket = false;
    802.                     if (IPRequestsPerSecond[i][1] != 0xFFFFFFFF)
    803.                     {
    804.                         IPRequestsPerSecond[i][1] = 0xFFFFFFFF;
    805. #if defined(USE_LOGS_MODE)
    806.                         // 打印黑名单日志
    807.                         fprintf(fp, "[%s] [Blacklist user: %s]\n", nowTime, inet_ntoa(clientSockaddrIn.sin_addr));
    808.                         fflush(fp);
    809. #endif
    810.                     }
    811.                 }
    812.                 else
    813.                 {
    814.                     IPRequestsPerSecond[i][1] ++;
    815.                 }
    816.                 break;
    817.             }
    818.         }
    819.         // 如果没有该IP记录,则可能覆盖之前的用户并为其建立档案
    820.         if((! alreadyFindClientIP) && (markI != -1))
    821.         {
    822.             IPRequestsPerSecond[markI][0] = clientSockaddrIn.sin_addr.s_addr;
    823.             IPRequestsPerSecond[markI][1] = 1;
    824.         }
    825.         // 判断该IP是否属于限制级IP
    826.         if
    827.         (
    828.             isBelongHTTP_SHILEDING_IPulongRange(REVUINT(clientSockaddrIn.sin_addr.s_addr)) ||
    829.             allowAcceptSocket == false
    830.         )
    831.         {
    832.             // 对于限制级IP网段,或恶意DDOS客户端,直接断开连接,不予提供服务
    833.             CLOSESOCKET(soc);
    834.             continue;
    835.         }
    836. #endif
    837. #if defined(USE_LOGS_MODE)
    838.         if
    839.         (
    840.             preClientSockS_addr   != clientSockaddrIn.sin_addr.s_addr ||
    841.             preClientSockVistTime != timeNow
    842.         )
    843.         {
    844.             preClientSockS_addr    = clientSockaddrIn.sin_addr.s_addr;
    845.             preClientSockVistTime  = timeNow;
    846.             // 打印服务器日志
    847.             fprintf(fp, "[%s] [Client: %s]\n", nowTime, inet_ntoa(clientSockaddrIn.sin_addr));
    848.             fflush(fp);
    849.         }
    850. #endif
    851. #if defined(WIN32) || defined(_WIN32) || defined(__MINGW32__) || defined(_MSC_VER)
    852.         // 创建请求线程
    853.         DWORD threadID;
    854.         CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)HTTP_ServerCore, (LPVOID)soc, 0, &threadID);
    855. #else
    856.         pthread_t newPthreadT;
    857.         pthread_create(&newPthreadT, NULL, (void*)HTTP_ServerCore, (void*)(intptr_t)soc);
    858. #endif
    859. #if defined(USE_SAFE_MODE) || defined(ANDROID) || defined(_ANDROID) || defined(__ANDROID__)
    860.         // 计次器
    861.         countTimes ++;
    862.         // 每隔秒检测一次服务器冲击量
    863.         if (clock()-preClock > CLOCKS_PER_SEC*0.618)
    864.         {
    865.             requestsPerSecond = CLOCKS_PER_SEC * countTimes / (clock()-preClock);
    866.             countTimes = 0;
    867.             preClock = clock();
    868. #if defined(USE_SAFE_MODE)
    869.             // 部分重置IP_RPS数组
    870.             for(i=IP_RPS_LEN-1; i; i--)
    871.             {
    872.                 if (IPRequestsPerSecond[i][1] <= MAX_REQUESTS_PER_SECOND)
    873.                 {
    874.                     IPRequestsPerSecond[i][1] = 0;
    875.                 }
    876.             }
    877. #endif
    878.         }
    879. // 针对安卓非阻塞休眠优化
    880. #if defined(ANDROID) || defined(_ANDROID) || defined(__ANDROID__)
    881.         // 如果冲击量过小,则休眠CPU
    882.         if (requestsPerSecond < MIN_HTTP_RPS)
    883.         {
    884.             SLEEP(3);
    885.         }
    886. #endif
    887. #endif
    888.     }
    889. MAIN_END1:
    890.     // 关闭监听套接口
    891.     CLOSESOCKET(socListen);
    892. MAIN_END2:
    893. #if defined(WIN32) || defined(_WIN32) || defined(__MINGW32__) || defined(_MSC_VER)
    894.     // 关闭安全套接字
    895.     WSACleanup();
    896. #endif
    897. MAIN_END3:
    898. #if defined(USE_LOGS_MODE)
    899.     // 关闭日志输出
    900.     fclose(fp);
    901. #endif
    902.     return ret;
    903. }
    复制代码
    2

    评分人数

    性能是misv的10倍,可承受15000并发,单日800万次访问量的繁重任务,性能略强于apache,不及nginx水平。

    对这部分感兴趣,能否把你的测试环境、测试工具、测试数据详细介绍一下?
    【扫描二维码捐助论坛的朋友请留言注明论坛账号】//bbs.bathome.net/thread-10403-1-1.html
    【批处理在线视频分享】//bbs.bathome.net/thread-31727-1-1.html
    【微信公众号、微信群、QQ群】//bbs.bathome.net/thread-3473-1-1.html

    TOP

    本帖最后由 happy886rr 于 2017-8-26 18:53 编辑

    回复 2# Batcher

    前辈,我在windows下做了测试,用ab软件跑了结果,msp服务器存放的是一个2M的婚纱网站。针对这个网站做1万5并发,10万次请求(仅一个请求失败,其余全部成功)。测试结果如下:
    1. 测试环境: 赛扬g550 2.1GHz
    2. Server Software:        Msp
    3. Server Hostname:        192.168.1.4
    4. Server Port:            80
    5. Document Path:          /index.html
    6. Document Length:        3227 bytes
    7. Concurrency Level:      15000
    8. Time taken for tests:   148.963 seconds
    9. Complete requests:      100000
    10. Failed requests:        1
    11.    (Connect: 0, Receive: 0, Length: 1, Exceptions: 0)
    12. Total transferred:      341299896 bytes
    13. HTML transferred:       322699954 bytes
    14. Requests per second:    671.31 [#/sec] (mean)
    15. Time per request:       22344.410 [ms] (mean)
    16. Time per request:       1.490 [ms] (mean, across all concurrent requests)
    17. Transfer rate:          2237.48 [Kbytes/sec] received
    18. Connection Times (ms)
    19.               min  mean[+/-sd] median   max
    20. Connect:        0    1  17.0      0     598
    21. Processing:  3570 20891 3865.4  22222   23293
    22. Waiting:     1175 10966 5642.1  11007   21571
    23. Total:       3585 20892 3865.4  22223   23294
    24. Percentage of the requests served within a certain time (ms)
    25.   50%  22223
    26.   66%  22315
    27.   75%  22542
    28.   80%  22584
    29.   90%  22747
    30.   95%  22804
    31.   98%  22860
    32.   99%  23078
    33. 100%  23294 (longest request)
    复制代码
    备注:这是在关闭服务器安全防御下才能测试的。因为服务器代码默认会对每个访问IP建立档案,发现恶意刷流量、DDOS都将主动拉黑。在开启安全模式下,任何测试软件都会被瞬间识别出来,并禁封IP。
    要是添加php的支持,解析速度还会更慢。单日1000万次的访问,完全没问题,另外手机上的性能也不错可以达到PC端性能的50%。
    默认是阉割了post方法,任何上传都会被禁止,服务器设置的安全文件类型才能被访问。

    TOP

    回复 3# happy886rr


        相同环境下Apache和Nginx的测试数据有吗?
    【扫描二维码捐助论坛的朋友请留言注明论坛账号】//bbs.bathome.net/thread-10403-1-1.html
    【批处理在线视频分享】//bbs.bathome.net/thread-31727-1-1.html
    【微信公众号、微信群、QQ群】//bbs.bathome.net/thread-3473-1-1.html

    TOP

    本帖最后由 happy886rr 于 2017-8-27 11:31 编辑

    回复 4# Batcher

    相同环境下Apache直接奔溃,因为windows下的apache根本承受不了1万5并发,这个已经远超apache的负载能力。nginx勉强能经得住1万5的并发,再多也会不干。而msp测试过2万并发,依然完成,因为msp不做任何限制,允许cpu接近100%工作,当然这只是低端双核处理器上的测试结果。
    以下为nginx的测试结果:
    1. Server Software:        nginx/1.13.4
    2. Server Hostname:        192.168.1.4
    3. Server Port:            80
    4. Document Path:          /index.html
    5. Document Length:        3152 bytes
    6. Concurrency Level:      15000
    7. Time taken for tests:   116.318 seconds
    8. Complete requests:      100000
    9. Failed requests:        0
    10. Total transferred:      338600000 bytes
    11. HTML transferred:       315200000 bytes
    12. Requests per second:    859.71 [#/sec] (mean)
    13. Time per request:       17447.737 [ms] (mean)
    14. Time per request:       1.163 [ms] (mean, across all concurrent requests)
    15. Transfer rate:          2842.75 [Kbytes/sec] received
    16. Connection Times (ms)
    17.               min  mean[+/-sd] median   max
    18. Connect:        0    1  11.5      0     601
    19. Processing:  3465 15650 3603.8  15525   25104
    20. Waiting:     1123 8637 4837.5   8219   23743
    21. Total:       3465 15651 3604.1  15525   25104
    22. Percentage of the requests served within a certain time (ms)
    23.   50%  15525
    24.   66%  16639
    25.   75%  16766
    26.   80%  17133
    27.   90%  19160
    28.   95%  22655
    29.   98%  24098
    30.   99%  24652
    31. 100%  25104 (longest request)
    复制代码

    TOP

    回复 5# happy886rr


        确实,Windows里面Apache和Nginx的性能比Linux差很多。
    【扫描二维码捐助论坛的朋友请留言注明论坛账号】//bbs.bathome.net/thread-10403-1-1.html
    【批处理在线视频分享】//bbs.bathome.net/thread-31727-1-1.html
    【微信公众号、微信群、QQ群】//bbs.bathome.net/thread-3473-1-1.html

    TOP

    本帖最后由 xxbdh 于 2017-8-31 16:46 编辑

    简单测试了一下
    URL不支持带空格或者中文等多字节字符
    应该是需要增加UTF8的识别
    另外日志里最好加上request与reponse的摘要信息

    TOP

    回复 7# xxbdh
    建议不错,下次更新时可以添加。

    TOP

    本帖最后由 freesoft00 于 2017-11-6 21:10 编辑

    回复 8# happy886rr


    这个是否可以再增加些功能。
    例如,windows下面,运行可以生成二维码,手机扫描直接连接。
    手机中可以创建无线热点,电脑连接热点,可以互传文件。
    吾爱破解的几个网友做的:
    https://www.52pojie.cn/thread-624702-1-1.html
    https://www.52pojie.cn/thread-605649-1-1.html
    https://www.52pojie.cn/thread-598043-1-1.html
    还有一些手机app也做的不错的。
    AirMore
    AirDroid

    TOP

    回复 9# freesoft00
    可以是可以,但是C语言太底层了,用C写比较累,需要很多代码才能实现。

    TOP

    回复 10# happy886rr


    安卓系统的还有一个Send Anywhere
    我测试使用过的就这么几个。
    主要就是局域网设备间互传文件。
    多谢回复!
    你看吧??茨愕母鋈耸奔浜途?。

    TOP

    可惜不支持asp, php
    我有支持这些脚本的, 跨平台服务器代码.

    TOP

    返回列表
  • 广州市第十五届人大常委会会议网络直播 2019-04-20
  • “西瓜足迹”瞎掰与“晒的虚荣” 2019-04-20
  • 习近平两会“典”亮新时代 2019-04-07
  • 中国足球,就是笑博士的“责权利平滑对接”改革的必然结果! 2019-04-03
  • 重庆高校陆续公布招生计划、专业设置情况和新政策 2019-04-03
  • 新时代 新气象 新作为 2019-03-30
  • 《中国地方志佛道教文献汇纂》——开辟佛道教研究新领域 2019-03-29
  • 拉萨市墨竹工卡县全力打造“绿色矿山” 2019-03-29
  • 习近平要求把这项工作作为重大政治任务 2019-03-24
  • 充分发挥重要平台和有效载体作用 以特色小镇建设促进乡村振兴 2019-03-18
  • 脸每天都洗,但你真的洗对了吗? 2019-03-18
  • 港珠澳大桥珠海口岸停车场智慧停车系统启用在即 2019-03-14
  • 以实际行动诠释忠诚 以实干实政维护核心 2019-03-14
  • 天津市津南区严打校园周边“五毛食品” 2019-03-11
  • 设计众议院:新时代消费观念造就的全新第八代凯美瑞 2019-03-11