工作流程:

1>服务器启动,在指定端口或随机选取端口绑定httpd服务。

2>收到一个http请求时(其实就是listen端口accept的时候),派生一个线程运行accept_request函数。

3>取出http请求中method(get或post)和url,对于get方法,如果有携带参数,则query_string指针指向url中?后面的get参数。

4>格式化url到path数组,表示浏览器请求的文件路径,在tinyhttpd中服务器文件是在htdocs文件夹下。当url以/结尾,或者url是个目录,则默认在path中加上index.thml,表示访问主页。

5>如果文件路径合法,对于无参数的get请求,直接输出服务器文件到浏览器,即用http格式写到套接字上,跳到(10)。其他情况(带参数get,post方法,url为科执行文件),则调用execute_cgi函数执行cgi脚本。

6>读取整个http请求并丢弃,如果是post则找出content-length,把http状态码200写到套接字里面。

7>建立两个管道,cgi_input和cgi_output,并fork一个子进程。

8>在子进程中,把stdout重定向到cgi_output的写入端,把stdin重定向到cgi_input的读取端,关闭cgi_input的写入端和cgi_output的读取端,是指request_method的环境变量,get的话设置query_string的环境变量,post的话设置content-length的环境变量,这些环境变量都是为了给cgi脚本调用,接着用execl运行cgi程序。

9>在父进程中,关闭cgi_input的读取端和cgi_output的写入端,如果post的话,把post数据写入到cgo_input,已被重定向到stdin读取cgi_output的管道输出到客户端,等待子进程结束。

