[toc]

用C语言在Linux中使用http协议浏览网页

1.用C语言在Linux中使用http协议浏览静态网页

LinServer.c

这个服务器程序将能够处理GET请求,并返回一个简单的HTML页面。

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
//LinServer.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>

#define PORT 8080
#define BUFFER_SIZE 1024

void handle_request(int client_socket) {
char buffer[BUFFER_SIZE];
int bytes_received = recv(client_socket, buffer, sizeof(buffer) - 1, 0);
if (bytes_received > 0) {
buffer[bytes_received] = '\0'; // 添加字符串结束符
printf("Received request:\n%s\n", buffer);

// 解析请求行
char method[16], path[256], version[16];
sscanf(buffer, "%s %s %s", method, path, version);

// 响应内容
const char* response_header;
const char* response_body;

// 根据请求路径返回不同的响应
if (strcmp(method, "GET") == 0) {
if (strcmp(path, "/") == 0) {
response_header = "HTTP/1.1 200 OK\r\n"
"Content-Type: text/html\r\n"
"Connection: close\r\n\r\n";
response_body = "<html><body><h1>Welcome to the Home Page!</h1></body></html>";
}
else if (strcmp(path, "/hello") == 0) {
response_header = "HTTP/1.1 200 OK\r\n"
"Content-Type: text/html\r\n"
"Connection: close\r\n\r\n";
response_body = "<html><body><h1>Hello, World!</h1></body></html>";
}
else {
response_header = "HTTP/1.1 404 Not Found\r\n"
"Content-Type: text/html\r\n"
"Connection: close\r\n\r\n";
response_body = "<html><body><h1>404 Not Found</h1></body></html>";
}

// 发送响应
send(client_socket, response_header, strlen(response_header), 0);
send(client_socket, response_body, strlen(response_body), 0);
}
}

// 关闭客户端套接字
close(client_socket);
}

int main() {
int server_socket, client_socket;
struct sockaddr_in server, client;
socklen_t client_len = sizeof(client);

// 创建套接字
server_socket = socket(AF_INET, SOCK_STREAM, 0);
if (server_socket < 0) {
perror("Could not create socket");
return 1;
}

// 设置服务器信息
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY; // 监听所有IP
server.sin_port = htons(PORT);

// 绑定套接字
if (bind(server_socket, (struct sockaddr*)&server, sizeof(server)) < 0) {
perror("Bind failed");
close(server_socket);
return 1;
}

// 开始监听
listen(server_socket, SOMAXCONN);
printf("Server listening on port %d...\n", PORT);

// 主循环,接受客户端连接
while (1) {
client_socket = accept(server_socket, (struct sockaddr*)&client, &client_len);
if (client_socket < 0) {
perror("Accept failed");
continue;
}

// 处理请求
handle_request(client_socket);
}

// 关闭服务器套接字
close(server_socket);
return 0;
}

LinClient.c

这个客户端程序将请求服务器的静态网页,并打印出服务器的响应。

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
//LinClient.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>

#define SERVER "127.0.0.1" // 服务器地址
#define PORT 8080 // 服务器端口
#define BUFFER_SIZE 1024

int main() {
int sock;
struct sockaddr_in server;
char request[BUFFER_SIZE], response[BUFFER_SIZE];
int bytes_received;

// 创建套接字
sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0) {
perror("Could not create socket");
return 1;
}

// 设置服务器信息
server.sin_family = AF_INET;
server.sin_addr.s_addr = inet_addr(SERVER);
server.sin_port = htons(PORT);

// 连接到服务器
if (connect(sock, (struct sockaddr*)&server, sizeof(server)) < 0) {
perror("Connect failed");
close(sock);
return 1;
}

// 构建HTTP GET请求
sprintf(request, "GET /hello HTTP/1.1\r\n"
"Host: %s\r\n"
"Connection: close\r\n\r\n", SERVER);

// 发送请求
send(sock, request, strlen(request), 0);

// 接收响应
while ((bytes_received = recv(sock, response, sizeof(response) - 1, 0)) > 0) {
response[bytes_received] = '\0'; // 添加字符串结束符
printf("%s", response); // 打印响应
}

