Unix提供了类似于文件操作的网络操作方式--Socket。通过Socket,程序员可以像操作文件一样通过打开、读取、写入、关闭等操作完成网络编程。
当Socket开发网络应用程序时,需要考虑使用的网络类型:
1、Socket类型,使用网络协议的类别,IPv4的类型为PF_INET
2、数据通信的类型,常见的数据报(SOCK_DGRAM)、数据流(SOCK_STREAM)
3、使用的网络协议,比如:TCP协议
下面演示几种使用Socket编程创建一个简单的Web服务器,该服务器通过端口号提供访问,向浏览器返回一个固定页面
1、通过Socket类实现:
private static void SocketDemo()
{
//取得本机换回地址
IPAddress ip = IPAddress.Loopback;
//端点=Ip+端口
IPEndPoint endPoint = new IPEndPoint(ip, 8888);
//参数分别为:使用网络协议的类别,数据通信的类型,使用的网络协议
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
socket.Bind(endPoint);
socket.Listen(10);
Console.WriteLine("开始监听,端口号:{0}。", endPoint.Port);
while (true)
{
//当接收到客户端请求时才继续往下执行
Socket client = socket.Accept();
//获取请求的端点
Console.WriteLine(client.RemoteEndPoint);
byte[] buffer = new byte[4096];
//获取请求数据长度
int len = client.Receive(buffer, 4096, SocketFlags.None);
System.Text.Encoding utf8 = System.Text.Encoding.UTF8;
//将获取的内容编码为一个字符串
string requestString = utf8.GetString(buffer, 0, len);
Console.WriteLine(requestString);
//消息格式:请求状态行+消息头+消息体 3部分
string statusLine = "Http/1.1 200 OK\r\n";
byte[] statusLineBytes = utf8.GetBytes(statusLine);
//准备发送到客户端的网页
string responseBody = "<html><head><title>From Socket Server</title></head><body><h1>Hello,Socket</h1></body></html>";
byte[] responseBodyBytes = utf8.GetBytes(responseBody);
string responseHeader = string.Format("Content-Type:Text/html;charset=UTF-8\r\nContent-Length:{0}\r\n", responseBody.Length);
byte[] responseHeaderBytes = utf8.GetBytes(responseHeader);
client.Send(statusLineBytes);
client.Send(responseHeaderBytes);
client.Send(new byte[] { 13, 10 });
client.Send(responseBodyBytes);
client.Close();
if (Console.KeyAvailable)
break;
}
socket.Close();
}
2、为了简化不再需要设置使用的网络协议等细节,.NET在System.Net.Socket命名空间中提供了TcpListener类:
//用TcpListener来替代Socket,就不用再设置网络协议等细节
private static void TcpListenerDemo()
{
IPAddress ip = IPAddress.Loopback;
IPEndPoint endpPoint = new IPEndPoint(ip,8888);
//创建tcp监听器
TcpListener newServer = new TcpListener(endpPoint);
newServer.Start();
Console.WriteLine("开始监听....");
while (true)
{
//等待客户端连接
TcpClient newClient = newServer.AcceptTcpClient();
Console.WriteLine("已经建立连接!");
//得到一个网络流
NetworkStream ns = newClient.GetStream();
byte[] request = new byte[4096];
//获取请求数据长度
System.Text.Encoding utf8 = System.Text.Encoding.UTF8;
int len = ns.Read(request, 0, 4096);
//将获取的内容编码为一个字符串
string requestString = utf8.GetString(request, 0, len);
Console.WriteLine(requestString);
//消息格式:请求状态行+消息头+"换行"+消息体 3部分
string statusLine = "Http/1.1 200 OK\r\n";
byte[] statusLineBytes = utf8.GetBytes(statusLine);
//准备发送到客户端的网页
string responseBody = "<html><head><title>From Socket Server</title></head><body><h1>Hello,TcpListener</h1></body></html>";
byte[] responseBodyBytes = utf8.GetBytes(responseBody);
string responseHeader = string.Format("Content-Type:Text/html;charset=UTF-8\r\nContent-Length:{0}\r\n", responseBody.Length);
byte[] responseHeaderBytes = utf8.GetBytes(responseHeader);
ns.Write(statusLineBytes, 0, statusLineBytes.Length);
ns.Write(responseHeaderBytes, 0, responseHeaderBytes.Length);
ns.Write(new byte[] { 13, 10 }, 0, 2);
ns.Write(responseBodyBytes, 0, responseBodyBytes.Length);
newClient.Close();
if (Console.KeyAvailable)
break;
}
newServer.Stop();
}
3、为了进一步简化HTTP协议的监听器,.Net在命名空间System.Net中提供了HttpListener类:
private static void HttpListenerDemo()
{
if (!HttpListener.IsSupported)
{
throw new System.InvalidOperationException("使用HttpListener 必须为Windows XP SP2 或 Server 2003 以上的系统");
}
string[] prefixes = new string[] { "http://localhost:8888/" };
//创建监听器
HttpListener listener = new HttpListener();
//增加监听的前缀
foreach (string s in prefixes)
{
listener.Prefixes.Add(s);
}
listener.Start();
Console.WriteLine("开始监听....");
while (true)
{
//阻塞线程,直到请求到达
HttpListenerContext context = listener.GetContext();
//获取请求对象
HttpListenerRequest request = context.Request;
//输出相关信息
Console.WriteLine("{0} {1} Http/1.1",request.HttpMethod,request.RawUrl);
Console.WriteLine("Accept:{0}",string.Join(",",request.AcceptTypes));
Console.WriteLine("Accept-Languages:{0}", string.Join(",", request.UserLanguages));
Console.WriteLine("User_Agent:{0}",request.UserAgent);
Console.WriteLine("Accept-Encoding:{0}",request.Headers["Accept-Encoding"]);
Console.WriteLine("Connection:{0}", request.KeepAlive ? "Keep-Alive" : "close");
Console.WriteLine("Host:{0}",request.UserHostName);
Console.WriteLine("Pragma:{0}",request.Headers["Pragma"]);
//获取回应对象
HttpListenerResponse response = context.Response;
string responseString = @"<html><head><title>From Socket Server</title></head><body><h1>Hello,HttpListener</h1></body></html>";
//设置回应头部内容,长度,编码
response.ContentLength64 = System.Text.Encoding.UTF8.GetByteCount(responseString);
response.ContentType = @"text/html;charset=UTF-8";
//输出回应内容
System.IO.Stream output = response.OutputStream;
System.IO.StreamWriter writer = new System.IO.StreamWriter(output);
writer.Write(responseString);
//关闭输出流
writer.Close();
if (Console.KeyAvailable)
break;
}
//关闭服务器
listener.Stop();
}
以上三种方法都实现了服务器接收客户端的请求,并对其进行回应,回应的消息由服务器生成,在真正处理的时候,我们需要根据接收浏览器的请求信息,给出不同的处理及回应。
以上内容参考书籍:ASP.NET本质论(郝冠军 著)