@@ -7,6 +7,226 @@ Socket 还可以认为是一种网络间不同计算机上的进程通信的一
77
88Socket 起源于 Unix ,Unix/Linux 基本哲学之一就是“一切皆文件”,都可以用“打开(open) –> 读写(write/read) –> 关闭(close)”模式来进行操作。因此 Socket 也被处理为一种特殊的文件。
99
10+ ## 写一个简易的 WebServer
11+
12+ 一个简易的 Server 的流程如下:
13+
14+ - 1.建立连接,接受一个客户端连接。
15+ - 2.接受请求,从网络中读取一条 HTTP 请求报文。
16+ - 3.处理请求,访问资源。
17+ - 4.构建响应,创建带有 header 的 HTTP 响应报文。
18+ - 5.发送响应,传给客户端。
19+
20+ 省略流程 3,大体的程序与调用的函数逻辑如下:
21+
22+ - socket() 创建套接字
23+ - bind() 分配套接字地址
24+ - listen() 等待连接请求
25+ - accept() 允许连接请求
26+ - read()/write() 数据交换
27+ - close() 关闭连接
28+
29+ 代码如下:
30+
31+ ``` cpp
32+ #include < cstdio>
33+ #include < cstdlib>
34+ #include < cstring>
35+ #include < unistd.h>
36+ #include < sys/socket.h>
37+ #include < arpa/inet.h>
38+ #include < string>
39+ #include < cstring>
40+ #include < iostream>
41+
42+ using namespace std ;
43+
44+ const int port = 9090 ;
45+ const int buffer_size = 1 <<20 ;
46+ const int method_size = 1 <<10 ;
47+ const int filename_size = 1 <<10 ;
48+ const int common_buffer_size = 1 <<10 ;
49+
50+ void handleError (const string &message);
51+ void requestHandling(int * sock);
52+ void sendError(int * sock);
53+ void sendData(int * sock, char * filename);
54+ void sendHTML(int * sock, char * filename);
55+ void sendJPG(int * sock, char * filename);
56+
57+ int main()
58+ {
59+ int server_sock;
60+ int client_sock;
61+
62+ struct sockaddr_in server_address;
63+ struct sockaddr_in client_address;
64+
65+ socklen_t client_address_size;
66+
67+ server_sock = socket(PF_INET, SOCK_STREAM, 0);
68+
69+ if (server_sock == -1)
70+ {
71+ handleError("socket error");
72+ }
73+
74+ memset(&server_address,0,sizeof(server_address));
75+ server_address.sin_family = AF_INET;
76+ server_address.sin_addr.s_addr = htonl(INADDR_ANY);
77+ server_address.sin_port = htons(port);
78+
79+ if(bind(server_sock,(struct sockaddr*)&server_address, sizeof(server_address)) == -1){
80+ handleError("bind error");
81+ }
82+
83+ if(listen(server_sock, 5) == -1) {
84+ handleError("listen error");
85+ }
86+
87+ while(true) {
88+ client_address_size = sizeof(client_address);
89+ client_sock = accept(server_sock, (struct sockaddr*) &client_address, &client_address_size);
90+
91+ if (client_sock == -1) {
92+ handleError("accept error");
93+ }
94+ requestHandling(&client_sock);
95+ }
96+
97+ //system("open http://127.0.0.1:9090/index.html");
98+ close(server_sock);
99+
100+ return 0;
101+ }
102+
103+ void requestHandling(int * sock){
104+ int client_sock = * sock;
105+ char buffer[ buffer_size] ;
106+ char method[ method_size] ;
107+ char filename[ filename_size] ;
108+
109+ read(client_sock, buffer, sizeof(buffer)-1);
110+
111+ if(!strstr(buffer, "HTTP/")) {
112+ sendError(sock);
113+ close(client_sock);
114+ return;
115+ }
116+
117+ strcpy(method, strtok(buffer," /"));
118+ strcpy(filename, strtok(NULL, " /"));
119+
120+ if(0 != strcmp(method, "GET")) {
121+ sendError(sock);
122+ close(client_sock);
123+ return;
124+ }
125+
126+ sendData(sock, filename);
127+ }
128+
129+ void sendData(int * sock, char * filename) {
130+ int client_sock = * sock;
131+ char buffer[ common_buffer_size] ;
132+ char type[ common_buffer_size] ;
133+
134+ strcpy(buffer, filename);
135+
136+ strtok(buffer, ".");
137+ strcpy(type, strtok(NULL, "."));
138+
139+ if(0 == strcmp(type, "html")){
140+ sendHTML(sock, filename);
141+ }else if(0 == strcmp(type, "jpg")){
142+ sendJPG(sock, filename);
143+ }else{
144+ sendError(sock);
145+ close(client_sock);
146+ return ;
147+ }
148+ }
149+
150+ void sendHTML(int * sock, char * filename) {
151+ int client_sock = * sock;
152+ char buffer[ buffer_size] ;
153+ FILE * fp;
154+
155+ char status[] = "HTTP/1.0 200 OK\r\n";
156+ char header[] = "Server: A Simple Web Server\r\nContent-Type: text/html\r\n\r\n";
157+
158+ write(client_sock, status, strlen(status));
159+ write(client_sock, header, strlen(header));
160+
161+ fp = fopen(filename, "r");
162+ if(!fp){
163+ sendError(sock);
164+ close(client_sock);
165+ handleError("failed to open file");
166+ return ;
167+ }
168+
169+ fgets(buffer,sizeof(buffer), fp);
170+ while(!feof(fp)) {
171+ write(client_sock, buffer, strlen(buffer));
172+ fgets(buffer, sizeof(buffer), fp);
173+ }
174+
175+ fclose(fp);
176+ close(client_sock);
177+ }
178+
179+ void sendJPG(int * sock, char * filename) {
180+ int client_sock = * sock;
181+ char buffer[ buffer_size] ;
182+ FILE * fp;
183+ FILE * fw;
184+
185+ char status[] = "HTTP/1.0 200 OK\r\n";
186+ char header[] = "Server: A Simple Web Server\r\nContent-Type: image/jpeg\r\n\r\n";
187+
188+ write(client_sock, status, strlen(status));
189+ write(client_sock, header, strlen(header));
190+
191+ fp = fopen(filename, "rb");
192+ if(NULL == fp){
193+ sendError(sock);
194+ close(client_sock);
195+ handleError("failed to open file");
196+ return ;
197+ }
198+
199+ fw = fdopen(client_sock, "w");
200+ fread(buffer, 1, sizeof(buffer), fp);
201+ while (!feof(fp)){
202+ fwrite(buffer, 1, sizeof(buffer), fw);
203+ fread(buffer, 1, sizeof(buffer), fp);
204+ }
205+
206+ fclose(fw);
207+ fclose(fp);
208+ close(client_sock);
209+ }
210+
211+ void handleError(const string &message) {
212+ cout<<message;
213+ exit(1);
214+ }
215+
216+ void sendError(int * sock){
217+ int client_sock = * sock;
218+
219+ char status[] = "HTTP/1.0 400 Bad Request\r\n";
220+ char header[] = "Server: A Simple Web Server\r\nContent-Type: text/html\r\n\r\n";
221+ char body[] = "<html><head><title>Bad Request</title></head><body><p>400 Bad Request</p></body></html>";
222+
223+ write(client_sock, status, sizeof(status));
224+ write(client_sock, header, sizeof(header));
225+ write(client_sock, body, sizeof(body));
226+ }
227+ ```
228+
229+
10230### 参考资料
11231
122321. [Linux Socket编程](http://www.cnblogs.com/skynet/archive/2010/12/12/1903949.html)
0 commit comments