// 关闭套接字
close(sock);
return 0;
}

运行结果

  1. 运行LinServer

  2. 运行LinClient或浏览器中访问http://127.0.0.1:8080/First.html

  3. 运行成功

2.修改程序,让程序可以解析同当前录中的First.html文件

First.html

在当前目录下创建一个名为First.html的文件,并添加一些HTML内容

1
2
3
4
5
6
<html>
<body>
<h1>This is First.html</h1>
<p>Welcome to the static HTML page served by the HTTP server!</p>
</body>
</html>

LinServer.c

这个服务器程序将能够处理GET请求,并返回当前目录下的First.html文件内容。

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
//LinServer.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>

#define PORT 8080
#define BUFFER_SIZE 1024
#define FILE_PATH "First.html" // 文件路径

void handle_request(int client_socket) {
char buffer[BUFFER_SIZE];
int bytes_received = recv(client_socket, buffer, sizeof(buffer) - 1, 0);
if (bytes_received > 0) {
buffer[bytes_received] = '\0'; // 添加字符串结束符
printf("Received request:\n%s\n", buffer);

// 解析请求行
char method[16], path[256], version[16];
sscanf(buffer, "%s %s %s", method, path, version);

// 响应内容
const char* response_header;
char response_body[BUFFER_SIZE];
FILE* file;

// 根据请求路径返回不同的响应
if (strcmp(method, "GET") == 0) {
if (strcmp(path, "/First.html") == 0) {
// 打开文件并读取内容
file = fopen(FILE_PATH, "r");
if (file) {
// 读取文件内容
size_t bytes_read = fread(response_body, sizeof(char), sizeof(response_body) - 1, file);
response_body[bytes_read] = '\0'; // 确保字符串结束
fclose(file);

// 发送响应头
response_header = "HTTP/1.1 200 OK\r\n"
"Content-Type: text/html\r\n"
"Content-Length: %lu\r\n"
"Connection: close\r\n\r\n";
char header[BUFFER_SIZE];
sprintf(header, response_header, bytes_read);
send(client_socket, header, strlen(header), 0);
send(client_socket, response_body, bytes_read, 0);
}
else {
// 文件未找到
response_header = "HTTP/1.1 404 Not Found\r\n"
"Content-Type: text/html\r\n"
"Connection: close\r\n\r\n";
const char* error_body = "<html><body><h1>404 Not Found</h1></body></html>";
send(client_socket, response_header, strlen(response_header), 0);
send(client_socket, error_body, strlen(error_body), 0);
}
}
else {
// 处理其他路径
response_header = "HTTP/1.1 404 Not Found\r\n"
"Content-Type: text/html\r\n"
"Connection: close\r\n\r\n";
const char* error_body = "<html><body><h1>404 Not Found</h1></body></html>";
send(client_socket, response_header, strlen(response_header), 0);
send(client_socket, error_body, strlen(error_body), 0);
}
}
}

// 关闭客户端套接字
close(client_socket);
}

int main() {
int server_socket, client_socket;
struct sockaddr_in server, client;
socklen_t client_len = sizeof(client);

// 创建套接字
server_socket = socket(AF_INET, SOCK_STREAM, 0);
if (server_socket < 0) {
perror("Could not create socket");
return 1;
}

// 设置服务器信息
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY; // 监听所有IP
server.sin_port = htons(PORT);

// 绑定套接字
if (bind(server_socket, (struct sockaddr*)&server, sizeof(server)) < 0) {
perror("Bind failed");
close(server_socket);
return 1;
}

// 开始监听
listen(server_socket, SOMAXCONN);
printf("Server listening on port %d...\n", PORT);

// 主循环,接受客户端连接
while (1) {
client_socket = accept(server_socket, (struct sockaddr*)&client, &client_len);
if (client_socket < 0) {
perror("Accept failed");
continue;
}

// 处理请求
handle_request(client_socket);
}

// 关闭服务器套接字
close(server_socket);
return 0;
}

LinClient.c

这个客户端程序将请求服务器的First.html文件,并打印出服务器的响应。

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
//LinClient.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>

#define SERVER "127.0.0.1" // 服务器地址
#define PORT 8080 // 服务器端口
#define BUFFER_SIZE 1024

