c#网络编程 003 (套接字概述)

2009年3月9日星期一

c#网络编程 003 (套接字概述)

一、简单说就是不同计算机之间为了满足各自进程间通信的需要所架设的一条数据通道,是一个通讯链的句柄。生成套接字需要三个参数,通讯的目的IP地址、使用的传输协议(TCP或UDP)和使用的端口号。

套接字的类型和常用属性:

原型:

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 评论:

发表评论