C# 网络
最后修改于 2023 年 7 月 5 日
在本文中,我们将展示如何在 C# 中创建基本网络程序。
System.Net 命名空间为当今网络上使用的许多协议提供了一个简单的编程接口。
C# Uri
Uri 提供了统一资源标识符 (URI) 的对象表示形式,并可以轻松访问 URI 的各个部分。
var resource = "http://webcode.me:80/";
var resource2 = "http://webcode.me/index.html";
var resource3 = "http://www.webcode.me/name=Peter&age=23";
var path = new Uri(resource);
var path2 = new Uri(resource2);
var path3 = new Uri(resource3);
Console.WriteLine(path.Port);
Console.WriteLine(path.Host);
Console.WriteLine(path.Authority);
Console.WriteLine(path.LocalPath);
Console.WriteLine(path.Scheme);
Console.WriteLine("-----------------------");
Console.WriteLine(path2.Port);
Console.WriteLine(path2.LocalPath);
Console.WriteLine("-----------------------");
Console.WriteLine(path3.Authority);
Console.WriteLine(path3.PathAndQuery);
Console.WriteLine(path3.Query);
Console.WriteLine(path3.AbsolutePath);
Console.WriteLine(path3.AbsoluteUri);
在这个例子中,我们使用 Uri 类。
var resource = "http://webcode.me:80/"; var resource2 = "http://webcode.me/index.html"; var resource3 = "http://www.webcode.me/name=Peter&age=23";
我们定义三个资源路径。
var path = new Uri(resource); var path2 = new Uri(resource2); var path3 = new Uri(resource3);
从这些路径,我们创建 Web 资源。
Console.WriteLine(path.Port); Console.WriteLine(path.Host); Console.WriteLine(path.Authority); Console.WriteLine(path.LocalPath); Console.WriteLine(path.Scheme);
这里我们打印 Uri 的各个部分。
$ dotnet run 80 webcode.me webcode.me / http ----------------------- 80 /index.html ----------------------- www.webcode.me /name=Peter&age=23 /name=Peter&age=23 http://www.webcode.me/name=Peter&age=23
C# UriBuilder
UriBuilder 提供了一种方便的方法来修改 Uri 实例的内容,而无需为每个修改创建一个新的 Uri 实例。
using System.Net; var uriBuilder = new UriBuilder(); uriBuilder.Scheme = "http"; uriBuilder.Host = "webcode.me"; uriBuilder.Path = "/"; Uri uri = uriBuilder.Uri; WebRequest request = WebRequest.Create(uri); using WebResponse response = request.GetResponse(); var headers = response.Headers; Console.WriteLine(headers);
该示例使用 UriBuilder 构建一个 Uri,并向该资源发出一个简单的 GET 请求。
var uriBuilder = new UriBuilder(); uriBuilder.Scheme = "http"; uriBuilder.Host = "webcode.me"; uriBuilder.Path = "/"; Uri uri = uriBuilder.Uri;
我们使用 UriBuilder 构建 Uri。
WebRequest request = WebRequest.Create(uri);
我们使用 WebRequest 创建到 Uri 的 Web 请求。
using WebResponse response = request.GetResponse();
通过 GetResponse 方法,我们对 Uri 指定的资源发出同步请求。
var headers = response.Headers; Console.WriteLine(headers);
从响应中,我们获取标头并将它们打印到控制台。
$ dotnet run Server: nginx/1.6.2 Date: Wed, 10 Feb 2021 12:42:16 GMT Connection: keep-alive ETag: "5d32ffc5-15c" Access-Control-Allow-Origin: * Accept-Ranges: bytes Content-Type: text/html Content-Length: 348 Last-Modified: Sat, 20 Jul 2019 11:49:25 GMT
我们看到了服务器对我们请求的响应标头。
C# 主机名
Dns.GetHostName 方法获取本地计算机的主机名。
using System.Net;
var hostName = Dns.GetHostName();
Console.WriteLine($"Hostname: {hostName}");
该程序打印出我们本地计算机的主机名。
$ dotnet run Hostname: LAPTOP-OBLOFB9J
C# Dns.GetHostAddresses
Dns.GetHostAddresses 返回一个 IPAddress 类型的数组,其中包含主机的 IP 地址。
using System.Net;
var hostname = "something.com";
IPAddress[] addresses = Dns.GetHostAddresses(hostname);
foreach (IPAddress address in addresses)
{
Console.WriteLine($"{address}");
}
该示例打印出网页的所有 IP 地址。
$ dotnet run 2606:4700:3033::ac43:b7a8 2606:4700:3031::6815:3bce 172.67.183.168 104.21.59.206
C# GetHostEntry
使用 Dns.GetHostEntry 方法,我们可以从主机名确定 IP 地址。
using System.Net;
var name = "wikipedia.org";
IPHostEntry host = Dns.GetHostEntry(name);
var addresses = host.AddressList;
foreach (var address in addresses)
{
Console.WriteLine($"{address}");
}
该示例打印出 wikipedia.org 网站的 IP 地址。
var addresses = host.AddressList;
AddressList 属性包含与主机关联的 IP 地址列表。
$ dotnet run 2620:0:862:ed1a::1 91.198.174.192
输出由 IPv6 和 IPv4 地址组成。
C# Ping
Ping 是一种网络管理实用程序,用于测试 Internet 协议 (IP) 网络上主机的可用性。 Ping 的工作原理是向目标主机发送 Internet 控制消息协议 (ICMP) 回显请求数据包,并等待 ICMP 回显回复。 该程序报告错误、数据包丢失以及结果的统计摘要。
.NET 包含用于发送 ping 请求的 Ping 类。 Ping 类使用 PingReply 类的实例来返回有关操作的信息并接收回复。
using System.Net.NetworkInformation;
using var ping = new Ping();
PingReply reply = ping.Send("192.168.0.23", 100);
if (reply.Status == IPStatus.Success)
{
var msg = @$"Status: {reply.Status}
IP Address:{reply.Address}
Time:{reply.RoundtripTime}ms";
Console.WriteLine(msg);
}
else
{
Console.WriteLine(reply.Status);
}
我们向本地 lan 上的主机发送 Ping 请求。
PingReply reply = ping.Send("192.168.0.23", 100);
Send 方法尝试发送 ICMP 回显消息。 第二个参数是超时。
$ dotnet run Status: Success IP Address:192.168.0.23 Time:4ms
C# 套接字
在编程中,套接字是网络上两个程序之间通信的端点。 套接字用于在客户端程序和服务器程序之间创建连接。
System.Net.Sockets.Socket 类实现了 Berkeley 套接字接口。
using System.Text;
using System.Net;
using System.Net.Sockets;
string server = "webcode.me";
int port = 80;
var request = $"GET / HTTP/1.1\r\nHost: {server}\r\nConnection: Close\r\n\r\n";
Byte[] requestBytes = Encoding.ASCII.GetBytes(request);
Byte[] bytesReceived = new Byte[256];
IPHostEntry hostEntry = Dns.GetHostEntry(server);
var ipe = new IPEndPoint(hostEntry.AddressList[0], port);
using var socket = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
socket.Connect(ipe);
if (socket.Connected)
{
Console.WriteLine("Connection established");
}
else
{
Console.WriteLine("Connection failed");
return;
}
socket.Send(requestBytes, requestBytes.Length, 0);
int bytes = 0;
var sb = new StringBuilder();
do
{
bytes = socket.Receive(bytesReceived, bytesReceived.Length, 0);
sb.Append(Encoding.ASCII.GetString(bytesReceived, 0, bytes));
} while (bytes > 0);
Console.WriteLine(sb.ToString());
该示例使用 Socket 类向 HTTP 服务器发送数据并接收响应。 此示例会阻塞,直到收到整个页面。 请注意,套接字编程是低级的。 诸如 HttpWebRequest 或 HttpClient 之类的类抽象掉了这些低级细节。
string server = "webcode.me"; int port = 80;
我们定义服务器和端口。
var request = $"GET / HTTP/1.1\r\nHost: {server}\r\nConnection: Close\r\n\r\n";
我们定义一个 GET 请求。 GET 请求以 GET 命令开头,后跟资源 URL 和 HTTP 协议版本。 请注意,\r\n 字符是通信过程的强制部分。 详细信息在 RFC 7231 文档中描述。
Byte[] requestBytes = Encoding.ASCII.GetBytes(request);
我们将请求的文本数据转换为字节。
Byte[] bytesReceived = new Byte[256];
这个字节数组用于来自服务器的数据。
IPHostEntry hostEntry = Dns.GetHostEntry(server);
通过 Dns.GetHostEntry,我们找出域名对应的 IP 地址。
var ipe = new IPEndPoint(hostEntry.AddressList[0], port);
我们创建一个 IPEndPoint; 它是一个网络端点,由 IP 地址和端口号组成。 IP 地址是从 AddressList 属性检索的。
using var socket = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
创建一个新的 TCP 套接字。 AddressFamily.InterNetwork 指定我们使用 IPv4 地址。 SocketType.Stream 提供可靠的、双向的、基于连接的字节流。 ProtocolType.Tcp 确定协议类型。
socket.Connect(ipe);
Connect 方法使用给定的 IPEndPoint 连接到网络端点。
if (socket.Connected)
{
Console.WriteLine("Connection established");
}
else
{
Console.WriteLine("Connection failed");
return;
}
我们检查是否已成功连接。
socket.Send(requestBytes, requestBytes.Length, 0);
我们使用 Send 方法将请求发送到服务器。
do
{
bytes = socket.Receive(bytesReceived, bytesReceived.Length, 0);
sb.Append(Encoding.ASCII.GetString(bytesReceived, 0, bytes));
} while (bytes > 0);
我们使用 Receive 方法从套接字获取数据。 我们使用 GetString 方法将字节转换为文本,并将文本数据添加到 StringBuilder 中。
Console.WriteLine(sb.ToString());
最后,文本数据被写入控制台。
C# UdpClient
UdpClient 提供用户数据报协议 (UDP) 网络服务。 它包含以阻塞同步模式发送和接收无连接 UDP 数据报的方法。 由于 UDP 是一种无连接传输协议,因此我们不需要在发送和接收数据之前建立远程主机连接。
由于安全问题,大多数公共服务器不再提供回显服务。 为了测试该示例,我们需要在本地 lan 上设置一个服务器并启用 xinetd (Debian) 或 inetd (FreeBSD) 守护程序。
using System.Text;
using System.Net;
using System.Net.Sockets;
UdpClient udpClient = new UdpClient("core9", 7);
Byte[] data = Encoding.ASCII.GetBytes("Hello there");
udpClient.Send(data, data.Length);
IPEndPoint RemoteIpEndPoint = new IPEndPoint(IPAddress.Any, 0);
Byte[] received = udpClient.Receive(ref RemoteIpEndPoint);
string output = Encoding.ASCII.GetString(received);
Console.WriteLine(output);
udpClient.Close();
该示例将消息发送到回显服务。 这是一种用于测试目的的简单服务。 回显服务在端口 7 上侦听。请注意,该服务可以在 TCP 或 UDP 上运行。
$ dotnet run Hello there
我们发送的消息会回显给我们。
C# TcpClient
TcpClient 类使用 TCP 从 Internet 资源请求数据。 TcpClient 抽象了创建 Socket 以通过 TCP 请求和接收数据的低级细节。
由于与远程设备的连接表示为流,因此可以使用 .NET 流处理技术来读取和写入数据。
using System.Text; using System.Net.Sockets; using var client = new TcpClient(); var hostname = "webcode.me"; client.Connect(hostname, 80); using NetworkStream networkStream = client.GetStream(); networkStream.ReadTimeout = 2000; var message = @"GET / HTTP/1.1 Accept: text/html, charset=utf-8 Accept-Language: en-US User-Agent: Console app Connection: close Host: webcode.me" + "\r\n\r\n"; using var reader = new StreamReader(networkStream, Encoding.UTF8); byte[] bytes = Encoding.UTF8.GetBytes(message); networkStream.Write(bytes, 0, bytes.Length); Console.WriteLine(reader.ReadToEnd());
该示例使用 TcpClient 创建一个 GET 请求。
using var client = new TcpClient(); var hostname = "webcode.me"; client.Connect(hostname, 80);
创建一个 TCP 客户端。 我们使用 Connect 方法连接到远程主机。
using NetworkStream networkStream = client.GetStream(); networkStream.ReadTimeout = 2000;
使用 GetStream 方法,我们获得一个网络流。 我们将超时设置为两秒。
var message = @"GET / HTTP/1.1 Accept: text/html, charset=utf-8 Accept-Language: en-US User-Agent: Console app Connection: close Host: webcode.me" + "\r\n\r\n";
我们构建 GET 请求消息。 不支持持久连接的 HTTP/1.1 应用程序必须在每条消息中包含 close 连接选项。
using var reader = new StreamReader(networkStream, Encoding.UTF8); byte[] bytes = Encoding.UTF8.GetBytes(message);
对于来自服务器的响应,我们创建一个 StreamReader。 我们使用 GetBytes 方法将文本数据转换为字节。
networkStream.Write(bytes, 0, bytes.Length);
我们使用 Write 方法将消息写入网络流。
Console.WriteLine(reader.ReadToEnd());
我们使用 ReadToEnd 方法读取响应。
C# FtpWebRequest
FtpWebRequest 实现了文件传输协议 (FTP) 客户端。
using System.Net;
string uri = "ftp://192.168.0.21";
FtpWebRequest ftpRequest = (FtpWebRequest)WebRequest.Create(uri);
ftpRequest.Credentials = new NetworkCredential("user7", "s$cret");
ftpRequest.Method = WebRequestMethods.Ftp.ListDirectory;
using FtpWebResponse response = (FtpWebResponse)ftpRequest.GetResponse();
using var streamReader = new StreamReader(response.GetResponseStream());
var content = new List<string>();
string line = streamReader.ReadLine();
while (!string.IsNullOrEmpty(line))
{
content.Add(line);
line = streamReader.ReadLine();
}
foreach (var el in content)
{
Console.WriteLine(el);
}
该示例列出了 FTP 目录上的内容。
string uri = "ftp://192.168.0.21";
这是本地 FTP 服务器上的 URL 路径。
FtpWebRequest ftpRequest = (FtpWebRequest)WebRequest.Create(uri);
从 URI 中,我们创建 FtpWebRequest。
ftpRequest.Credentials = new NetworkCredential("user7", "s$cret");
ftpRequest.Method = WebRequestMethods.Ftp.ListDirectory;
我们提供凭据和 FTP 方法; 我们将列出目录的内容。
using FtpWebResponse response = (FtpWebResponse)ftpRequest.GetResponse(); using var streamReader = new StreamReader(response.GetResponseStream());
我们获取响应并创建一个流读取器来读取它。
var content = new List<string>();
string line = streamReader.ReadLine();
while (!string.IsNullOrEmpty(line))
{
content.Add(line);
line = streamReader.ReadLine();
}
数据被读入列表中。
foreach (var el in content)
{
Console.WriteLine(el);
}
最后,内容被打印到控制台。
C# SmtpClient
SmtpClient 允许应用程序使用简单邮件传输协议 (SMTP) 发送电子邮件。
请注意,该类被标记为已过时,建议使用 MailKit 库来处理电子邮件。
using System.Net.Mail;
var client = new SmtpClient("core9", 25);
using var msg = new MailMessage();
msg.From = new MailAddress("john.doe@example.com");
msg.Subject = "Hello";
msg.Body = "hello there";
msg.To.Add(new MailAddress("root@core9"));
client.Send(msg);
该示例将一封简单的邮件发送到本地网络上的服务器。
C# HttpClient
HttpClient 是一个基类,用于发送 HTTP 请求和接收来自 URI 标识的资源的 HTTP 响应。
using var client = new HttpClient();
var result = await client.GetAsync("http://webcode.me");
Console.WriteLine(result.StatusCode);
此示例创建一个 GET 请求到一个小型网站。我们获取请求的状态码。
using var client = new HttpClient();
创建一个新的 HttpClient。
var result = await client.GetAsync("http://webcode.me");
GetAsync 方法以异步操作向指定的 Uri 发送 GET 请求。 await 运算符暂停封闭 async 方法的评估,直到异步操作完成。 当异步操作完成时,await 运算符返回操作的结果(如果有)。
$ dotnet run OK
我们获得 200 OK 状态代码; 该网站已启动。
C# HttpListener
HttpListener 是一个简单的、以编程方式控制的 HTTP 协议监听器。
using System.Net;
using System.Text;
using var listener = new HttpListener();
listener.Prefixes.Add("https://:8001/");
listener.Start();
Console.WriteLine("Listening on port 8001...");
while (true)
{
HttpListenerContext context = listener.GetContext();
HttpListenerRequest req = context.Request;
using Stream ris = req.InputStream;
using StreamReader sr = new StreamReader(ris, Encoding.UTF8);
string doc = sr.ReadToEnd();
Console.WriteLine($"Received request for {req.Url}");
Console.WriteLine(doc);
HttpListenerResponse resp = context.Response;
string data = "Hello there!";
byte[] buffer = Encoding.UTF8.GetBytes(data);
resp.ContentLength64 = buffer.Length;
Stream ros = resp.OutputStream;
ros.Write(buffer, 0, buffer.Length);
ros.Close();
}
该示例创建一个简单的 HTTP 服务器。
using var listener = new HttpListener();
listener.Prefixes.Add("https://:8001/");
listener.Start();
我们创建一个在端口 8001 上监听的监听器。
HttpListenerContext context = listener.GetContext(); HttpListenerRequest req = context.Request;
通过 GetContext,我们等待传入请求,并在收到请求时返回。
using Stream ris = req.InputStream;
using StreamReader sr = new StreamReader(ris, Encoding.UTF8);
string doc = sr.ReadToEnd();
Console.WriteLine($"Received request for {req.Url}");
Console.WriteLine(doc);
服务器将请求记录到终端。
HttpListenerResponse resp = context.Response; string data = "Hello there!"; byte[] buffer = Encoding.UTF8.GetBytes(data); resp.ContentLength64 = buffer.Length;
我们构建响应对象。
Stream ros = resp.OutputStream; ros.Write(buffer, 0, buffer.Length);
服务器使用 Write 将数据写入响应输出流。
来源
在本文中,我们使用 C# 创建了一些基本的网络编程。
作者
列出所有 C# 教程。