int main() {
int sock;
struct sockaddr_in server;
char request[BUFFER_SIZE], response[BUFFER_SIZE];
int bytes_received;

// 创建套接字
sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0) {
perror("Could not create socket");
return 1;
}

// 设置服务器信息
server.sin_family = AF_INET;
server.sin_addr.s_addr = inet_addr(SERVER);
server.sin_port = htons(PORT);

// 连接到服务器
if (connect(sock, (struct sockaddr*)&server, sizeof(server)) < 0) {
perror("Connect failed");
close(sock);
return 1;
}

// 构建HTTP GET请求
sprintf(request, "GET /First.html HTTP/1.1\r\n"
"Host: %s\r\n"
"Connection: close\r\n\r\n", SERVER);

// 发送请求
send(sock, request, strlen(request), 0);

// 接收响应
while ((bytes_received = recv(sock, response, sizeof(response) - 1, 0)) > 0) {
response[bytes_received] = '\0'; // 添加字符串结束符
printf("%s", response); // 打印响应
}

// 关闭套接字
close(sock);
return 0;
}

运行结果

  1. 在当前目录创建First.html

  2. 运行LinServer

  3. 运行LinClient或者浏览器中访问http://127.0.0.1:8080/First.html

  4. 运行成功

3.修改服务端程序,让程序可以访问多个html文件

LinSever.c

设置当前目录为基本路径,设置绝对路径通过相对路径访问First.html

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
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <fcntl.h>

#define PORT 8080
#define BUFFER_SIZE 1024
#define BASE_PATH "/home/kali/cc++/http/" // 基础文件路径,确保使用Linux格式的路径

void handle_request(int client_socket) {
char buffer[BUFFER_SIZE];
int bytes_received = recv(client_socket, buffer, sizeof(buffer) - 1, 0);
if (bytes_received > 0) {
buffer[bytes_received] = '\0'; // 添加字符串结束符
printf("Received request:\n%s\n", buffer);

// 解析请求行
char method[16], path[256], version[16];
sscanf(buffer, "%s %s %s", method, path, version);

// 响应内容
const char* response_header;
char response_body[BUFFER_SIZE];
int file;

// 根据请求路径返回不同的响应
if (strcmp(method, "GET") == 0) {
// 构建文件路径
char file_path[BUFFER_SIZE];
snprintf(file_path, sizeof(file_path), "%s%s", BASE_PATH, path + 1); // 路径前加上基础路径,去掉前面的'/'

// 打开文件并读取内容
file = open(file_path, O_RDONLY);
if (file != -1) {
// 读取文件内容
ssize_t bytes_read = read(file, response_body, sizeof(response_body) - 1);
response_body[bytes_read] = '\0'; // 确保字符串结束
close(file);

// 发送响应头
response_header = "HTTP/1.1 200 OK\r\n"
"Content-Type: text/html\r\n"
"Content-Length: %lu\r\n"
"Connection: close\r\n\r\n";
char header[BUFFER_SIZE];
sprintf(header, response_header, bytes_read);
send(client_socket, header, strlen(header), 0);
send(client_socket, response_body, bytes_read, 0);
} else {
// 文件未找到
response_header = "HTTP/1.1 404 Not Found\r\n"
"Content-Type: text/html\r\n"
"Connection: close\r\n\r\n";
const char* error_body = "<html><body><h1>404 Not Found</h1></body></html>";
send(client_socket, response_header, strlen(response_header), 0);
send(client_socket, error_body, strlen(error_body), 0);
}
}
}

// 关闭客户端套接字
close(client_socket);
}

int main() {
int server_socket, client_socket;
struct sockaddr_in server, client;
socklen_t client_len = sizeof(client);

// 创建套接字
server_socket = socket(AF_INET, SOCK_STREAM, 0);
if (server_socket < 0) {
perror("Could not create socket");
return 1;
}

// 设置服务器信息
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY; // 监听所有IP
server.sin_port = htons(PORT);

// 绑定套接字
if (bind(server_socket, (struct sockaddr*)&server, sizeof(server)) < 0) {
perror("Bind failed");
close(server_socket);
return 1;
}

// 开始监听
listen(server_socket, SOMAXCONN);
printf("Server listening on port %d...\n", PORT);

// 主循环,接受客户端连接
while (1) {
client_socket = accept(server_socket, (struct sockaddr*)&client, &client_len);
if (client_socket < 0) {
perror("Accept failed");
continue;
}

// 处理请求
handle_request(client_socket);
}

// 关闭服务器套接字
close(server_socket);
return 0;
}

