在本文中,我们展示了如何在C#中使用套接字。
网络协议
TCP/IP是设备用来通过Internet和大多数本地网络进行通信的一套协议。TCP更可靠,具有广泛的错误检查,并且需要更多资源。它由HTTP、SMTP或FTP等服务使用。UDP的可靠性低得多,错误检查有限,并且需要的资源较少。它被VoIP等服务使用。
套接字
在编程中,套接字是网络上运行的两个程序之间通信的端点。在.NET中,Socket
类为网络通信提供了一组丰富的方法和属性。它允许我们执行同步和异步数据传输。
C#UDP套接字示例
UDP是一种通过网络传输独立数据包的通信协议,不保证到达且不保证交付顺序。使用UDP的一项服务是每日报价(QOTD)。
using System.Text; using System.Net; using System.Net.Sockets; string server = "djxmmx.net"; int port = 17; byte[] data = new byte[0]; IPHostEntry hostEntry = Dns.GetHostEntry(server); var ipe = new IPEndPoint(hostEntry.AddressList[0], port); using var socket = new Socket(AddressFamily.InterNetworkV6, SocketType.Dgram, ProtocolType.Udp); socket.ReceiveTimeout = 5000; socket.SendTimeout = 2000; socket.SendTo(data, ipe); byte[] data2 = new byte[1024]; EndPoint remote = (EndPoint)ipe; int n = socket.ReceiveFrom(data2, ref remote); Console.WriteLine($"Message size: {n}"); Console.WriteLine($"Messaged received from: {remote}"); Console.WriteLine(Encoding.ASCII.GetString(data2, 0, n));
该程序创建一个连接到QOTD服务的客户端程序。
string server = "djxmmx.net"; int port = 17;
这是可以找到QOTD服务的服务器和端口。请注意,此类服务通常是短暂的。
byte[] data = new byte[0];
我们向服务器发送一条空消息。
IPHostEntry hostEntry = Dns.GetHostEntry(server);
Dns.GetHostEntry
将主机名或IP地址解析为IPHostEntry实例。这是Internet主机地址信息的.NET容器类。
using var socket = new Socket(AddressFamily.InterNetworkV6, SocketType.Dgram, ProtocolType.Udp);
Socket
被创建。我们传递寻址方案、套接字类型和协议类型。
socket.ReceiveTimeout = 5000; socket.SendTimeout = 2000;
我们设置接收发送数据的超时。
socket.SendTo(data, ipe);
我们使用SendTo
将数据(在本例中为空)发送到端点。
byte[] data2 = new byte[1024];
我们将在此处存储响应消息。
int n = socket.ReceiveFrom(data2, ref remote);
ReceiveFrom
方法将数据报接收到数据缓冲区中并存储端点。它返回接收到的字节数。
Console.WriteLine($"Message size: {n}"); Console.WriteLine($"Messaged received from: {remote}"); Console.WriteLine(Encoding.ASCII.GetString(data2, 0, n));
我们打印消息大小、删除地址和接收到的数据。
$ dotnet run Message size: 73 Messaged received from: [2001:470:e312:10::10]:17 "Take what you can, give nothing back..." - Pirates Of The Caribbean
C#套接字HTTPHEAD请求
HEAD请求是没有消息正文的HTTPGET请求。请求/响应的标头包含元数据,例如HTTP协议版本或内容类型。
using System.Text; using System.Net; using System.Net.Sockets; string server = "webcode.me"; int port = 80; var request = "HEAD / HTTP/1.0\r\n\r\n"; byte[] bReq = Encoding.ASCII.GetBytes(request); byte[] bRec = new byte[8192]; 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(bReq, bReq.Length, 0); int n = socket.Receive(bRec, bRec.Length, 0); Console.WriteLine(Encoding.ASCII.GetString(bRec, 0, n));
在代码示例中,我们向webcode.me发送了一个HEAD请求。
string server = "webcode.me"; int port = 80;
这是服务器名称和端口号。
string request = "HEAD / HTTP/1.0\r\n\r\n";
head请求是通过HEAD
命令发出的,后跟资源URL和HTTP协议版本。请注意,\r\n
字符是通信过程的必需部分。RFC7231文档中描述了详细信息。
using var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
HTTP协议(HTTP/0.9到HTTP/2)是基于TCP的。
if (socket.Connected)
我们可以通过Connected
属性检查我们是否连接成功。
socket.Send(bReq, bReq.Length, 0);
我们使用Send
发送数据。
int n = socket.Receive(bRec, bRec.Length, 0); Console.WriteLine(Encoding.ASCII.GetString(bRec, 0, n));
我们接收并打印标题数据。
$ dotnet run Connection established HTTP/1.1 200 OK Server: nginx/1.6.2 Date: Wed, 21 Sep 2022 17:43:39 GMT Content-Type: text/html Content-Length: 394 Last-Modified: Sun, 23 Jan 2022 10:39:25 GMT Connection: close ETag: "61ed305d-18a" Accept-Ranges: bytes
C#套接字HTTPGET请求
HTTPGET方法请求指定资源的表示。使用GET的请求应该只检索数据。
using System.Text; using System.Net; using System.Net.Sockets; string server = "webcode.me"; int port = 80; string request = $"GET / HTTP/1.1\r\nHost: {server} \r\nConnection: Close\r\n\r\n"; Byte[] bReq = Encoding.ASCII.GetBytes(request); Byte[] bRec = new Byte[1024]; 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(bReq, bReq.Length, 0); int n = 0; var sb = new StringBuilder(); do { n = socket.Receive(bRec, bRec.Length, 0); sb.Append(Encoding.ASCII.GetString(bRec, 0, n)); } while (n > 0); Console.WriteLine(sb);
该示例使用GET请求读取webcode.me的主页。
string request = $"GET / HTTP/1.1\r\nHost: {server} \r\nConnection: Close\r\n\r\n";
我们向套接字写入一个简单的GET请求。
do { n = socket.Receive(bRec, bRec.Length, 0); sb.Append(Encoding.ASCII.GetString(bRec, 0, n)); } while (n > 0);
由于我们无法确定响应的大小,因此我们使用do/while
循环来分块读取响应。
在本文中,我们使用了C#中的套接字。
列出所有C#教程。