10>关闭与浏览器的链接,完成一次http请求与回应,因为http是无连接的。

  1. /* J. David's webserver */
  2. /* This is a simple webserver.
  3. * Created November 1999 by J. David Blackstone.
  4. * CSE 4344 (Network concepts), Prof. Zeigler
  5. * University of Texas at Arlington
  6. */
  7. /* This program compiles for Sparc Solaris 2.6.
  8. * To compile for Linux:
  9. * 1) Comment out the #include <pthread.h> line.
  10. * 2) Comment out the line that defines the variable newthread.
  11. * 3) Comment out the two lines that run pthread_create().
  12. * 4) Uncomment the line that runs accept_request().
  13. * 5) Remove -lsocket from the Makefile.
  14. */
  15. #include <stdio.h>
  16. #include <sys/socket.h>
  17. #include <sys/types.h>
  18. #include <netinet/in.h>
  19. #include <arpa/inet.h>
  20. #include <unistd.h>
  21. #include <ctype.h>
  22. #include <strings.h>
  23. #include <string.h>
  24. #include <sys/stat.h>
  25. #include <pthread.h>
  26. #include <sys/wait.h>
  27. #include <stdlib.h>
  28.  
  29. #define ISspace(x) isspace((int)(x))
  30.  
  31. #define SERVER_STRING "Server: jdbhttpd/0.1.0\r\n"
  32.  
  33. void accept_request(int);
  34. //处理从套接字上监听到的一个HTTP请求,在这里可以很大一部分的体现服务器处理请求的流程
  35. void bad_request(int);
  36. //返回给客户端这是个错误请求,HTTP状态码是400 BAD REQUEST
  37. void cat(int, FILE *);
  38. //读取服务器上某个文件写到socket套接字
  39. void cannot_execute(int);
  40. //主要执行在处理cgi程序的处理,也是个主要函数
  41. void error_die(const char *);
  42. //把错误信息写到perror并退出
  43. void execute_cgi(int, const char *, const char *, const char *);
  44. //运行cgi程序的处理,也是哥主函数
  45. int get_line(int, char *, int);
  46. //读取套接字的一行,把回车换行等情况都统一为换行符结束
  47. void headers(int, const char *);
  48. //把HTTP相应头写到套接字
  49. void not_found(int);
  50. //主要处理找不到请求的文件时的情况
  51. void serve_file(int, const char *);
  52. //调用cat把服务器文件返回给浏览器
  53. int startup(u_short *);
  54. //初始化httpd服务,包括建立套接字,绑定端口,进行监听等
  55. void unimplemented(int);
  56. //返回给浏览器表示接收到的http请求所用的method不被支持
  57.  
  58. /**********************************************************************/
  59. /* A request has caused a call to accept() on the server port to
  60. * return. Process the request appropriately.
  61. * Parameters: the socket connected to the client */
  62. /**********************************************************************/
  63. void accept_request(int client)
  64. {
  65.  
  66. char buf[];
  67. int numchars;
  68. char method[];
  69. char url[];
  70. char path[];
  71. size_t i, j;
  72. struct stat st;
  73. int cgi = ; /* becomes true if server decides this is a CGI
  74. * program */
  75. char *query_string = NULL;
  76.  
  77. numchars = get_line(client, buf, sizeof(buf));
  78. //读取 client端发送的数据并且 返回的参数是 numchars
  79. i = ;
  80. j = ;
  81. while (!ISspace(buf[j]) && (i < sizeof(method) - ))
  82. {
  83. method[i] = buf[j];
  84. i++;
  85. j++;
  86. }
  87. //得到传递的参数是post 还是get方法 还是其他
  88. method[i] = '\0';
  89.  
  90. if (strcasecmp(method, "GET") && strcasecmp(method, "POST"))
  91. {
  92. //回给浏览器表明收到的 HTTP 请求所用的 method 不被支持
  93. unimplemented(client);
  94. return;
  95. }
  96.  
  97. if (strcasecmp(method, "POST") == )
  98. cgi = ;
  99.  
  100. i = ;
  101. //http请求行格式是 method urI http-version
  102. while (ISspace(buf[j]) && (j < sizeof(buf)))
  103. j++;
  104. while (!ISspace(buf[j]) && (i < sizeof(url) - ) && (j < sizeof(buf)))
  105. {
  106. url[i] = buf[j]; //包含请求行中的URI
  107. i++;
  108. j++;
  109. }
  110. url[i] = '\0';
  111. ///获取发送数据中的URI
  112. if (strcasecmp(method, "GET") == )
  113. {
  114. //get方法 是将参数传递在URI中的?后面如果元素多用&进行链接
  115. query_string = url;
  116. while ((*query_string != '?') && (*query_string != '\0'))
  117. query_string++;
  118. // get 请求? 后面为参数
  119. if (*query_string == '?')
  120. {
  121. cgi = ;
  122. *query_string = '\0';
  123. query_string++;
  124. }
  125. }
  126. //格式url存储在path数组 并且html存储在 htdocs文件中
  127. sprintf(path, "htdocs%s", url);
  128. if (path[strlen(path) - ] == '/')
  129. strcat(path, "index.html"); //字符串进行衔接 + index.html
  130. //stat函数 根据path路径 获取文件内容 存储在 st 结构体中 成功返回0 错误返回-1
  131. if (stat(path, &st) == -)
  132. {
  133. while ((numchars > ) && strcmp("\n", buf)) /* read & discard headers */
  134. numchars = get_line(client, buf, sizeof(buf));
  135. not_found(client);
  136. }
  137. else
  138. {
  139. if ((st.st_mode & S_IFMT) == S_IFDIR)
  140. strcat(path, "/index.html");
  141. //文件的权限 属主 属组 其它 三种任一个拥有执行权
  142. if ((st.st_mode & S_IXUSR) ||
  143. (st.st_mode & S_IXGRP) ||
  144. (st.st_mode & S_IXOTH) )
  145. cgi = ;
  146. //调用cat 把服务器文件返回给浏览器 post方法或者拥有执行权限
  147. if (!cgi)
  148. serve_file(client, path);
  149. else
  150. execute_cgi(client, path, method, query_string)
  151. //运行cgi程序的处理,也是个主要函数
  152. }
  153.  
  154. close(client);
  155. }
  156.  
  157. /**********************************************************************/
  158. /* Inform the client that a request it has made has a problem.
  159. * Parameters: client socket */
  160. /**********************************************************************/
  161. void bad_request(int client)
  162. {
  163. char buf[];
  164.  
  165. sprintf(buf, "HTTP/1.0 400 BAD REQUEST\r\n");
  166. send(client, buf, sizeof(buf), );
  167. sprintf(buf, "Content-type: text/html\r\n");
  168. send(client, buf, sizeof(buf), );
  169. sprintf(buf, "\r\n");
  170. send(client, buf, sizeof(buf), );
  171. sprintf(buf, "<P>Your browser sent a bad request, ");
  172. send(client, buf, sizeof(buf), );
  173. sprintf(buf, "such as a POST without a Content-Length.\r\n");
  174. send(client, buf, sizeof(buf), );
  175. }
  176.  
  177. /**********************************************************************/
  178. /* Put the entire contents of a file out on a socket. This function
  179. * is named after the UNIX "cat" command, because it might have been
  180. * easier just to do something like pipe, fork, and exec("cat").
  181. * Parameters: the client socket descriptor
  182. * FILE pointer for the file to cat */
  183. /**********************************************************************/
  184. //读取服务器上的某个文件 写到socket套接字上
  185. void cat(int client, FILE *resource)
  186. {
  187. char buf[];
  188.  
  189. fgets(buf, sizeof(buf), resource);
  190. //检测流上的文件结束符 如果文件结束,则返回非0值,否则返回0,文件结束符只能被clearerr()清除。
  191. while (!feof(resource))
  192. {
  193. send(client, buf, strlen(buf), );
  194. fgets(buf, sizeof(buf), resource);
  195. }
  196. }
  197.  
  198. /**********************************************************************/
  199. /* Inform the client that a CGI script could not be executed.
  200. * Parameter: the client socket descriptor. */
  201. /**********************************************************************/
  202. void cannot_execute(int client)
  203. {
  204. char buf[];
  205.  
  206. sprintf(buf, "HTTP/1.0 500 Internal Server Error\r\n");
  207. send(client, buf, strlen(buf), );
  208. sprintf(buf, "Content-type: text/html\r\n");
  209. send(client, buf, strlen(buf), );
  210. sprintf(buf, "\r\n");
  211. send(client, buf, strlen(buf), );
  212. sprintf(buf, "<P>Error prohibited CGI execution.\r\n");
  213. send(client, buf, strlen(buf), );
  214. }
  215.  
  216. /**********************************************************************/
  217. /* Print out an error message with perror() (for system errors; based
  218. * on value of errno, which indicates system call errors) and exit the
  219. * program indicating an error. */
  220. /**********************************************************************/
  221. void error_die(const char *sc)
  222. {
  223. perror(sc);
  224. exit();
  225. }
  226.  
  227. /**********************************************************************/
  228. /* Execute a CGI script. Will need to set environment variables as
  229. * appropriate.
  230. * Parameters: client socket descriptor
  231. * path to the CGI script */
  232. /**********************************************************************/
  233.  
  234. //运行cgi程序 也是个主函数
  235. void execute_cgi(int client, const char *path,
  236. const char *method, const char *query_string)
  237. {
  238. //在父进程中,关闭cgi_input的读入端和cgi_output的写入端,如果post的话
  239. //把post数据写入到cgi_input,已被重定向到stdin,读取cgi_output的管道
  240. //输出到客户端,该管道输入是stdout,接着关闭所有管道,等待子进程结束。
  241.  
  242. char buf[];
  243. int cgi_output[];
  244. int cgi_input[];
  245. //cgi_output[1] cgi_input[1] 为输入端
  246. //cgi_input[0] cgi_output[0] 为输出端
  247. pid_t pid;
  248. int status;
  249. int i;
  250. char c;
  251. int numchars = ;
  252. int content_length = -;
  253.  
  254. buf[] = 'A';
  255. buf[] = '\0';
  256. //读入请求头
  257. if (strcasecmp(method, "GET") == )
  258. while ((numchars > ) && strcmp("\n", buf)) /* read & discard headers */
  259. numchars = get_line(client, buf, sizeof(buf));
  260. else /* POST */
  261. {
  262. numchars = get_line(client, buf, sizeof(buf));
  263. while ((numchars > ) && strcmp("\n", buf))
  264. {
  265. buf[] = '\0';
  266. if (strcasecmp(buf, "Content-Length:") == )
  267. content_length = atoi(&(buf[]));
  268. numchars = get_line(client, buf, sizeof(buf));
  269. }
  270. if (content_length == -)
  271. {
  272. bad_request(client);
  273. return;
  274. }
  275. }
  276.  
  277. sprintf(buf, "HTTP/1.0 200 OK\r\n");
  278. send(client, buf, strlen(buf), );
  279.  
  280. if (pipe(cgi_output) < )
  281. {
  282. cannot_execute(client);
  283. return;
  284. }
  285. if (pipe(cgi_input) < )
  286. {
  287. cannot_execute(client);
  288. return;
  289. }
  290.  
  291. if ( (pid = fork()) < )
  292. {
  293. cannot_execute(client);
  294. return;
  295. }
  296. if (pid == ) /* child: CGI script */
  297. {
  298. char meth_env[];
  299. char query_env[];
  300. char length_env[];
  301. //把stdout重定向到cgi_output的写入端
  302. dup2(cgi_output[], );
  303. //把stdin重定向到cgi_input的读入端
  304. dup2(cgi_input[], );
  305. //关闭cgi_output的读入端 和 cgi_input的 写入端
  306. close(cgi_output[]);
  307. close(cgi_input[]);
  308. //设置request_method的环境变量
  309. sprintf(meth_env, "REQUEST_METHOD=%s", method);
  310. putenv(meth_env);
  311. if (strcasecmp(method, "GET") == )
  312. {
  313. //设置query_string的环境变量
  314. sprintf(query_env, "QUERY_STRING=%s", query_string);
  315. putenv(query_env);
  316. }
  317. else /* POST */
  318. {
  319. //设置content_length的环境变量
  320. sprintf(length_env, "CONTENT_LENGTH=%d", content_length);
  321. putenv(length_env);
  322. }
  323. //用execl运行cgi程序
  324. execl(path, path, NULL);
  325. exit();
  326. }
  327. else /* parent */
  328. {
  329. close(cgi_output[]);
  330. close(cgi_input[]);
  331. //关闭cgi_output的 写入端 和 cgi_input的读取端
  332. if (strcasecmp(method, "POST") == )
  333. //接受post的数据
  334. for (i = ; i < content_length; i++)
  335. {
  336. recv(client, &c, , );
  337. write(cgi_input[], &c, );
  338. //讲post数据写入cgi_input,并且重定向到stdin中
  339. }
  340. //读取cgi_output的管道输出到客户端,该管道输入时stdout
  341. while (read(cgi_output[], &c, ) > )
  342. send(client, &c, , );
  343. //关闭管道
  344. close(cgi_output[]);
  345. close(cgi_input[]);
  346. //等待子进程
  347. waitpid(pid, &status, );
  348. }
  349. }
  350.  
  351. /**********************************************************************/
  352. /* Get a line from a socket, whether the line ends in a newline,
  353. * carriage return, or a CRLF combination. Terminates the string read
  354. * with a null character. If no newline indicator is found before the
  355. * end of the buffer, the string is terminated with a null. If any of
  356. * the above three line terminators is read, the last character of the
  357. * string will be a linefeed and the string will be terminated with a
  358. * null character.
  359. * Parameters: the socket descriptor
  360. * the buffer to save the data in
  361. * the size of the buffer
  362. * Returns: the number of bytes stored (excluding null) */
  363. /**********************************************************************/
  364. int get_line(int sock, char *buf, int size)
  365. {
  366. int i = ;
  367. char c = '\0';
  368. int n;
  369.  
  370. while ((i < size - ) && (c != '\n'))
  371. {
  372. //每次接受一个字符
  373. n = recv(sock, &c, , );
  374. /* DEBUG printf("%02X\n", c); */
  375. if (n > )
  376. {
  377. if (c == '\r')
  378. {
  379. n = recv(sock, &c, , MSG_PEEK);
  380. /* DEBUG printf("%02X\n", c); */
  381. if ((n > ) && (c == '\n'))
  382. recv(sock, &c, , );
  383. else
  384. c = '\n';
  385. }
  386. buf[i] = c;
  387. i++;
  388. }
  389. else
  390. c = '\n';
  391. }
  392. buf[i] = '\0';
  393.  
  394. return(i);
  395. }
  396.  
  397. /**********************************************************************/
  398. /* Return the informational HTTP headers about a file. */
  399. /* Parameters: the socket to print the headers on
  400. * the name of the file */
  401. /**********************************************************************/
  402. //http 响应体
  403. void headers(int client, const char *filename)
  404. {
  405. char buf[];
  406. (void)filename; /* could use filename to determine file type */
  407.  
  408. strcpy(buf, "HTTP/1.0 200 OK\r\n");//响应的状态行
  409. send(client, buf, strlen(buf), );
  410. strcpy(buf, SERVER_STRING);
  411. send(client, buf, strlen(buf), );
  412. sprintf(buf, "Content-Type: text/html\r\n"); //响应头
  413. send(client, buf, strlen(buf), );
  414. strcpy(buf, "\r\n"); //响应正文段
  415. send(client, buf, strlen(buf), );
  416. }
  417.  
  418. /**********************************************************************/
  419. /* Give a client a 404 not found status message. */
  420. /**********************************************************************/
  421. void not_found(int client)
  422. {
  423. //客户端发送的请求无法实现
  424. char buf[];
  425. //响应行
  426. sprintf(buf, "HTTP/1.0 404 NOT FOUND\r\n");
  427. send(client, buf, strlen(buf), );
  428. sprintf(buf, SERVER_STRING);
  429. send(client, buf, strlen(buf), );
  430. //响应头
  431. sprintf(buf, "Content-Type: text/html\r\n");
  432. send(client, buf, strlen(buf), );
  433. sprintf(buf, "\r\n");
  434. //响应头和响应正文段之间有一个空行 表示响应行结束
  435. send(client, buf, strlen(buf), );
  436. //响应正文段 text/html
  437. sprintf(buf, "<HTML><TITLE>Not Found</TITLE>\r\n");
  438. send(client, buf, strlen(buf), );
  439. sprintf(buf, "<BODY><P>The server could not fulfill\r\n");
  440. send(client, buf, strlen(buf), );
  441. sprintf(buf, "your request because the resource specified\r\n");
  442. send(client, buf, strlen(buf), );
  443. sprintf(buf, "is unavailable or nonexistent.\r\n");
  444. send(client, buf, strlen(buf), );
  445. sprintf(buf, "</BODY></HTML>\r\n");
  446. send(client, buf, strlen(buf), );
  447. }
  448.  
  449. /**********************************************************************/
  450. /* Send a regular file to the client. Use headers, and report
  451. * errors to client if they occur.
  452. * Parameters: a pointer to a file structure produced from the socket
  453. * file descriptor
  454. * the name of the file to serve */
  455. /**********************************************************************/
  456. void serve_file(int client, const char *filename)
  457. {
  458. FILE *resource = NULL;
  459. int numchars = ;
  460. char buf[];
  461.  
  462. buf[] = 'A';
  463. buf[] = '\0';
  464. while ((numchars > ) && strcmp("\n", buf)) /* read & discard headers */
  465. numchars = get_line(client, buf, sizeof(buf));
  466.  
  467. resource = fopen(filename, "r");
  468. if (resource == NULL)
  469. not_found(client);
  470. else
  471. {
  472. headers(client, filename);
  473. cat(client, resource);
  474. }
  475. fclose(resource);
  476. }
  477.  
  478. /**********************************************************************/
  479. /* This function starts the process of listening for web connections
  480. * on a specified port. If the port is 0, then dynamically allo //响应正文段cate a
  481. * port and modify the original port variable to reflect the actual
  482. * port.
  483. * Parameters: pointer to variable containing the port to connect on
  484. * Returns: the socket */
  485. /**********************************************************************/
  486. int startup(u_short *port)
  487. {
  488. int httpd = ;
  489. struct sockaddr_in name;
  490. //建立套接字
  491. httpd = socket(PF_INET, SOCK_STREAM, );
  492. if (httpd == -)
  493. error_die("socket");
  494. memset(&name, , sizeof(name));
  495. name.sin_family = AF_INET;
  496. name.sin_port = htons(*port);
  497. name.sin_addr.s_addr = htonl(INADDR_ANY);
  498. //绑定端口和ip
  499. if (bind(httpd, (struct sockaddr *)&name, sizeof(name)) < )
  500. error_die("bind");
  501. if (*port == ) /* if dynamically allocating a port */
  502. {
  503. int namelen = sizeof(name);
  504. if (getsockname(httpd, (struct sockaddr *)&name, &namelen) == -)
  505. error_die("getsockname");
  506. *port = ntohs(name.sin_port);
  507. }
  508. //监听
  509. if (listen(httpd, ) < )
  510. error_die("listen");
  511. return(httpd);
  512. }
  513.  
  514. /**********************************************************************/
  515. /* Inform the client that the requested web method has not been
  516. * implemented.
  517. * Parameter: the client socket */
  518. /**********************************************************************/
  519. void unimplemented(int client)
  520. {
  521. //发回响应信息 http的请求方法不被接受
  522. char buf[];
  523. //返回501 错误 未实现 (Not implemented)是指Web 服务器不理解或不支持发送给它的 HTTP 数据流中找到的 HTTP 方法
  524. sprintf(buf, "HTTP/1.0 501 Method Not Implemented\r\n");
  525. send(client, buf, strlen(buf), );
  526. sprintf(buf, SERVER_STRING);
  527. send(client, buf, strlen(buf), );
  528. sprintf(buf, "Content-Type: text/html\r\n");//响应头
  529. send(client, buf, strlen(buf), );
  530. sprintf(buf, "\r\n");
  531. send(client, buf, strlen(buf), ); //响应正文段
  532. sprintf(buf, "<HTML><HEAD><TITLE>Method Not Implemented\r\n");
  533. send(client, buf, strlen(buf), );
  534. sprintf(buf, "</TITLE></HEAD>\r\n");
  535. send(client, buf, strlen(buf), );
  536. sprintf(buf, "<BODY><P>HTTP request method not supported.\r\n");
  537. send(client, buf, strlen(buf), );
  538. sprintf(buf, "</BODY></HTML>\r\n");
  539. send(client, buf, strlen(buf), );
  540. }
  541.  
  542. /**********************************************************************/
  543.  
  544. int main(void)
  545. {
  546. int server_sock = -;
  547. u_short port = ;
  548. int client_sock = -;
  549. struct sockaddr_in client_name;
  550. int client_name_len = sizeof(client_name);
  551. pthread_t newthread;
  552.  
  553. server_sock = startup(&port);
  554. printf("httpd running on port %d\n", port);
  555.  
  556. while ()
  557. {
  558. client_sock = accept(server_sock,
  559. (struct sockaddr *)&client_name,
  560. &client_name_len);
  561. //建立链接
  562. if (client_sock == -)
  563. error_die("accept");
  564. /* accept_request(client_sock); */
  565. //多线程进行控制
  566. if (pthread_create(&newthread , NULL, accept_request, client_sock) != )
  567. perror("pthread_create");
  568. }
  569.  
  570. close(server_sock);
  571.  
  572. return();
  573. }