运行结果

  1. 在当前目录创建First.html
  2. 运行LinServer
  3. 运行LinClient或者浏览器中访问http://127.0.0.1:8080/First.html
  4. 运行成功

4. 修改程序,让程序可以解析css

1. 修改First.html

将First.html文件保存在”/home/kali/cc++/http/First/First.html”中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>First</title>
<!-- 设置:h3{color:blue;} -->
<style type="text/css">
/* 内部样式 */
h3{color:green;}
</style>
</head>
<body>

<h3>显示绿色,是内部样式</h3>

</body>
</html>

2.修改LinServer.c

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
//LinServer.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>

#define PORT 8080
#define BUFFER_SIZE 1024
#define BASE_PATH "/home/kali/cc++/http/First/" // 基础文件路径,确保使用Linux格式的路径

void handle_request(int client_socket) {
char buffer[BUFFER_SIZE];
int bytes_received = recv(client_socket, buffer, sizeof(buffer) - 1, 0);
if (bytes_received > 0) {
buffer[bytes_received] = '\0'; // 添加字符串结束符
printf("Received request:\n%s\n", buffer);

// 解析请求行
char method[16], path[256], version[16];
sscanf(buffer, "%s %s %s", method, path, version);

// 响应内容
const char* response_header;
char response_body[BUFFER_SIZE];
FILE* file;

// 根据请求路径返回不同的响应
if (strcmp(method, "GET") == 0) {
// 构建文件路径
char file_path[BUFFER_SIZE];
snprintf(file_path, sizeof(file_path), "%s%s", BASE_PATH, path + 1); // 路径前加上基础路径,去掉前面的'/'

// 打开文件并读取内容
file = fopen(file_path, "r");
if (file) {
// 读取文件内容
size_t bytes_read = fread(response_body, sizeof(char), sizeof(response_body) - 1, file);
response_body[bytes_read] = '\0'; // 确保字符串结束
fclose(file);

// 确定 Content-Type
const char* content_type;
if (strstr(path, ".html")) {
content_type = "text/html";
}
else if (strstr(path, ".css")) {
content_type = "text/css";
}
else {
content_type = "application/octet-stream"; // 默认类型
}

// 发送响应头
response_header = "HTTP/1.1 200 OK\r\n"
"Content-Type: %s\r\n"
"Content-Length: %lu\r\n"
"Connection: close\r\n\r\n";
char header[BUFFER_SIZE];
sprintf(header, response_header, content_type, bytes_read);
send(client_socket, header, strlen(header), 0);
send(client_socket, response_body, bytes_read, 0);
}
else {
// 文件未找到
response_header = "HTTP/1.1 404 Not Found\r\n"
"Content-Type: text/html\r\n"
"Connection: close\r\n\r\n";
const char* error_body = "<html><body><h1>404 Not Found</h1></body></html>";
send(client_socket, response_header, strlen(response_header), 0);
send(client_socket, error_body, strlen(error_body), 0);
}
}
}

// 关闭客户端套接字
close(client_socket);
}

int main() {
int server_socket, client_socket;
struct sockaddr_in server, client;
socklen_t client_len = sizeof(client);

// 创建套接字
server_socket = socket(AF_INET, SOCK_STREAM, 0);
if (server_socket < 0) {
perror("Could not create socket");
return 1;
}

// 设置服务器信息
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY; // 监听所有IP
server.sin_port = htons(PORT);

// 绑定套接字
if (bind(server_socket, (struct sockaddr*)&server, sizeof(server)) < 0) {
perror("Bind failed");
close(server_socket);
return 1;
}

// 开始监听
listen(server_socket, SOMAXCONN);
printf("Server listening on port %d...\n", PORT);

// 主循环,接受客户端连接
while (1) {
client_socket = accept(server_socket, (struct sockaddr*)&client, &client_len);
if (client_socket < 0) {
perror("Accept failed");
continue;
}

// 处理请求
handle_request(client_socket);
}

// 关闭服务器套接字
close(server_socket);
return 0;
}

