套接字的类型和常用属性:
原型:
System.NetSockets.Socket
public Socket(AddressFamily addressFamily,SocketType socketType,ProtocolType protocolType);
套接字类型和协议对应关系:
Dgram(UDP) 无连接通信 例如网络文件系统(NFS)无连接、不保证无错,数据可能丢失,接受顺序不定
Stream(TCP) 面向连接的通讯 例如ftp,适合处理大量数据,数据被看做字节流传输,可靠,无差错
Raw(ICMP) ICMP协议 用于检验新的协议实现或访问现有服务中配置的新设备。
Raw(Raw) 简单IP包
常用属性:
Blocking 表示套接字是否处于阻塞状态。
Connected 获取截至到最后的I/O操作时Socket的连接状态。
LocalEndPoint 用来表述本机的终结点,即IP地址和端口号的组合。
RemoteEndPoint 如果使用面向连接的协议,该属性将获取包含Socket连接到的远程IP地址和端口号,如果使用无连接的协议,则包含将要和Socket通讯的默认远程IP地址和端口号。在调用Accept或Connect之后设置。
常用方法:
Socket(AddressFamily af,SocketType st,ProtocolType pt)创建套接字
bind(IPEndPoint iep)绑定本地IP地址和端口号
listen(int backlog)等待客户端发出连接的请求,参数backlog是指用户的连接数。超过拒绝通讯
accept()有新客户连接时,返回一个新的套接字句柄。返回包含客户端的信息的套接字句柄
connect(IPEndPoint iep)客户机独有,负责把自己新创建的套接字与本地地址相绑定,与bind()方法相对应
Send()/Receive()这两个方法在完成了客户端连接后,进行数据传输。
ShutDown()负责释放连接,并关闭socket对象。
二、建立面向连接的套接字。
指针对TCP协议来建立两端的通信。
要进行互联网通信,至少需要一对套接字,一个运行于客户端,称之为ClientSocket,另一个运行于服务端,称之为ServerSocket
连接过程:服务监听,客户端请求,连接确认。
重要步骤:
1、通过套接字的构造方法创建套接字对象并与本地的终结点进行绑定。
2、在端口上使用listen方法侦听是否有连接请求,如果侦听到连接请求则开始准备连接。
3、accept方法则会从客户端接入连接,建立连接后,accept方法会返回一个新的套接字。
从客户端来说,它调用connect方法尝试与服务器建立连接。用send和receive负责数据的传送和接受。
4、数据传送结束后,双方使用shutdown方法释放连接,接着使用close方法关系套接字。
三、建立无连接的套接字。
相对来说同有连接方式:
1、都采用bind方法绑定套接字,只有正确绑定才能通信。
2、无需建立连接,绑完就科传数据。
3、无连接采用SendTo方法和ReceiveFrom方法,一定要指定目的主机地址。
4、释放连接,关闭套接字即可。
四、简单示例:
C/S结构即服务器客户机结构,必须在客户机上安装相应软件。
B/S结构,即浏览器/服务器结构,一般为表示层、业务逻辑层、数据存储层三层结构。
编写代码:
1、客户端
using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Net.Sockets;
namespace S.Q.S
{
class ClientProm
{
static void Main(string[] args)
{
Socket Server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP);
IPAddress adr = IPAddress.Parse("127.0.0.1");
IPEndPoint ep = new IPEndPoint(adr,3000);
Server.Connect(ep);
byte[] buffer = new byte[255];
int end = 0;
if (Server.Receive(buffer)>0)
{
Console.WriteLine("连接上...");
Console.WriteLine("从服务器接收数据...");
while (buffer[end]!=0)
{
Console.WriteLine(buffer[end]);
end++;
}
Console.WriteLine("连接断开...");
Server.Shutdown(SocketShutdown.Both);
Server.Close();
}
}
}
}
2、服务端。
using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Net.Sockets;
namespace S.Q.S
{
class ServerProm
{
static void Main(string[] args)
{
Socket client;
//int recv;
//byte[] message = new byte[255];
Socket ServerSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP);
IPAddress adr = IPAddress.Parse("127.0.0.1");
IPEndPoint ep = new IPEndPoint(adr, 3000);
ServerSocket.Bind(ep); //类似于客户机的connect()方法
ServerSocket.Listen(3); //开始监听
while (true)
{
if ((client = ServerSocket.Accept()) != null)
{
Console.WriteLine("连接上...发送数据....");
//欲发送的字节数组,以0为结束标记
byte[] message = { 1, 2, 3, 4, 5, 6, 0 };
//send方法返回发送的字节数
Console.WriteLine("总计将发送" + client.Send(message) + "个字节的数据");
Console.WriteLine("结束.");
client.Close();
break;
}
}
}
}
}
运行结果:
客户端:
连接上...
从服务器接收数据...
1
2
3
4
5
6
连接断开...
服务端:
连接上...发送数据....
总计将发送7个字节的数据
结束.
四、无阻塞套接字。
上例是有阻塞的套接字会影响程序的并行度和效率。
一般有两种办法可以解决:
1、直接设置成无阻塞的:
Socket s = New Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
s.Blocking=false;
2、采用多路复用技术。
Select方法原型
public static void Select
{
IList checkRead,
IList checkWrite,
IList checkError,
int microSeconds
}
其中前三项都是list对象,表示它们是被监视的socket数组。
使用方法:
Socket socket1=null;
Socket socker2=null;
Byte buffer=new Byte[255];
ArrayList listenList=new ArrayList();
listenList.Add(socket1);
listenList.Add(socket2);
Socket.Select(listenList,null,null,1000);
for(int i=0;i
listenList.Receive(buffer);
Console.WriteLine(System.text.EncodingASCII.GetString(buffer));
}
这样就算在套接字上没有收到任何的数据,Receive方法也不会产生任何阻塞,对程序的效率也不会造成影响。
0 评论:
发表评论