tinyhttpd ------ C 语言实现最简单的 HTTP 服务器的更多相关文章

  1. go 语言实现一个简单的 web 服务器

    学习Go语言的一些感受,不一定准确. 假如发生战争,JAVA一般都是充当航母战斗群的角色.一旦出动,就是护卫舰.巡洋舰.航母舰载机.预警机.电子战飞机.潜艇等等浩浩荡荡,杀将过去.(JVM,数十个JA ...

  2. 一个简单的 Web 服务器 [未完成]

    最近学习C++,linux和网络编程,想做个小(mini)项目.  就去搜索引擎, 开源中国, Sourceforge上找http server的项目. 好吧,也去了知乎.    知乎上程序员氛围好, ...

  3. R语言:用简单的文本处理方法优化我们的读书体验

    博客总目录:http://www.cnblogs.com/weibaar/p/4507801.html 前言 延续之前的用R语言读琅琊榜小说,继续讲一下利用R语言做一些简单的文本处理.分词的事情.其实 ...

  4. 踢爆IT劣书出版黑幕——由清华大学出版社之《C语言入门很简单》想到的(1)

    1.前言与作者 首先声明,我是由于非常偶然的机会获得<C语言入门很简单>这本书的,绝对不是买的.买这种书实在丢不起那人. 去年这书刚出版时,在CU论坛举行试读推广,我当时随口说了几句(没说 ...

  5. 留念 C语言第一课简单的计算器制作

    留念 C语言第一课简单的计算器制作 学C语言这么久了.  /* 留念 C语言第一课简单的计算器制作 */   #include<stdio.h>  #include<stdlib.h ...

  6. 用C语言编写一个简单的词法分析程序

    问题描述: 用C或C++语言编写一个简单的词法分析程序,扫描C语言小子集的源程序,根据给定的词法规则,识别单词,填写相应的表.如果产生词法错误,则显示错误信息.位置,并试图从错误中恢复.简单的恢复方法 ...

  7. 用Go语言实现一个简单的聊天机器人

    一.介绍 目的:使用Go语言写一个简单的聊天机器人,复习整合Go语言的语法和基础知识. 软件环境:Go1.9,Goland 2018.1.5. 二.回顾 Go语言基本构成要素:标识符.关键字.字面量. ...

  8. C语言之非常简单的几道题

    C语言之非常简单的几道题(还是写写),比较简单吧,主要有几道题的数据类型(如,第三题)和语句顺序(如,第二题)需要注意一小下下. 1. 求表达式S=1*2*3……*N的值大于150时,最小的N的值 / ...

  9. C 语言实例 - 实现简单的计算器

    C 语言实例 - 实现简单的计算器 实现加减乘除计算. 实例 # include <stdio.h> int main() { char operator; double firstNum ...

随机推荐

  1. Redux的应该注意的问题

    1. Store中的State修改不能直接修改原有的State,若直接修改State,则redux中的所有操作都将指向 内存中的同一个state,将无法获取每一次操作前后的state,就无法追溯sta ...

  2. idea导入web项目tomcat

    概述 主要分为项目配置和tomcat配置两大步骤. 一.项目配置 打开idea,选择导入项 选择将要打开的项目路径后,继续选择项目的原本类型(后续引导设置会根据原本的项目类型更新成idea的项目),此 ...

  3. CentOS7搭建 Hadoop + HBase + Zookeeper集群

    摘要: 本文主要介绍搭建Hadoop.HBase.Zookeeper集群环境的搭建 一.基础环境准备 1.下载安装包(均使用当前最新的稳定版本,截止至2017年05月24日) 1)jdk-8u131 ...

  4. 论C++11 中vector的N种遍历方法

    随着C++11标准的出现,C++标准添加了许多有用的特性,C++代码的写法也有比较多的变化. vector是经常要使用到的std组件,对于vector的遍历,本文罗列了若干种写法. (注:本文中代码为 ...

  5. HDU1298 字典树+dfs

    T9 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submissi ...

  6. 使用tcpdump监控网络消息发送

    tcpdump是一个用于截取网络分组,并输出分组内容的工具,简单说就是数据包抓包工具.tcpdump凭借强大的功能和灵活的截取策略,使其成为Linux系统下用于网络分析和问题排查的首选工具. tcpd ...

  7. 编译skia静态库时,图片解码库无法注册的问题

    转载:http://www.cnblogs.com/imlucky/archive/2012/08/01/2617851.html 今天编译skia库,增加图片解码库时总是无效.按照此博客的方法修改后 ...

  8. java中String字符串的替换函数:replace与replaceAll的区别

    例如有如下x的字符串 String x = "[kllkklk\\kk\\kllkk]";要将里面的“kk”替换为++,可以使用两种方法得到相同的结果 replace(CharSe ...

  9. 使用jquery.qrcode生成二维码及常见问题解决方案

    转载文章  使用jquery.qrcode生成二维码及常见问题解决方案 一.jquery.qrcode.js介 jquery.qrcode.js 是一个纯浏览器 生成 QRcode 的 jQuery ...

  10. 【C++ STL】Deques

    1.结构 容器deque和vector非常相似,也是采用动态数组来管理元素,提供随机存取,有着和vector几乎一样的接口,不同的是deque的动态数组头尾都开放,因此可以在头尾都可以进行快速的安插和 ...