C#中使用Socket请求Web服务器过程

news/2024/10/14 16:43:00

最开始我们需要明白一件事情,因为这是这篇文章的前提:

HTTP协议只是一个应用层协议,它底层是通过TCP进行传输数据的。因此,浏览器访问Web服务器的过程必须先有“连接建立”的发生。

而有人或许会问:众所周知,HTTP协议有两大特性,一个是“无连接”性,一个是“无状态”性。这里的“无连接”岂不是跟上面的说法有冲突?其实这里并没有矛盾,
只是人们对“连接”这个词的理解有差异。首先我们来看一下浏览器向Web服务器发出Http请求以及Web服务器给浏览器回复的过程:
  1. 浏览器创建Socket,按给定IP(域名)和端口(默认为80)连接服务器。比如使用类似Socket.Connect()、Socket.BeginConnect()等方法;
  2. 连接成功后,浏览器依据HTTP协议规范(关于协议,后面有讲到),向Web服务器发送请求数据。比如“请求行”、“请求头标”以及“请求数据”等,这里可能使用类似Socket.Send()、Socket.BeginSend()等方法。【关于HTTP协议中的请求行、请求头标等请参见http://www.cnblogs.com/riky/archive/2007/04/09/705848.html】
  3. 浏览器等待服务器处理并返回数据;
  4. Web服务器端使用Socket.Accept()、Socket.BeginAccept()等方法侦听到浏览器的连接后,便开始接收浏览器发送的数据。接收到请求数据后,依据HTTP协议规范解析数据,然后处理,最终将处理结果(如html文档)发回给浏览器,这里可能用到类似Socket.Send()、Socket.BeginSend()等方法;
  5. Web服务器发送完处理结果后,关闭Socket;
  6. 浏览器接收Web服务器发回的数据(如html),将其显示在浏览器UI界面。关闭socket;
  7. 一次“浏览器到Web服务器”的http请求结束;
  8. 下一次浏览器需要请求Web服务器,跳转到第1)步循环开始。

如上图所示。浏览器向Web服务器发送http请求之前,需要先建立连接。没错,它们间建立连接的过程跟我们平时开发socket程序类似。由此可知,
HTTP协议的“无连接”特性并不是指:浏览器与Web服务器进行数据交换时,不需要建立连接。那么“无连接”特性到底指什么呢?我们再看图1会发现,
浏览器每次请求完毕后都会与服务器处于“断开”状态,下一次请求时再重新与服务器建立连接。HTTP的无连接特性恰恰就是指浏览器的每次请求都必须重新与服务器建立连接,
正常情况下,浏览器不会与Web服务器保持长时间的连接状态。现将HTTP协议的两大特性归结如下:

 

 以下是发送HTTP请求的代码:

  /// <summary>2         /// 发送请求3         /// </summary>4         /// <param name="socket"></param>5         private void SendRequest(Socket socket)6         {7             string h1 = "GET " + _path + " HTTP/1.1\r\n";8             string h2 = "Accept: */*\r\n";9             string h3 = "Accept-Language: zh-cn\r\n";
10             string h4 = "Host: " + _host + "\r\n";
11             string h5 = "User-Agent: Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.116 Safari/537.36\r\n";
12             string h7 = "Connection: close\r\n\r\n";
13 
14             byte[] send_buffer = Encoding.UTF8.GetBytes(h1 + h2 + h3 + h4 + h5 + h7);
15             socket.Send(send_buffer);
16             Print("请求发送完毕,等待Web Server回复...");
17             socket.BeginReceive(_buffer, 0, 640 * 1024, SocketFlags.None, new AsyncCallback(OnReceive), socket);
18         }

源码下载:https://files.cnblogs.com/xiaozhi_5638/socket_browser.rar
作者:周见智
出处:http://www.cnblogs.com/xiaozhi_5638/
首发公众号,扫描二维码关注公众号,分享原创计算机视觉/深度学习/算法落地相关文章
来源:https://www.cnblogs.com/xiaozhi_5638/p/3912668.html

 

