一起Talk Android吧(第三百三十一回: HTTP协议概述)

本文介绍了HTTP协议的基础,包括其在TCP/IP体系中的位置,请求响应模式,以及请求报文和响应报文的构成。重点讲解了报文结构和常见状态码,并通过实例帮助理解其在实际应用中的操作方式。

各位看官们,大家好,上一回中咱们说的是Android中网络通信之UDP 通过演示的例子,这一回中咱们说的例子是HTTP协议概述。闲话休提,言归正转。让我们一起Talk Android吧!

看官们,我们在前面章回中介绍了TCP和UDP通信相关的内容,接下来的章回中将介绍HTTP通信相关的内容,在此之前,先介绍HTTP协议

有看官提问,之前介绍TCP和UDP通信时也没有介绍这些协议,为会在这里突然介绍协议?因为我们使用的是Socket接口,这些接口封装了协议的细节,因此我们更多地关注于接口的使用而不是协议的细节,而HTTP协议虽然也有接口,但是需要了解一些细节才能更好地使用接口。下面我们将对HTTP协议做概要性的介绍。

HTTP协议是在TCP和UDP上层的协议,我们上网浏览网页时使用的就是此协议。它是一种请求响应式的协议。客户端(浏览器)向服务端(服务器)发起请求,服务端进行响应。请求和响应的内容分别叫作请求报文和响应报文,报文的内容都是ASII码串,报文的结构有着明确的要求,比如请求报文由头部、空行、主体三个结构组成,每个结构中又划分成小的结构,这些小结构占用多大字节等等。这些细节都可以在协议中查找到,我们写程序的时候需要了解这些细节才能去发起请求。下面是请求报文和响应报文的大体组成结构.
在这里插入图片描述

此图形来自《图解HTTP》,它只有大的结构划分,没有列出每个结构的大小。大家可以自行查找资料。

我们还需要了解的是常见的请求方法和响应结果的状态码。下面是请求报文的截图,请大家参考:
在这里插入图片描述

下面是响应报文的截图,请大家参考:

在这里插入图片描述

此图形来自《图解HTTP》,响应状态码中只是大的归类,没有具体到值,大家可以自行查找具体的值。

看官们,关于HTTP协议概述的例子咱们就介绍到这里,欲知后面还有什么例子,且听下回分解!

