HTTP协议浅析(下): 使用HTTP协议实现通信http://blog.csdn.net/tennysonsky/article/details/53909564
1. 概述
服务器的开发不容易,尤其是开发高性能、稳定性好服务器,更加不容易,因此人们尝试更好简单的方式来开发软件。
在服务器方面,使用Web服务器,采用HTTP协议来代替底层的socket,是常见的选择。采用HTTP协议更加除了能得到稳定的服务器支持外,更加可以兼容各种客户端(手机、PC、浏览器)等等。这样实现了一个服务器之后,多个客户端可以通用。
2.通信过程
HTTP 协议采用请求/响应模型。客户端向服务器发送一个请求报文,服务器以一个状态作为响应。
HTTP 请求/响应的步骤:
- 客户端连接到web服务器:HTTP 客户端与web服务器建立一个 TCP 连接;
- 客户端向服务器发起 HTTP 请求:通过已建立的TCP 连接,客户端向服务器发送一个请求报文;
- 服务器接收 HTTP 请求并返回 HTTP 响应:服务器解析请求,定位请求资源,服务器将资源副本写到 TCP 连接,由客户端读取;
- 释放 TCP 连接:若connection 模式为close,则服务器主动关闭TCP 连接,客户端被动关闭连接,释放TCP 连接;若connection 模式为keepalive,则该连接会保持一段时间,在该时间内可以继续接收请求;
- 客户端浏览器解析HTML内容:客户端将服务器响应的 html 文本解析并显示。
3. 测试代码
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <fcntl.h>#include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h>int main(){ int sockfd = socket(AF_INET, SOCK_STREAM, 0); if(sockfd < 0) { perror("socket"); return -1; } struct sockaddr_in my_addr; bzero(&my_addr, sizeof(my_addr)); my_addr.sin_family = AF_INET; my_addr.sin_port = htons(8000); my_addr.sin_addr.s_addr = htonl(INADDR_ANY); int err_log = bind(sockfd, (struct sockaddr*)&my_addr, sizeof(my_addr)); if( err_log != 0) { perror("binding"); close(sockfd); return -1; } err_log = listen(sockfd, 10); if(err_log != 0) { perror("listen"); close(sockfd); return -1; } printf("listen client @port=%d...\n", 8000); int connfd; connfd = accept(sockfd, NULL, NULL); char recv_buf[8*1024] = {0}; read(connfd, recv_buf, sizeof(recv_buf)); printf("%s", recv_buf); char filename[200] = {0}; sscanf(recv_buf, "GET /%[^ ]", filename); printf("filename = %s\n", filename); int fd; fd = open(filename, O_RDONLY); if(fd < 0) { char err[]= "HTTP/1.1 404 Not Found\r\n" "Content-Type: text/html\r\n" "\r\n" "<HTML><BODY>File not found</BODY></HTML>"; perror("open"); send(connfd, err, strlen(err), 0); close(connfd); return -1; } char head[] = "HTTP/1.1 200 OK\r\n" "Content-Type: text/html\r\n" "\r\n"; send(connfd, head, strlen(head), 0); int len; char file_buf[4 * 1024]; while((len = read(fd, file_buf, sizeof(file_buf))) > 0) { send(connfd, file_buf, len, 0); } close(fd); close(connfd); while(1) { NULL; } return 0;}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
终端运行服务器程序:
浏览器请求服务,得到相应内容:
4. 简单版Web服务器
#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <fcntl.h>#include <string.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>int main(int argc, char *argv[]){ unsigned short port = 8000; if(argc > 1) { port = atoi(argv[1]); } int sockfd = socket(AF_INET, SOCK_STREAM, 0); if( sockfd < 0) { perror("socket"); exit(-1); } struct sockaddr_in my_addr; bzero(&my_addr, sizeof(my_addr)); my_addr.sin_family = AF_INET; my_addr.sin_port = htons(port); my_addr.sin_addr.s_addr = htonl(INADDR_ANY); if( bind(sockfd, (struct sockaddr*)&my_addr, sizeof(my_addr)) != 0) { perror("bind"); close(sockfd); exit(-1); } if( listen(sockfd, 10) != 0) { perror("listen"); close(sockfd); exit(-1); } printf("Listenning at port=%d\n",port); printf("Usage: http://127.0.0.1:%d/html/index.html\n", port); while(1) { char cli_ip[INET_ADDRSTRLEN] = {0}; struct sockaddr_in client_addr; socklen_t cliaddr_len = sizeof(client_addr); int connfd = accept(sockfd, (struct sockaddr*)&client_addr, &cliaddr_len); printf("connfd=%d\n",connfd); if(connfd > 0) { if(fork() == 0) { close(sockfd); int fd = 0; int len = 0; char buf[1024] = ""; char filename[50] = ""; inet_ntop(AF_INET, &client_addr.sin_addr, cli_ip, INET_ADDRSTRLEN); printf("connected form %s\n\r", cli_ip); recv(connfd, buf, sizeof(buf), 0); sscanf(buf, "GET /%[^ ]", filename); printf("filename=*%s*\n", filename); fd = open(filename, O_RDONLY); if( fd < 0) { char err[]= "HTTP/1.1 404 Not Found\r\n" "Content-Type: text/html\r\n" "\r\n" "<HTML><BODY>File not found</BODY></HTML>"; perror("open error"); send(connfd, err, strlen(err), 0); close(connfd); exit(0); } char head[]="HTTP/1.1 200 OK\r\n" "Content-Type: text/html\r\n" "\r\n"; send(connfd, head, strlen(head), 0); while( (len = read(fd, buf, sizeof(buf))) > 0) { send(connfd, buf, len, 0); } close(fd); close(connfd); exit(0); } } close(connfd); } close(sockfd); printf("exit main!\n"); return 0;}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
本教程示例代码下载请点此链接:http://download.csdn.net/detail/tennysonsky
github下载路径:https://github.com/mikejiangsky/http_communication.git