3. 运行结果

  1. 运行LinServer
  2. 在浏览器中访问http://127.0.0.1:8080/First/First.html
  3. 运行成功,显示绿字体

5. 修改程序,让程序可以解析javascript

1. 修改First.html

1
2
3
4
5
6
7
8
9
10
11
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>简单的JavaScript Hello World</title>
<script src="example.js"></script>
</head>
<body>
    HTML内容……
</body>
</html>

2.创建example.js

D:\First文件夹中创建example.js

1
2
3
4

document.write("Hello, world!"); // 直接插入页面中
alert("Hello, world!"); // 弹窗显示
console.log("Hello, world!"); // 在控制台(console)里显示,需要先开启开发工具控制台

3. 修改LinServer.c

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
126
127
// LinServer.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <fcntl.h>

#define PORT 8080
#define BUFFER_SIZE 1024
#define BASE_PATH "/home/kali/cc++/http/First/" // 基础文件路径,确保使用Linux格式的路径

void handle_request(int client_socket) {
char buffer[BUFFER_SIZE];
int bytes_received = recv(client_socket, buffer, sizeof(buffer) - 1, 0);
if (bytes_received > 0) {
buffer[bytes_received] = '\0'; // 添加字符串结束符
printf("Received request:\n%s\n", buffer);

// 解析请求行
char method[16], path[256], version[16];
sscanf(buffer, "%s %s %s", method, path, version);

// 响应内容
const char* response_header;
char response_body[BUFFER_SIZE];
FILE* file;

// 根据请求路径返回不同的响应
if (strcmp(method, "GET") == 0) {
// 构建文件路径
char file_path[BUFFER_SIZE];
snprintf(file_path, sizeof(file_path), "%s%s", BASE_PATH, path + 1); // 路径前加上基础路径,去掉前面的'/'

// 打开文件并读取内容
file = fopen(file_path, "r");
if (file) {
// 读取文件内容
size_t bytes_read = fread(response_body, sizeof(char), sizeof(response_body) - 1, file);
response_body[bytes_read] = '\0'; // 确保字符串结束
fclose(file);

// 确定 Content-Type
const char* content_type;
if (strstr(path, ".html")) {
content_type = "text/html";
}
else if (strstr(path, ".css")) {
content_type = "text/css";
}
else if (strstr(path, ".js")) { // 添加对JavaScript文件的支持
content_type = "application/javascript";
}
else {
content_type = "application/octet-stream"; // 默认类型
}

// 发送响应头
response_header = "HTTP/1.1 200 OK\r\n"
"Content-Type: %s\r\n"
"Content-Length: %lu\r\n"
"Connection: close\r\n\r\n";
char header[BUFFER_SIZE];
sprintf(header, response_header, content_type, bytes_read);
send(client_socket, header, strlen(header), 0);
send(client_socket, response_body, bytes_read, 0);
}
else {
// 文件未找到
response_header = "HTTP/1.1 404 Not Found\r\n"
"Content-Type: text/html\r\n"
"Connection: close\r\n\r\n";
const char* error_body = "<html><body><h1>404 Not Found</h1></body></html>";
send(client_socket, response_header, strlen(response_header), 0);
send(client_socket, error_body, strlen(error_body), 0);
}
}
}

// 关闭客户端套接字
close(client_socket);
}

int main() {
int server_socket, client_socket;
struct sockaddr_in server, client;
socklen_t client_len = sizeof(client);

// 创建套接字
server_socket = socket(AF_INET, SOCK_STREAM, 0);
if (server_socket < 0) {
perror("Could not create socket");
return 1;
}

// 设置服务器信息
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY; // 监听所有IP
server.sin_port = htons(PORT);

// 绑定套接字
if (bind(server_socket, (struct sockaddr*)&server, sizeof(server)) < 0) {
perror("Bind failed");
close(server_socket);
return 1;
}

// 开始监听
listen(server_socket, SOMAXCONN);
printf("Server listening on port %d...\n", PORT);

// 主循环,接受客户端连接
while (1) {
client_socket = accept(server_socket, (struct sockaddr*)&client, &client_len);
if (client_socket < 0) {
perror("Accept failed");
continue;
}

// 处理请求
handle_request(client_socket);
}

// 关闭服务器套接字
close(server_socket);
return 0;
}