int FirstStageMain(int argc, char** argv) { 185 if (REBOOT_BOOTLOADER_ON_PANIC) { 186 InstallRebootSignalHandlers(); 187 } 188 189 boot_clock::time_point start_time = boot_clock::now(); 190 191 std::vector<std::pair<std::string, int>> errors; 192 #define CHECKCALL(x) \ 193 if ((x) != 0) errors.emplace_back(#x " failed", errno); 194 195 // Clear the umask. 196 umask(0); 197 198 CHECKCALL(clearenv()); 199 CHECKCALL(setenv("PATH", _PATH_DEFPATH, 1)); 200 // Get the basic filesystem setup we need put together in the initramdisk 201 // on / and then we'll let the rc file figure out the rest. 202 CHECKCALL(mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755")); 203 CHECKCALL(mkdir("/dev/pts", 0755)); 204 CHECKCALL(mkdir("/dev/socket", 0755)); 205 CHECKCALL(mkdir("/dev/dm-user", 0755)); 206 CHECKCALL(mount("devpts", "/dev/pts", "devpts", 0, NULL)); 207 #define MAKE_STR(x) __STRING(x) 208 CHECKCALL(mount("proc", "/proc", "proc", 0, "hidepid=2,gid=" MAKE_STR(AID_READPROC))); 209 #undef MAKE_STR 210 // Don't expose the raw commandline to unprivileged processes. 211 CHECKCALL(chmod("/proc/cmdline", 0440)); 212 std::string cmdline; 213 android::base::ReadFileToString("/proc/cmdline", &cmdline); 214 // Don't expose the raw bootconfig to unprivileged processes. 215 chmod("/proc/bootconfig", 0440); 216 std::string bootconfig; 217 android::base::ReadFileToString("/proc/bootconfig", &bootconfig); 218 gid_t groups[] = {AID_READPROC}; 219 CHECKCALL(setgroups(arraysize(groups), groups)); 220 CHECKCALL(mount("sysfs", "/sys", "sysfs", 0, NULL)); 221 CHECKCALL(mount("selinuxfs", "/sys/fs/selinux", "selinuxfs", 0, NULL)); 222 223 CHECKCALL(mknod("/dev/kmsg", S_IFCHR | 0600, makedev(1, 11))); 224 225 if constexpr (WORLD_WRITABLE_KMSG) { 226 CHECKCALL(mknod("/dev/kmsg_debug", S_IFCHR | 0622, makedev(1, 11))); 227 } 228 229 CHECKCALL(mknod("/dev/random", S_IFCHR | 0666, makedev(1, 8))); 230 CHECKCALL(mknod("/dev/urandom", S_IFCHR | 0666, makedev(1, 9))); 231 232 // This is needed for log wrapper, which gets called before ueventd runs. 233 CHECKCALL(mknod("/dev/ptmx", S_IFCHR | 0666, makedev(5, 2))); 234 CHECKCALL(mknod("/dev/null", S_IFCHR | 0666, makedev(1, 3))); 235 236 // These below mounts are done in first stage init so that first stage mount can mount 237 // subdirectories of /mnt/{vendor,product}/. Other mounts, not required by first stage mount, 238 // should be done in rc files. 239 // Mount staging areas for devices managed by vold 240 // See storage config details at http://source.android.com/devices/storage/ 241 CHECKCALL(mount("tmpfs", "/mnt", "tmpfs", MS_NOEXEC | MS_NOSUID | MS_NODEV, 242 "mode=0755,uid=0,gid=1000")); 243 // /mnt/vendor is used to mount vendor-specific partitions that can not be 244 // part of the vendor partition, e.g. because they are mounted read-write. 245 CHECKCALL(mkdir("/mnt/vendor", 0755)); 246 // /mnt/product is used to mount product-specific partitions that can not be 247 // part of the product partition, e.g. because they are mounted read-write. 248 CHECKCALL(mkdir("/mnt/product", 0755)); 249 250 // /debug_ramdisk is used to preserve additional files from the debug ramdisk 251 CHECKCALL(mount("tmpfs", "/debug_ramdisk", "tmpfs", MS_NOEXEC | MS_NOSUID | MS_NODEV, 252 "mode=0755,uid=0,gid=0")); 253 254 // /second_stage_resources is used to preserve files from first to second 255 // stage init 256 CHECKCALL(mount("tmpfs", kSecondStageRes, "tmpfs", MS_NOEXEC | MS_NOSUID | MS_NODEV, 257 "mode=0755,uid=0,gid=0")) 258 //#ifdef OPLUS_FEATURE_PHOENIX 259 //martin.li@kernel.stability, 2021/07/21, add for oplusreserve* mount point 260 CHECKCALL(mkdir("/mnt/oplus", 0755)); 261 //#endif 262 #undef CHECKCALL 263 264 SetStdioToDevNull(argv); 265 // Now that tmpfs is mounted on /dev and we have /dev/kmsg, we can actually 266 // talk to the outside world... 267 InitKernelLogging(argv); 268 269 if (!errors.empty()) { 270 for (const auto& [error_string, error_errno] : errors) { 271 LOG(ERROR) << error_string << " " << strerror(error_errno); 272 } 273 LOG(FATAL) << "Init encountered errors starting first stage, aborting"; 274 } 275 276 LOG(INFO) << "init first stage started!"; 277 278 auto old_root_dir = std::unique_ptr<DIR, decltype(&closedir)>{opendir("/"), closedir}; 279 if (!old_root_dir) { 280 PLOG(ERROR) << "Could not opendir(\"/\"), not freeing ramdisk"; 281 } 282 283 struct stat old_root_info; 284 if (stat("/", &old_root_info) != 0) { 285 PLOG(ERROR) << "Could not stat(\"/\"), not freeing ramdisk"; 286 old_root_dir.reset(); 287 } 288 289 auto want_console = ALLOW_FIRST_STAGE_CONSOLE ? FirstStageConsole(cmdline, bootconfig) : 0; 290 291 boot_clock::time_point module_start_time = boot_clock::now(); 292 int module_count = 0; 293 if (!LoadKernelModules(IsRecoveryMode() && !ForceNormalBoot(cmdline, bootconfig), want_console, 294 module_count)) { 295 if (want_console != FirstStageConsoleParam::DISABLED) { 296 LOG(ERROR) << "Failed to load kernel modules, starting console"; 297 } else { 298 LOG(FATAL) << "Failed to load kernel modules"; 299 } 300 } 301 if (module_count > 0) { 302 auto module_elapse_time = std::chrono::duration_cast<std::chrono::milliseconds>( 303 boot_clock::now() - module_start_time); 304 setenv(kEnvInitModuleDurationMs, std::to_string(module_elapse_time.count()).c_str(), 1); 305 LOG(INFO) << "Loaded " << module_count << " kernel modules took " 306 << module_elapse_time.count() << " ms"; 307 } 308 309 310 bool created_devices = false; 311 if (want_console == FirstStageConsoleParam::CONSOLE_ON_FAILURE) { 312 if (!IsRecoveryMode()) { 313 created_devices = DoCreateDevices(); 314 if (!created_devices){ 315 LOG(ERROR) << "Failed to create device nodes early"; 316 } 317 } 318 StartConsole(cmdline); 319 } 320 321 if (access(kBootImageRamdiskProp, F_OK) == 0) { 322 std::string dest = GetRamdiskPropForSecondStage(); 323 std::string dir = android::base::Dirname(dest); 324 std::error_code ec; 325 if (!fs::create_directories(dir, ec) && !!ec) { 326 LOG(FATAL) << "Can't mkdir " << dir << ": " << ec.message(); 327 } 328 if (!fs::copy_file(kBootImageRamdiskProp, dest, ec)) { 329 LOG(FATAL) << "Can't copy " << kBootImageRamdiskProp << " to " << dest << ": " 330 << ec.message(); 331 } 332 LOG(INFO) << "Copied ramdisk prop to " << dest; 333 } 334 335 // If "/force_debuggable" is present, the second-stage init will use a userdebug 336 // sepolicy and load adb_debug.prop to allow adb root, if the device is unlocked. 337 if (access("/force_debuggable", F_OK) == 0) { 338 std::error_code ec; // to invoke the overloaded copy_file() that won't throw. 339 if (!fs::copy_file("/adb_debug.prop", kDebugRamdiskProp, ec) || 340 !fs::copy_file("/userdebug_plat_sepolicy.cil", kDebugRamdiskSEPolicy, ec)) { 341 LOG(ERROR) << "Failed to setup debug ramdisk"; 342 } else { 343 // setenv for second-stage init to read above kDebugRamdisk* files. 344 setenv("INIT_FORCE_DEBUGGABLE", "true", 1); 345 } 346 } 347 348 if (ForceNormalBoot(cmdline, bootconfig)) { 349 mkdir("/first_stage_ramdisk", 0755); 350 // SwitchRoot() must be called with a mount point as the target, so we bind mount the 351 // target directory to itself here. 352 if (mount("/first_stage_ramdisk", "/first_stage_ramdisk", nullptr, MS_BIND, nullptr) != 0) { 353 LOG(FATAL) << "Could not bind mount /first_stage_ramdisk to itself"; 354 } 355 SwitchRoot("/first_stage_ramdisk"); 356 } 357 358 if (!DoFirstStageMount(!created_devices)) { 359 LOG(FATAL) << "Failed to mount required partitions early ..."; 360 } 361 362 struct stat new_root_info; 363 if (stat("/", &new_root_info) != 0) { 364 PLOG(ERROR) << "Could not stat(\"/\"), not freeing ramdisk"; 365 old_root_dir.reset(); 366 } 367 368 if (old_root_dir && old_root_info.st_dev != new_root_info.st_dev) { 369 FreeRamdisk(old_root_dir.get(), old_root_info.st_dev); 370 } 371 372 SetInitAvbVersionInRecovery(); 373 374 setenv(kEnvFirstStageStartedAt, std::to_string(start_time.time_since_epoch().count()).c_str(), 375 1); 376 LOG(INFO) << "init first stage completed!"; 377 378 const char* path = "/system/bin/init"; 379 const char* args[] = {path, "selinux_setup", nullptr}; 380 auto fd = open("/dev/kmsg", O_WRONLY | O_CLOEXEC); 381 dup2(fd, STDOUT_FILENO); 382 dup2(fd, STDERR_FILENO); 383 close(fd); 384 execv(path, const_cast<char**>(args)); 385 386 // execv() only returns if an error happened, in which case we 387 // panic and never fall through this conditional. 388 PLOG(FATAL) << "execv(\"" << path << "\") failed"; 389 390 return 1; 391 } 392 393 } // namespace init 394 } // namespace android 395
07-22
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

talk_8

真诚赞赏,手有余香

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值