首先,创建一个控制台应用程序(包),向 Web 服务器发送一个 HTTP 请求。以前用 HttpClient 类实现了这个功能,但使用 TcpClient 类需要深入 HTTP 协议。
HttpClientUsingTcp 示例代码使用了以下名称空间:
System
System.IO
System.Net.Sockets
System.Text
System.Threading.Tasks
应用程序接受一个命令行参数,传递服务器的名称。这样,就调用RequestHtmlAsync 方法,向服务器发出 HTTP 请求。它用 Task 的 Result 属性返回一个字符串:
static void Main(string[] args)
{if (args.Length != 1){ShowUsage();}Task<string> tl = RequestHtmlAsync(args[0]); Console.WriteLine(t1.Result); Console.ReadLine();
}private static void ShowUsage()
{Console.WriteLine("Usage: HttpClientUsingTcp hostname");
}
现在看看 RequestHtmlAsync 方法的最重要部分。首先,实例化一个 TcpClient 对象。其次,使用 ConnectAsync 方法,在 HTTP 默认端口 80 上建立到主机的TCP 连接。再次,通过 GetStream 方法检索一个流,使用这个连接进行读写:
private const int ReadBufferSize = 1024;
public static async Task<string> RequestHtmlAsync(string hostname)
{try{using (var client = new TcpClient()){await client.ConnectAsync(hostname, 80); NetworkStream stream = client.GetStream();//...}}
}
流现在可以用来把请求写到服务器,读取响应。HTTP 是一种基于文本的协议,所以很容易在字符串中定义请求。为了向服务器发出一个简单的请求,标题定义了 HTTP 方法 GET,其后是 URL/ 的路径和 HTTP 版本 HTTP/1.1。第二行定义了 Host 标题、主机名和端口号,第三行定义了 Connection 标题。通常,通过Connection 标题,客户端请求 keep-alive,要求服务器保持连接打开,因为客户端希望发出更多的请求。这里只向服务器发出一个请求,所以服务器应该关闭连接,从而 close 设置为 Connection 标题。为了结束标题信息,需要使用 \r\n 给请求添加一个空行。标题信息调用 NetworkStream 的方法 WriteAsync,用UTF-8 编码发送。\r\n 为了立即向服务器发送缓存,请调用 FlushAsync 方法。否则数据就可能保存在本地缓存:
//...
string header = "GET/HTTP/1.1\r\n" +
$"Host: {hostname}:80\r\n" +
"Connection: close\r\n" +
"\r\n";
byte[] buffer = Encoding.UTF8.GetBytes(header);
await stream.WriteAsync(buffer, 0, buffer.Length);
await stream.FlushAsync();
现在可以继续这个过程,从服务器中读取回应。不知道回应有多大,所以创建一个动态生长的 MemoryStream。使用 ReadAsync 方法把服务器的回应暂时写入一个字节数组,这个字节数组的内容添加到 MemoryStream 中。从服务器中读取所有数据后,StreamReader 接管控制,把数据从流读入一个字符串,并返回给调用者:
var ms = new MemoryStream();
buffer = new byte[ReadBufferSize];
int read = 0;
do
{read = await stream.ReadAsync(buffer, 0, ReadBufferSize); ms.Write(buffer, 0, read);Array.Clear(buffer, 0, buffer.Length);} while (read > 0);ms.Seek(0, SeekOrigin.Begin);var reader = new StreamReader(ms); return reader.ReadToEnd();
}
//...
1
把一个网站传递给程序,会看到一个成功的请求,其 HTML 内容显示在控制台上。现在该创建一个 TCP 侦听器和自定义协议了。
微信公众号
Dotnet