4. 运行结果

  1. 运行LinServer

  2. 浏览器中访问http://127.0.0.1:8080/First/First.html

  3. 运行成功

6.设置utf8编码,并让客户端能去除html标签只显示文本内容

LinClient.c

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
//LinClient.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>

#define SERVER_IP "127.0.0.1" // 服务器IP地址
#define PORT 8080
#define BUFFER_SIZE 4096

void print_html_text(const char* response) {
const char* pos = response;
int in_tag = 0; // 标记是否在标签内

while (*pos) {
if (*pos == '<') {
in_tag = 1; // 进入标签
}
else if (*pos == '>') {
in_tag = 0; // 退出标签
}
else if (!in_tag) {
// 如果不在标签内,打印字符
putchar(*pos);
}
pos++;
}
}

void send_request(const char* path) {
int sock;
struct sockaddr_in server;
char request[BUFFER_SIZE];
char response[BUFFER_SIZE];
int bytes_received;
int header_end = 0; // 标记HTTP头部结束的位置

// 创建套接字
sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0) {
perror("Could not create socket");
return;
}

// 设置服务器信息
server.sin_family = AF_INET;
server.sin_addr.s_addr = inet_addr(SERVER_IP);
server.sin_port = htons(PORT);

// 连接到服务器
if (connect(sock, (struct sockaddr*)&server, sizeof(server)) < 0) {
perror("Connect failed");
close(sock);
return;
}

// 构建HTTP GET请求
sprintf(request, "GET %s HTTP/1.1\r\nHost: %s\r\nConnection: close\r\n\r\n", path, SERVER_IP);

// 发送请求
send(sock, request, strlen(request), 0);

// 接收响应
while ((bytes_received = recv(sock, response, sizeof(response) - 1, 0)) > 0) {
response[bytes_received] = '\0'; // 添加字符串结束符

// 查找HTTP头部结束的位置
if (!header_end) {
char* header_end_pos = strstr(response, "\r\n\r\n");
if (header_end_pos) {
header_end = 1; // 找到头部结束
*header_end_pos = '\0'; // 将头部结束符替换为字符串结束符
printf("HTTP Response Headers:\n%s\n", response); // 打印HTTP头部
print_html_text(header_end_pos + 4); // 打印HTML文本内容
}
else {
printf("%s", response); // 打印接收到的内容
}
}
else {
// 头部已经结束,直接打印HTML文本内容
print_html_text(response);
}
}

// 关闭套接字
close(sock);
}

int main() {
char path[256];

// 输入请求路径
printf("Enter the path to request (e.g., /index.html): ");
scanf("%s", path);

// 发送请求
send_request(path);

return 0;
}

LinServer.c

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
126
//LinServer.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>

#define PORT 8080
#define BUFFER_SIZE 1024
#define BASE_PATH "/home/kali/cc++/http/" // 基础文件路径,确保使用Linux格式的路径