public partial class Form1 : Form{Socket _socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);  //客户端socketbyte[] _buffer = new byte[1024 * 640];  //接收缓冲区IPAddress _ip;  //当前请求主机IPint _port;  //当前请求主机Portstring _path;  //当前请求url(除去主机部分)string _host; //当前请求url(主机部分)bool _isBusy = false;public Form1(){InitializeComponent();}private void Form1_Load(object sender, EventArgs e){}/// <summary>/// 访问/// </summary>/// <param name="sender"></param>/// <param name="e"></param>private void button1_Click(object sender, EventArgs e){if (_isBusy)return;if (textBox2.Text != ""){_socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);_isBusy = true;Uri u = new Uri(textBox2.Text);_ip = Dns.GetHostByName(u.Host).AddressList[0];_port = u.Port;_path = u.AbsolutePath;_host = u.Authority;Print("开始连接Web Server...");Print("Web Server信息:【" + "IP:" + _ip.ToString() + "     端口:" + _port + "");_socket.BeginConnect(new IPEndPoint(_ip, _port), new AsyncCallback(OnConnect), _socket);  //使用socket连接web server
            }}/// <summary>/// 异步连接 回调/// </summary>/// <param name="ar"></param>private void OnConnect(IAsyncResult ar){Socket socket = ar.AsyncState as Socket;try{socket.EndConnect(ar);Print("连接Web Server完成, 本地socket端口:"+ (_socket.LocalEndPoint as IPEndPoint).Port);Print("开始向Web Server请求数据...");SendRequest(socket);}catch{Print("连接Web Server失败!");_isBusy = false;}}/// <summary>/// 异步接收数据 回调/// </summary>/// <param name="ar"></param>private void OnReceive(IAsyncResult ar){Socket socket = ar.AsyncState as Socket;try{int real_recv = socket.EndReceive(ar);  string recv_str = Encoding.UTF8.GetString(_buffer, 0, real_recv); //第一次接收数据while ((real_recv = socket.Receive(_buffer)) != 0)  //循环接收剩余数据
                {recv_str += Encoding.UTF8.GetString(_buffer, 0, real_recv);}Print("收到Web Server的回复:");Print("\r\n"+recv_str);  //输出到界面
            }catch{}finally{_isBusy = false;_socket.Close();}}/// <summary>/// 发送请求/// </summary>/// <param name="socket"></param>private void SendRequest(Socket socket){string h1 = "GET" + _path + " HTTP/1.1\r\n";string h2 = "Accept: */*\r\n";string h3 = "Accept-Language: zh-cn\r\n";string h4 = "Host: " + _host + "\r\n";string h5 = "User-Agent: Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.116 Safari/537.36\r\n";string h7 = "Connection: close\r\n\r\n";byte[] send_buffer = Encoding.UTF8.GetBytes(h1 + h2 + h3 + h4 + h5 + h7);socket.Send(send_buffer);Print("请求发送完毕,等待Web Server回复...");socket.BeginReceive(_buffer, 0, 640 * 1024, SocketFlags.None, new AsyncCallback(OnReceive), socket);}/// <summary>/// 输出信息/// </summary>/// <param name="info"></param>private void Print(string info){if (this.InvokeRequired){this.Invoke((Action)delegate(){DateTime now = DateTime.Now;string time_str = now.ToString("hh:mm:ss");textBox1.AppendText(time_str + " " + info + "\r\n");});}else{DateTime now = DateTime.Now;string time_str = now.ToString("hh:mm:ss");textBox1.AppendText(time_str + " " + info + "\r\n");}}}

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.ryyt.cn/news/71503.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈,一经查实,立即删除!

相关文章

新蜀门+单机版安装教程+虚拟机一键端+GM

今天给大家带来一款单机游戏的架设:新蜀门。本版本支持win64位系统 另外:本人承接各种游戏架设(单机+联网) 本人为了学习和研究软件内含的设计思想和原理,带了架设教程仅供娱乐。 教程是本人亲自搭建成功的,绝对是完整可运行的,踩过的坑都给你们填上了。如果你是小白也没…

一文为你解读MySQL8.0 Instant DDL源码实现

MySQL 8.0.12版本引入了INSTANT(即时)算法,对部分ADD COLUMN操作,不再修改用户原有数据,只需对表元信息进行修改。一、背景介绍 数据库中每一行数据都被持久化存储在磁盘中。当我们对表进行ADD/DROP COLUMN操作时,磁盘中的数据也会相应地被修改,所需时间与对应表的大小成…

csp-s模拟11

E题面最暴力的做法,枚举连续段长度\(i\),然后暴力搜索,复杂度\(O(n^3)\)点击查看代码 #include <bits/stdc++.h> #define speed() ios::sync_with_stdio(false),cin.tie(0),cout.tie(0); #define ll long long #define pb push_back #define ull unsigned long long #de…

高等数学 5.1 定积分的概念与性质

目录一、定积分的定义1.定义2.定积分的几何意义二、定积分的近似计算1.矩形法2.梯形法3.抛物线法三、定积分的性质 一、定积分的定义 1.定义定义 设函数 \(f(x)\) 在 \([a, b]\) 上有界,在 \([a, b]\) 中任意插入若干个分点 \[a = x_0 < x_1 < x_2 < \cdots < x_{…

PARTI-Oracle关系数据结构-索引和索引组织表

3. 索引和索引组织表 3.1. 索引概述 索引是与表或表簇关联的可选结构,有时可以加快数据访问速度。通过在表的一个或多个列上创建索引,在某些情况下,可以从表中检索一小部分随机分布的行。索引是减少磁盘I/O的众多方法之一。如果堆组织表没有索引,那么数据库必须执行全表扫描…

5分钟学会使用Linux的 grep、find、ls、wc 命令

01 概述 本系列主要讲解Linux运行时命令,包括网络、磁盘、内存、CPU相关参数等,主要是为了分享怎么通过常见的 Linux 命令去排查相关问题。比如:发现机器的CPU负荷比较高,那么怎么查到是哪个进程CPU占用率比较高?磁盘IO的写入很频繁,怎么查到是哪个进程或线程对磁盘IO频…

python3.6 解析svg保存到mysql

1 import json2 from collections import Counter3 from json import JSONDecodeError4 5 import mysql6 import requests7 from lxml import etree8 9 # 定义远程 SVG 文件的 URL10 file = rD:\tmp_files\jmx\0919_3568.txt11 data_to_insert=[]12 with open(file, r, encodin…