C#.Net 网络程序开发基础之Socket篇‖的网络服务,其名字空间Sy
用程序。.Net类采用的分层
据需要选择针对不同的级别
接字到普通的请求/响应,
的需要。
ork为应用程序访问Internet提
stem.Net和System.Net.Sockets
结构允许应用程序在不同的控制
编制程序,这些级别几乎囊括了
更重要的是,这种分层是可以扩
| 供了分层的、可扩展的以及受管辖
包含丰富的类可以开发多种网络应
级别上访问网络,开发人员可以根
Internet的所有需要--从socket套
展的,能够适应Internet不断扩展
|
抛开ISO/OSI模型的7层
个层次:请求/响应层、应
层,支持Http、Tcp和Udp的
| 构架,单从TCP/IP模型上的逻辑
用协议层、传输层。WebReqeust
类组成了应用协议层,而Socket
| 层面上看,.Net类可以视为包含3
和WebResponse 代表了请求/响应
类处于传输层。
|
传输层位于这个结构的
的特殊需要时,就需要使用
| 最底层,当其上面的应用协议层
这一层进行Socket套接字编程。
| 和请求/响应层不能满足应用程序
|
而在.Net中,System.Net.Sockets
Windows Sockets (Winsock) 接口的托
问类都建立在该套接字Socket实现之上,
关创建到 Internet 的 TCP 和 UDP 连接
的基础数据流等,常见的许多Internet服
Email、Echo等,这些服务尽管通讯协议P
Socket。
| 命名空间为需要严密控制网络访问的开发人员提供了
管实现。System.Net 命名空间械乃衅渌绶?br>如TCPClient、TCPListener 和 UDPClient 类封装有
的详细信息;NetworkStream类则提供用于网络访问
务都可以见到Socket的踪影,如Telnet、Http、
rotocol的定义不同,但是其基础的传输都是采用的
|
其实,Socket可以象流Stream一样被
户端)和远程服务器端之间,而后,数据
行。
| 视为一个数据通道,这个通道架设在应用程序端(客
的读取(接收)和写入(发送)均针对这个通道来进
|
可见,在应用程序端或
将数据发送到连接的Socket
| 者服务器端创建了Socket对象之
,或者使用Receive/ReceiveFrom
| 后,就可以使用Send/SentTo方法
方法接收来自连接Socket的数据;
|
针对Socket编程,.NET 框架的 Sock
码版本。其中为实现网络编程提供了大量
封送到它们的本机 Win32 副本中并处理
,那么用Socket类编写网络程序会非常容
下面的解说,你会发觉使用Socket类开发
情况下遵循大致相同的步骤。
| et 类是 Winsock32 API 提供的套接字服务的托管代
的方法,大多数情况下,Socket 类方法只是将数据
任何必要的安全检查。如果你熟悉Winsock API函数
易,当然,如果你不曾接触过,也不会太困难,跟随
windows 网络应用程序原来有规可寻,它们在大多数
|
在使用之前,你需要首
:
| 先创建Socket对象的实例,这可
| 以通过Socket类的构造方法来实现
|
public Socket(Addres
protocolType);
| sFamily addressFamily,Socket
| Type socketType,ProtocolType
|
其中,addressFamily
Socket 的类型,protocolT
| 参数指定 Socket 使用的寻址方
ype 参数指定 Socket 使用的协
| 案,socketType 参数指定
议。
|
下面的示例语句创建一个 Socket,
通讯。
| 它可用于在基于 TCP/IP 的网络(如 Internet)上
|
Socket s = new Socket(AddressFam
ProtocolType.Tcp);
| ily.InterNetwork, SocketType.Stream,
|
| 若要使用 UDP 而不是 TCP,需要更改协议类型,如下面的示例所示: |
Socket s = new Socke
ProtocolType.Udp);
| t(AddressFamily.InterNetwork
| , SocketType.Dgram,
|
一旦创建 Socket,在
Send/SendTo方法向远程服
数据;而在服务器端,你需
,并通过Listen方法侦听该
操作,创建新的Socket以处
禁用 Socket,并使用 Clos
| 客户端,你将可以通过Connect
务器发送数据,而后可以通过Re
要使用Bind方法绑定所指定的接
接口上的请求,当侦听到用户端
理传入的连接请求。使用完 Soc
e 方法关闭 Socket。其间用到
| 方法连接到指定的服务器,并通过
ceive/ReceiveFrom从服务端接收
口使Socket与一个本地终结点相联
的连接时,调用Accept完成连接的
ket 后,记住使用 Shutdown 方法
的方法/函数有:
|
| Socket.Connect方法:建立到远程设备的连接 |
public void Connect(EndPoint rem
| oteEP)(有重载方法)
|
Socket.Send 方法:从
| 数据中的指示位置开始将数据发
| 送到连接的 Socket。
|
public int Send(byte
| [], int, SocketFlags);(有重
| 载方法)
|
| Socket.SendTo 方法 将数据发送到特定终结点。 |
public int SendTo(byte[], EndPoi
| nt);(有重载方法)
|
Socket.Receive方法:
| 将数据从连接的 Socket 接收到
| 接收缓冲区的特定位置。
|
public int Receive(byte[],int,So
| cketFlags);
|
Socket.ReceiveFrom方
| 法:接收数据缓冲区中特定位置
| 的数据并存储终结点。
|
public int ReceiveFr
| om(byte[], int, SocketFlags,
| ref EndPoint);
|
| Socket.Bind 方法:使 Socket 与一个本地终结点相关联: |
| public void Bind( EndPoint localEP ); |
| Socket.Listen方法:将 Socket 置于侦听状态。 |
| public void Listen( int backlog ); |
| Socket.Accept方法:创建新的 Socket 以处理传入的连接请求。 |
| Socket.Shutdown方法:禁用某 Socket 上的发送和接收 |
public void Shutdown( SocketShut
| down how );
|
| Socket.Close方法:强制 Socket 连接关闭 |
可以看出,以上许多方
络地址和一个服务端口号来
接到的该设备上的特定服务
EndPoint 类表示这个终结
。.Net同时也为每个受支持
IPEndPoint。IPEndPoint
组合服务的主机IP地址和端
| 法包含EndPoint类型的参数,在
唯一标识设备。网络地址标识网
。网络地址和服务端口的组合称
点,它提供表示网络资源或服务
的地址族定义了 EndPoint 的子
类包含应用程序连接到主机上的
口号,IPEndPoint 类形成到服
| Internet中,TCP/IP 使用一个网
络上的特定设备;端口号标识要连
为终结点,在 .NET 框架中正是由
的抽象,用以标志网络地址等信息
代;对于 IP 地址族,该类为
服务所需的主机和端口信息,通过
务的连接点。
|
用到IPEndPoint类的时候就不可避免
地址实例:
| 地涉及到计算机IP地址,.Net中有两种类可以得到IP
|
IPAddress类:IPAddress 类包含计
址字符串转换为 IPAddress 实例。下面
| 算机在 IP 网络上的地址。其Parse方法可将 IP 地
的语句创建一个 IPAddress 实例:
|
IPAddress myIP = IPA
| ddress.Parse("192.168.1.2");
|
Dns 类:向使用 TCP/I
DNS 服务器以将用户友好
址(如 192.168.1.1)。Re
地址和别名的列表。大多数
的代码获取一个 IPAddress
| P Internet 服务的应用程序提
的域名(如"host.contoso.com"
solve方法 返回一个 IPHostEnt
情况下,可以使用 AddressList
实例,该实例包含服务器 host
| 供域名服务。其Resolve 方法查询
)映射到数字形式的 Internet 地
y 实例,该实例包含所请求名称的
数组中返回的第一个地址。下面
.contoso.com 的 IP 地址。
|
IPHostEntry ipHostInfo = Dns.Res
| olve("host.contoso.com");
|
IPAddress ipAddress = ipHostInfo
| .AddressList[0];
|
| 你也可以使用GetHostName方法得到IPHostEntry实例: |
IPHosntEntry hostInf
| o=Dns.GetHostByName("host.co
| ntoso.com")
|
| SocketException异常:访问Socket时操作系统发生错误引发 |
| ArgumentNullException异常:参数为空引用引发 |
| ObjectDisposedException异常:Socket已经关闭引发 |
在掌握上面得知识后,
口号组合,以便为连接创建
| 下面的代码将该服务器主机( h
远程终结点:
| ost.contoso.com的 IP 地址与端
|
IPEndPoint ipe = new
| IPEndPoint(ipAddress,11000)
| ;
|
确定了远程设备的地址
连接。下面的示例使用现有
| 并选择了用于连接的端口后,应
的 IPEndPoint 实例与远程设备
| 用程序可以尝试建立与远程设备的
连接,并捕获可能引发的异常:
|
| catch(ArgumentNullException ae) { |
Console.WriteLine("A
| rgumentNullException : {0}",
| ae.ToString());
|
| catch(SocketException se) { |
Console.WriteLine("SocketExcepti
| on : {0}", se.ToString());
|
Console.WriteLine("U
| nexpected exception : {0}",
| e.ToString());
|
需要知道的是:Socket
,对执行网络操作的函数(
调用程序。在异步模式中,
| 类支持两种基本模式:同步和
如 Send 和 Receive)的调用一
这些调用立即返回。
| 异步。其区别在于:在同步模式中
直等到操作完成后才将控制返回给
|
另外,很多时候,Socket编程视情况
端编制应用程序向服务端指定端口发送请
在上面的阐述中已经提及;当然,并非所
用情况不同,你可以在客户端构造出请求
服务程序进行处理。以下事例语句中的字
| 不同需要在客户端和服务器端分别予以实现,在客户
求,同时编制服务端应用程序处理该请求,这个过程
有的Socket编程都需要你严格编写这两端程序;视应
字符衿飨嘤Χ丝诓痘裾飧銮肭螅挥善涔?br>符串就向远程主机提出页面请求:
|
string Get = "GET /
Closernrn";
| HTTP/1.1rnHost: " + server
| + "rnConnection:
|
远程主机指定端口接受到这一请求后
制服务器端应用程序。
| ,就可利用其公用服务程序进行处理而不需要另行编
|
综合运用以上阐述的使
地实现了Web页面下载功能
部分表示法格式的 IP 地址
可以获取远程主机页面并保
Internet浏览器中打开该页
| 用Visual C#进行Socket网络程
。用户只需在窗体上输入远程主
)和预保存的本地文件名,并利
存在本地机指定文件中。如果保
面。适当添加代码,你甚至可以
| 序开发的知识,下面的程序段完整
机名(Dns 主机名或以点分隔的四
用专门提供Http服务的80端口,就
存格式是.htm格式,你就可以在
实现一个简单的浏览器程序。
|
private void button1
| _Click(object sender, System
| .EventArgs e) {
|
| string fileName=textBox3.Text.Trim(); |
| string hostName=textBox1.Text.Trim(); |
int port=Int32.Parse(textBox2.Te
| xt.Trim());
|
IPHostEntry ipInfo=D
| ns.GetHostByName(hostName);
|
| IPAddress[] ipAddr=ipInfo.AddressList; |
IPEndPoint hostEP=new IPEndPoint
| (ip,port);
|
Socket socket=new Socket(Address
etType.Stream,ProtocolType.Tcp);
| Family.InterNetwork,Sock
|
| MessageBox.Show("连接错误"+se.Message,"提示信息 |
,MessageBoxButtons.R
| etryCancel,MessageBoxIcon.In
| formation);
|
string sendStr="GET / HTTP/1.1r
| nHost: " + hostName +
|
| "rnConnection: Closernrn"; |
| byte[] bytesSendStr=new byte[1024]; |
bytesSendStr=Encoding.ASCII.GetB
| ytes(sendStr);
|
socket.Send(bytesSendStr,bytesSe
| ndStr.Length,0);
|
MessageBox.Show("发送错误:"+ce.M
| essage,"提示信息
|
,MessageBoxButtons.RetryCancel,M
| essageBoxIcon.Information);
|
| //声明字节数组,一次接收数据的长度为1024字节 |
| byte[] recvBytes=new byte[1024]; |
bytes=socket.Receive
| (recvBytes,recvBytes.Length,
| 0);
|
recvStr+=Encoding.AS
| CII.GetString(recvBytes,0,by
| tes);
|
byte[] content=Encoding.ASCII.Ge
| tBytes(recvStr);
|
FileStream fs=new FileStream(fil
ate,FileAccess.ReadWrite);
| eName,FileMode.OpenOrCre
|
| fs.Write(content,0,content.Length); |
MessageBox.Show("文件创建/写入错
",MessageBoxButtons.RetryCancel,Mess
| 误:"+fe.Message,"提示信息
ageBoxIcon.Information);
|
| socket.Shutdown(SocketShutdown.Both); |
上一页> 下一页>