void handle_request(int client_socket) {
char buffer[BUFFER_SIZE];
int bytes_received = recv(client_socket, buffer, sizeof(buffer) - 1, 0);
if (bytes_received > 0) {
buffer[bytes_received] = '\0'; // 添加字符串结束符
printf("Received request:\n%s\n", buffer);

// 解析请求行
char method[16], path[256], version[16];
sscanf(buffer, "%s %s %s", method, path, version);

// 响应内容
const char* response_header;
char response_body[BUFFER_SIZE];
FILE* file;

// 根据请求路径返回不同的响应
if (strcmp(method, "GET") == 0) {
// 构建文件路径
char file_path[BUFFER_SIZE];
snprintf(file_path, sizeof(file_path), "%s%s", BASE_PATH, path + 1); // 路径前加上基础路径,去掉前面的'/'

// 打开文件并读取内容
file = fopen(file_path, "rb"); // 以二进制模式打开文件
if (file) {
// 读取文件内容
size_t bytes_read = fread(response_body, sizeof(char), sizeof(response_body) - 1, file);
response_body[bytes_read] = '\0'; // 确保字符串结束
fclose(file);

// 确定 Content-Type
const char* content_type;
if (strstr(path, ".html")) {
content_type = "text/html; charset=utf-8"; // 添加字符集
}
else if (strstr(path, ".css")) {
content_type = "text/css; charset=utf-8"; // 添加字符集
}
else if (strstr(path, ".js")) {
content_type = "application/javascript; charset=utf-8"; // 添加字符集
}
else {
content_type = "application/octet-stream"; // 默认类型
}

// 发送响应头
response_header = "HTTP/1.1 200 OK\r\n"
"Content-Type: %s\r\n"
"Content-Length: %lu\r\n"
"Connection: close\r\n\r\n";
char header[BUFFER_SIZE];
sprintf(header, response_header, content_type, bytes_read);
send(client_socket, header, strlen(header), 0);
send(client_socket, response_body, bytes_read, 0);
}
else {
// 文件未找到
response_header = "HTTP/1.1 404 Not Found\r\n"
"Content-Type: text/html; charset=utf-8\r\n"
"Connection: close\r\n\r\n";
const char* error_body = "<html><body><h1>404 Not Found</h1></body></html>";
send(client_socket, response_header, strlen(response_header), 0);
send(client_socket, error_body, strlen(error_body), 0);
}
}
}

// 关闭客户端套接字
close(client_socket);
}

int main() {
int server_socket, client_socket;
struct sockaddr_in server, client;
socklen_t client_len = sizeof(client);

// 创建套接字
server_socket = socket(AF_INET, SOCK_STREAM, 0);
if (server_socket < 0) {
perror("Could not create socket");
return 1;
}

// 设置服务器信息
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY; // 监听所有IP
server.sin_port = htons(PORT);

// 绑定套接字
if (bind(server_socket, (struct sockaddr*)&server, sizeof(server)) < 0) {
perror("Bind failed");
close(server_socket);
return 1;
}

// 开始监听
listen(server_socket, SOMAXCONN);
printf("Server listening on port %d...\n", PORT);

// 主循环,接受客户端连接
while (1) {
client_socket = accept(server_socket, (struct sockaddr*)&client, &client_len);
if (client_socket < 0) {
perror("Accept failed");
continue;
}

// 处理请求
handle_request(client_socket);
}

// 关闭服务器套接字
close(server_socket);
return 0;
}

运行结果

  1. 运行LinServer

  2. 运行LinClient后输入html文件路径/First/First.html

  3. 运行成功

7. 用C语言在Linux中使用http协议浏览网页http://info.cern.ch/

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
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <netdb.h> // 包含 gethostbyname 的定义

#define SERVER "info.cern.ch" // 服务器地址
#define PORT 80 // HTTP端口
#define BUFFER_SIZE 4096

int main() {
int sock;
struct sockaddr_in server;
char request[BUFFER_SIZE], response[BUFFER_SIZE];
int bytes_received;

// 创建套接字
sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0) {
perror("Could not create socket");
return 1;
}

// 设置服务器信息
server.sin_family = AF_INET;
server.sin_port = htons(PORT);

// 将主机名转换为IP地址
struct hostent* host = gethostbyname(SERVER);
if (host == NULL) {
herror("Could not resolve hostname");
close(sock);
return 1;
}
memcpy(&server.sin_addr, host->h_addr, host->h_length);

// 连接到服务器
if (connect(sock, (struct sockaddr*)&server, sizeof(server)) < 0) {
perror("Connect failed");
close(sock);
return 1;
}

// 构建HTTP GET请求
sprintf(request, "GET / HTTP/1.1\r\n"
"Host: %s\r\n"
"Connection: close\r\n\r\n", SERVER);

// 发送请求
send(sock, request, strlen(request), 0);

// 接收响应
while ((bytes_received = recv(sock, response, sizeof(response) - 1, 0)) > 0) {
response[bytes_received] = '\0'; // 添加字符串结束符
printf("%s", response); // 打印响应
}

// 关闭套接字
close(sock);
return 0;
}