Socket类:这个低层的类用于管理连接,实现Berkeley通信端接口,定义绑定、连接网络端点以及传输数据所需的方法,提供处理端点连接传输等细节所需要的功能。WebRequest、TcpClient和UdpClinet等类在内部使用这个类。
TcpClient类:允许创建和使用TCP连接,其创建于Socket类的基础上,并且封装了许多更高级的功能,避免开发人员处理连接操作的相关细节。
TcpListener类:允许监听传入的TCP连接请求,倾听来自TCP客户端应用程序的连接要求,封装更高级的功能,使用这个类同样也可以让你避免处理一些连接服务的细节,以一种比较有效它率的方式,接受倾听的连接需求。
UdpClinet类:用于为UDP客户创建连接(UDP是另一种TCP协议,但没有得到广泛的使用,主要用于本地网络)。
NetWorkStream类:这个类是从Stream派生出来的,专门用以处理网络形式的数据流,与其他文件数据流最大不同的地方在于,这个类接受Socket类对象参数,对网络数据进行存取操作。
.NET Framework Socket类是Winsock32 API提供的套接字服务的托管代码版本。在大多数情况下,Socket类方法只是将数据封送到它们的本机Win32副本中,并处理任何必要的安全检查。
Socket类支持两种基本模式:同步和异步。在同步模式中,对执行网络操作的函数(如Send和Receive)的调用一直等到操作完成后才将控制返回给调用程序,而在异步模式中,这些调用立即返回。
在可以使用套接字与远程设备通信之前,必须使用协议和网络地址信息初始化套接字。Socket类的构造函数具有指定套接字用来建立连接的地址族、套接字类型和协议类型的参数等功能。
在基于TCP/IP的网络(如Internet)上通信的关键代码如下:
Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
要使用UDP而不是TCP进行通信的关键代码如下:
Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
参数:
AddressFamily :AddressFamily枚举,用来指定Socket类用来解析网络地址的标准地址族。
SocketType: SocketType枚举,用来指定套接字的类型。
ProtocolType: ProtocolType枚举,用来指定在Socket上通信时使用的网络协议。
创建Socket后,它既可以开始与远程终结点的连接,也可以接收来自远程设备的连接。
本节将主要介绍Socket类的属性和方法,以便为读者使用Socket类进行网络编程提供方便。
Socket类常用属性及说明如表所示。
表 Socket类常用属性及说明
名称 |
说明 |
AddressFamily |
获取Socket的地址族 |
Available |
获取已经从网络接收且可供读取的数据量 |
Blocking |
获取或设置一个值,该值指示Socket是否处于阻止模式 |
Connected |
获取一个值,该值指示Socket是在上次Send还是Receive操作时连接到远程主机 |
DontFragment |
获取或设置Boolean值,该值指定Socket是否允许将Internet协议(IP)数据报分段 |
EnableBroadcast |
获取或设置一个Boolean值,该值指定Socket是否可以发送或接收广播数据包 |
ExclusiveAddressUse |
获取或设置Boolean值,该值指定Socket是否仅允许一个进程绑定到端口 |
Handle |
获取Socket的操作系统句柄 |
I sBound |
获取一个值,该值指示Socket是否绑定到特定本地端口 |
LingerState |
获取或设置一个值,该值指定Socket在尝试发送所有挂起数据时是否延迟关闭套接字 |
LocalEndPoint |
获取本地终结点 |
MulticastLoopback |
获取或设置一个值,该值指定传出的多路广播数据包是否传递到发送应用程序 |
NoDelay |
获取或设置Boolean值,该值指定流Socket是否正在使用Nagle算法 |
OSSupportsIPv6 |
指示基础操作系统和网络适配器是否支持Internet协议第6版 |
ProtocolType |
获取Socket的协议类型 |
ReceiveBufferSize |
获取或设置一个值,它指定Socket接收缓冲区的大小 |
ReceiveTimeout |
获取或设置一个值,该值指定之后同步Receive调用将超时的时间长度 |
RemoteEndPoint |
获取远程终结点 |
SendBufferSize |
获取或设置一个值,该值指定Socket发送缓冲区的大小 |
SendTimeout |
获取或设置一个值,该值指定之后同步Send调用将超时的时间长度 |
SocketType |
获取Socket的类型 |
UseOnlyOverlappedIO |
指定套接字是否应仅使用重叠I/O模式 |
下面对比较重要的属性进行详细介绍。
(1)AddressFamily属性
获取Socket的地址族。
语法:
public AddressFamily AddressFamily { get; }
注意:AddressFamily指定Socket类的实例可以使用的寻址方案。此属性为只读属性,它在创建Socket时设置。
示例 获取Socket的地址族
本示例实现的是当程序运行时,单击窗体中的【获取地址族】按钮,在窗体的文本框中显示出当前Socket对应的地址族,本示例在实现时,首先引入System.Net.Sockets命名空间,然后在窗体中添加一个Lable控件(用于显示信息)、一个TextBox控件(用于显示结果)和一个Button控件(用于触发事件)。
程序主要代码如下。
private void button1_Click(object sender, EventArgs e)
{
if (sk != null)
{
this.textBox1.Text = sk.AddressFamily.ToString();
}
else
{
MessageBox.Show("结果为空值");
}
}
在窗体加载时,实例化Socket对象(sk)、将Socket的地址族设为InterNetwork、将Socket的类型设为Stream类型、将Socket的协议类型设为Tcp类型。FrmSockect窗体的Load事件代码如下:
private void FrmSockect_Load(object sender, EventArgs e)
{
sk = new Socket(AddressFamily.InterNetwork, SocketType.Stream,
ProtocolType.Tcp);
}
(2)DontFragment属性:
获取或设置Boolean值,该值指定Socket是否允许将Internet协议(IP)数据报分段。
语法:
public bool DontFragment { get; set; }
注意:如果数据报大小超过传输介质的最大传送单位,则需要将数据报分段。可以由发送主机或中间路由器将数据报分段。如果必须对数据报进行分段,且已设置DontFragment选项,则会丢弃数据报,而且会将Internet控制消息协议错误信息返回给数据报的发送方。
(3)EnableBroadcast属性:
获取或设置一个Boolean值,该值指定Socket是否可以发送或接收广播数据包。
语法:
public bool EnableBroadcast { get; set; }
注意:广播仅限于特定子网,并且必须使用用户数据报协议(UDP)。对于Internet协议版本4,可通过向255.255.255.255发送数据包来向本地子网广播;也可以使用定向广播地址,即Internet协议(IP)地址的网络部分,同时所有位都在主机部分设置。例如,如果IP地址是192.168.1.40(C类地址,网络掩码为255.255.255.0,网络部分是前3个八进制数,主机部分是最后一个八进制数),则定向广播地址是192.168.1.255。
(4)MulticastLoopback属性:
获取或设置一个值,该值指定传出的多路广播数据包是否传递到发送应用程序。
语法:
public bool MulticastLoopback { get; set; }
注意:多路广播是一种适用于Internet上的多对多通信的可伸缩方式。一个进程预订多路广播地址;之后,已预订进程发送的所有数据包都由预订该多路广播地址的所有其他进程接收。对传输控制协议(TCP)套接字设置此属性不起任何作用。
示例 Socket属性设置
本示例实现的是当程序运行时,在窗体的3组单选框中显示出当前Socket对应的属性信息.本示例在实现时,需在引入System.Net.Sockets命名空间,然后在窗体中添加3个Lable控件(用户显示提示信息)、6个RadioButton控件(用于显示结果信息)和3个groupBox(用于分组显示控件)。
程序主要代码如下:
private void FrmDont_Load(object sender, EventArgs e)
{
Socket sk = new Socket(AddressFamily.InterNetwork, SocketType.Dgram,
ProtocolType.Udp);
ConfigureUdpSocket(sk);
if (sk.DontFragment)
{
this.radioButton1.Checked = true;
}
else
{
this.radioButton2.Checked = true;
}
if (sk.EnableBroadcast)
{
this.radioButton4.Checked = true;
}
else
{
this.radioButton3.Checked = true;
}
if (sk.MulticastLoopback)
{
this.radioButton6.Checked = true;
}
else
{
this.radioButton5.Checked = true;
}
}
在窗体的Load事件中调用了ConfigureUdpSocket方法,该方法主要用来为Socket设置相应的属性,其关键代码如下:
void ConfigureUdpSocket(Socket udpSocket)
{
udpSocket.DontFragment = true;
udpSocket.EnableBroadcast = true;//这个针对UDP而言
udpSocket.MulticastLoopback = false;
}
Socket类的常用方法及说明如表所示。
表 Socket类的常用方法
名称 |
说明 |
BeginConnect |
已重载。 开始一个对远程主机连接的异步请求 |
BeginSend |
已重载。 将数据异步发送到连接的Socket |
BeginSendTo |
向特定远程主机异步发送数据 |
BeginSendFile |
已重载。 将文件异步发送到连接的Socket对象 |
Listen |
将Socket置于侦听状态 |
SendTo |
已重载。 将数据发送到特定终结点 |
Shutdown |
禁用某Socket上的发送和接收 |
EndSend |
已重载。 结束挂起的异步发送 |
EndSendFile |
结束文件的挂起异步发送 |
EndSendTo |
结束挂起的、向指定位置进行的异步发送 |
下面对比较重要的方法进行详细介绍。
(1)BeginConnect 方法:
开始一个对远程主机连接的异步请求,主机由 IPAddress 和端口号指定。
语法:
public IAsyncResult BeginConnect
(
IPAddress address,
int port,
AsyncCallback requestCallback,
Object state
)
参数:
address:远程主机的IPAddress。
Port:远程主机的端口号。
RequestCallback:一个AsyncCallback委托,它引用连接操作完成时要调用的方法。
State:一个用户定义对象,其中包含连接操作的相关信息。当操作完成时,此对象会被传递给requestCallback委托。
返回值:IAsyncResult,它引用异步连接。
示例 Socket类的BeginConnect方法应用举例
本示例中通过Socket类的BeginConnect方法发起一次异步连接尝试。实现的相关程序代码如下:
public ManualResetEvent allDone = new ManualResetEvent(false);
public void connectCallback(IAsyncResult ar)
{
try
{
allDone.Set();
Socket s = (Socket)ar.AsyncState;
s.EndConnect(ar);
}
catch (Exception ey)
{
MessageBox.Show(ey.Message);
}
}
public void beginConnect(string host, int port)
{
IPAddress[] IPs = Dns.GetHostAddresses(host);
Socket s = new
Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
allDone.Reset();
s.BeginConnect(IPs[0], port,new AsyncCallback(connectCallback), s);
allDone.WaitOne();
MessageBox.Show("连接以确立");
}
private void button1_Click(object sender, EventArgs e)
{
beginConnect(this.textBox1.Text,int.Parse(this.textBox2.Text.ToString()));
}
注意:本示例在实现时,首先需要引入以下命名空间System.Net、System.Net.Sockets和System.Threading。
(2)Bind 方法:
使Socket与一个本地终结点相关联。
语法:
public void Bind
(
EndPoint localEP
)
参数
localEP:要与Socket关联的本地EndPoint。
注意:如果打算接收多路广播的数据报,则必须使用多路广播端口号调用Bind方法。
(3)Listen方法:
将 Socket 置于侦听状态。
语法:
public void Listen
(
int backlog
)
参数:
backlog:挂起连接队列的最大长度。
注意:在调用Listen之前,必须首先调用Bind方法,否则Listen将引发SocketException异常。根据操作系统的不同,backlog参数被限制为不同的值。用户可以指定更大的值,但backlog将受操作系统的限制。
示例 Socket类的Listen方法应用举例
本示例中通过Socket类的Listen方法来侦听传入的连接。程序主要代码如下。
private void FrmListinMothed_Load(object sender, EventArgs e)
{
Socket listenSocket = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
//绑定套接字监听的端口
IPAddress hostIP = (Dns.Resolve(IPAddress.Any.ToString())).AddressList[0];
IPEndPoint ep = new IPEndPoint(hostIP, 10001);
listenSocket.Bind(ep);
// 开始监听
listenSocket.Listen(10);
}
(4)SendTo方法:
将数据发送到指定的终结点。
语法:
public int SendTo
(
byte[] buffer,
EndPoint remoteEP
)
参数:
buffer:Byte类型的数组,它包含要发送的数据。
RemoteEP:EndPoint(标识网络地址,是一个abstract类),它表示数据的目标位置。
返回值:已发送的字节数。
示例 Socket类的SendTo方法应用举例
本示例中通过Socket类的SendTo方法来将数据发送到指定的终结点。程序主要代码如下。
public void sendTo()
{
IPHostEntry hostEntry = Dns.GetHostEntry(Dns.GetHostName());
IPEndPoint endPoint = new IPEndPoint(hostEntry.AddressList[0], 11000);
Socket s = new
Socket(endPoint.Address.AddressFamily,SocketType.Dgram,ProtocolType.Udp);
byte[] msg = Encoding.GetEncoding("gb2312").GetBytes ("sendTo Method test");
Console.WriteLine("Sending data.");
// This call blocks.
s.SendTo(msg, endPoint);
s.Close();
}