在两台计机传输文g之前Q必需得先有一台计机建立套节子连接ƈl定一个固定得端口Qƈ在这个端口侦听另外一台计机的连接请求?/p>
socket = new Socket(AddressFamily.InterNetwork,SocketType.Stream, ProtocolType.Tcp);
socket.Blocking = true ;
IPEndPoint computernode1 = new IPEndPoint(serverIpadress, 8080);
socket.Bind(computernode1);
socket.Listen(-1);
当有其他的计机发出q接h的时候,被请求的计算机将Ҏ一个连接请求分配一个线E,用于处理文g传输和其他服务?/p>
while ( true )
{
clientsock = socket.Accept();
if ( clientsock.Connected )
{
Thread tc = new Thread(new ThreadStart(listenclient));
tc.Start();
}
}
下面的代码展CZlistenclientҎ是如何处理另外一台计机发送过来的h。首先ƈ对发送过来的h字符串作出判断,看看是何U请求,然后军_相应的处理方法?/p>
void listenclient()
{
Socket sock = clientsock ;
try
{
while ( sock != null )
{
byte[] recs = new byte[32767];
int rcount = sock.Receive(recs,recs.Length,0) ;
string message = System.Text.Encoding.ASCII.GetString(recs) ;
//对message作出处理Q解析处h字符和参数存储在cmdList ?br /> execmdQcmdList[0];
sender = null ;
sender = new Byte[32767];
string parm1 = "";
//目录列D
if ( execmd == "LISTING" )
{
ListFiles(message);
continue ;
}
//文g传输
if ( execmd == "GETOK" )
{
cmd = "BEGINSEND " + filepath + " " + filesize ;
sender = new Byte[1024];
sender = Encoding.ASCII.GetBytes(cmd);
sock.Send(sender, sender.Length , 0 );
//转到文g下蝲处理
DownloadingFile(sock);
continue ;
}
}
}
catch(Exception Se)
{
string s = Se.Message;
Console.WriteLine(s);
}
}
xQ基本的工作已经完成了,下面我们看看如何处理文g传输的?br />while(rdby < total && nfs.CanWrite)
{
//从要传输的文件读取指定长度的数据
len =fin.Read(buffed,0,buffed.Length) ;
//读取的数据发送到对应的计机
nfs.Write(buffed, 0,len);
//增加已经发送的长度
rdby=rdby+len ;
}
从上面的代码可以看出是完成文件{换成FileStream ,然后通过NetworkStreaml定对应的套节子Q最后调用他的writeҎ发送到对应的计机?br />我们再看看接受端是如何接受传输过来的,q且转换成文件的Q?br />NetworkStream nfs = new NetworkStream(sock) ;
try
{
//一直@环直到指定的文g长度
while(rby < size)
{
byte[] buffer = new byte[1024] ;
//d发送过来的文g?br /> int i = nfs.Read(buffer,0,buffer.Length) ;
fout.Write(buffer,0,(int)i) ;
rby=rby+i ;
}
fout.Close() ;
从上面可以看出接受与发送恰好是互ؓ相反的过E,非常单?br />xQ单方向的文件传输就完成了,只需要在每个对等的节点上同时实现上面的发送和接受的处理代码就可以做到互相传输文g了?/p>
=============================
Microsoft.Net Framework为应用程序访问Internet提供了分层的、可扩展的以及受辖的网l服务,其名字空间System.Net和System.Net.Sockets包含丰富的类可以开发多U网l应用程序?Netc采用的分层l构允许应用E序在不同的控制U别上访问网l,开发h员可以根据需要选择针对不同的别编制程序,q些U别几乎囊括了Internet的所有需?-从socket套接字到普通的h/响应Q更重要的是Q这U分层是可以扩展的,能够适应Internet不断扩展的需要?
抛开ISO/OSI模型?层构Ӟ单从TCP/IP模型上的逻辑层面上看Q?Netcd以视为包?个层ơ:h/响应层、应用协议层、传输层。WebReqeust和WebResponse 代表了请?响应层,支持Http、Tcp和Udp的类l成了应用协议层Q而Socketcd于传输层。?
传输层位于这个结构的最底层Q当其上面的应用协议层和h/响应层不能满_用程序的Ҏ需要时Q就需要用这一层进行Socket套接字编E?
而在.Net中,System.Net.Sockets 命名I间为需要严密控制网l访问的开发h员提供了 Windows Sockets (Winsock) 接口的托实现。System.Net 命名I间中的所有其他网l访问类都徏立在该套接字Socket实现之上Q如TCPClient、TCPListener ?UDPClient cd装有兛_建到 Internet ?TCP ?UDP q接的详l信息;NetworkStreamcd提供用于|络讉K的基数据等Q常见的许多Internet服务都可以见到Socket的踪影,如Telnet、Http、Email、Echo{,q些服务管通讯协议Protocol的定义不同,但是其基的传输都是采用的Socket?
其实QSocket可以象流Stream一栯视ؓ一个数据通道Q这个通道架设在应用程序端Q客LQ和q程服务器端之间Q而后Q数据的dQ接Ӟ和写入(发送)均针对这个通道来进行?
可见Q在应用E序端或者服务器端创ZSocket对象之后Q就可以使用Send/SentToҎ数据发送到q接的Socket,或者用Receive/ReceiveFromҎ接收来自q接Socket的数据;
针对Socket~程Q?NET 框架?Socket cL Winsock32 API 提供的套接字服务的托代码版本。其中ؓ实现|络~程提供了大量的ҎQ大多数情况下,Socket cL法只是将数据送到它们的本?Win32 副本中ƈ处理M必要的安全检查。如果你熟悉Winsock API函数Q那么用Socketcȝ写网l程序会非常ҎQ当Ӟ如果你不曾接触过Q也不会太困难,跟随下面的解_你会发觉使用Socketcd发windows |络应用E序原来有规可寻Q它们在大多数情况下遵@大致相同的步骤?
在用之前,你需要首先创建Socket对象的实例,q可以通过Socketcȝ构造方法来实现Q?
public Socket(AddressFamily addressFamily,SocketType socketType,ProtocolType protocolType);
其中QaddressFamily 参数指定 Socket 使用的寻址ҎQsocketType 参数指定 Socket 的类型,protocolType 参数指定 Socket 使用的协议?
下面的示例语句创Z?SocketQ它可用于在Z TCP/IP 的网l(?InternetQ上通讯?
Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
若要使用 UDP 而不?TCPQ需要更改协议类型,如下面的CZ所C:
Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
一旦创?SocketQ在客户端,你将可以通过ConnectҎq接到指定的服务器,q过Send/SendToҎ向远E服务器发送数据,而后可以通过Receive/ReceiveFrom从服务端接收数据Q而在服务器端Q你需要用BindҎl定所指定的接口Socket与一个本地终l点相联Qƈ通过ListenҎ侦听该接口上的请求,当侦听到用户端的q接Ӟ调用Accept完成q接的操作,创徏新的Socket以处理传入的q接h。用完 Socket 后,C使用 Shutdown Ҏ用 SocketQƈ使用 Close Ҏ关闭 Socket。其间用到的Ҏ/函数有:
Socket.ConnectҎ:建立到远E设备的q接
public void Connect(EndPoint remoteEP)Q有重蝲ҎQ?
Socket.Send Ҏ:从数据中的指CZ|开始将数据发送到q接?Socket?
public int Send(byte[], int, SocketFlags);(有重载方?
Socket.SendTo Ҏ 数据发送到特定l结炏V?
public int SendTo(byte[], EndPoint);Q有重蝲ҎQ?
Socket.ReceiveҎ:数据从q接?Socket 接收到接收缓冲区的特定位|?
public int Receive(byte[],int,SocketFlags);
Socket.ReceiveFromҎQ接收数据缓冲区中特定位|的数据q存储终l点?
public int ReceiveFrom(byte[], int, SocketFlags, ref EndPoint);
Socket.Bind ҎQ Socket 与一个本地终l点相关联:
public void Bind( EndPoint localEP );
Socket.ListenҎQ将 Socket |于侦听状态?
public void Listen( int backlog );
Socket.AcceptҎ:创徏新的 Socket 以处理传入的q接h?
public Socket Accept();
Socket.ShutdownҎ:用?Socket 上的发送和接收
public void Shutdown( SocketShutdown how );
Socket.CloseҎ:强制 Socket q接关闭
public void Close();
可以看出Q以上许多方法包含EndPointcd的参敎ͼ在Internet中,TCP/IP 使用一个网l地址和一个服务端口号来唯一标识讑֤。网l地址标识|络上的特定讑֤Q端口号标识要连接到的该讑֤上的特定服务。网l地址和服务端口的l合UCؓl结点,?.NET 框架中正是由 EndPoint c表C个终l点Q它提供表示|络资源或服务的抽象Q用以标志网l地址{信息?Net同时也ؓ每个受支持的地址族定义了 EndPoint 的子代;对于 IP 地址族,该类?IPEndPoint。IPEndPoint cd含应用程序连接到L上的服务所需的主机和端口信息Q通过l合服务的主机IP地址和端口号QIPEndPoint cdŞ成到服务的连接点?
用到IPEndPointcȝ时候就不可避免地涉及到计算机IP地址Q?Net中有两种cd以得到IP地址实例Q?
IPAddressc:IPAddress cd含计机?IP |络上的地址。其ParseҎ可将 IP 地址字符串{换ؓ IPAddress 实例。下面的语句创徏一?IPAddress 实例Q?
IPAddress myIP = IPAddress.Parse("192.168.1.2");
Dns c:向?TCP/IP Internet 服务的应用程序提供域名服务。其Resolve Ҏ查询 DNS 服务器以用户友好的域名Q如"host.contoso.com"Q映到数字形式?Internet 地址Q如 192.168.1.1Q。ResolveҎ q回一?IPHostEnty 实例Q该实例包含所h名称的地址和别名的列表。大多数情况下,可以使用 AddressList 数组中返回的W一个地址。下面的代码获取一?IPAddress 实例Q该实例包含服务?host.contoso.com ?IP 地址?
IPHostEntry ipHostInfo = Dns.Resolve("host.contoso.com");
IPAddress ipAddress = ipHostInfo.AddressList[0];
你也可以使用GetHostNameҎ得到IPHostEntry实例Q?
IPHosntEntry hostInfo=Dns.GetHostByName("host.contoso.com")
在用以上方法时Q你可能需要处理以下几U异常:
SocketException异常Q访问Socket时操作系l发生错误引?
ArgumentNullException异常Q参CؓI引用引?
ObjectDisposedException异常QSocket已经关闭引发
在掌握上面得知识后,下面的代码将该服务器LQ?host.contoso.com?IP 地址与端口号l合Q以便ؓq接创徏q程l结点:
IPEndPoint ipe = new IPEndPoint(ipAddress,11000);
定了远E设备的地址q择了用于连接的端口后,应用E序可以试建立与远E设备的q接。下面的CZ使用现有?IPEndPoint 实例与远E设备连接,q捕获可能引发的异常Q?
try {
s.Connect(ipe);//试q接
}
//处理参数为空引用异常
catch(ArgumentNullException ae) {
Console.WriteLine("ArgumentNullException : {0}", ae.ToString());
}
//处理操作pȝ异常
catch(SocketException se) {
Console.WriteLine("SocketException : {0}", se.ToString());
}
catch(Exception e) {
Console.WriteLine("Unexpected exception : {0}", e.ToString());
}
需要知道的是:Socket cL持两U基本模式:同步和异步。其区别在于Q在同步模式中,Ҏ行网l操作的函数Q如 Send ?ReceiveQ的调用一直等到操作完成后才将控制q回l调用程序。在异步模式中,q些调用立即q回?
另外Q很多时候,Socket~程视情况不同需要在客户端和服务器端分别予以实现Q在客户端编制应用程序向服务端指定端口发送请求,同时~制服务端应用程序处理该hQ这个过E在上面的阐qC已经提及Q当Ӟq所有的Socket~程都需要你严格~写q两端程序;视应用情况不同,你可以在客户端构造出h字符Ԍ服务器相应端口捕莯个请求,交由其公用服务程序进行处理。以下事例语句中的字W串向q程L提出面hQ?
string Get = "GET / HTTP/1.1\r\nHost: " + server + "\r\nConnection: Close\r\n\r\n";
q程L指定端口接受到这一h后,可利用其公用服务程序进行处理而不需要另行编制服务器端应用程序?
l合q用以上阐述的用Visual C#q行Socket|络E序开发的知识Q下面的E序D完整地实现了Web面下蝲功能。用户只需在窗体上输入q程L名(Dns L名或以点分隔的四部分表示法格式的 IP 地址Q和预保存的本地文g名,q利用专门提供Http服务?0端口Q就可以获取q程L面q保存在本地机指定文件中。如果保存格式是.htm格式Q你可以在Internet览器中打开该页面。适当d代码Q你甚至可以实现一个简单的览器程序?
实现此功能的主要源代码如下:
//"开?按钮事g
private void button1_Click(object sender, System.EventArgs e) {
//取得预保存的文g?
string fileName=textBox3.Text.Trim();
//q程L
string hostName=textBox1.Text.Trim();
//端口
int port=Int32.Parse(textBox2.Text.Trim());
//得到L信息
IPHostEntry ipInfo=Dns.GetHostByName(hostName);
//取得IPAddress[]
IPAddress[] ipAddr=ipInfo.AddressList;
//得到ip
IPAddress ip=ipAddr[0];
//l合E终l点
IPEndPoint hostEP=new IPEndPoint(ip,port);
//创徏Socket 实例
Socket socket=new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
try
{
//试q接
socket.Connect(hostEP);
}
catch(Exception se)
{
MessageBox.Show("q接错误"+se.Message,"提示信息
,MessageBoxButtons.RetryCancel,MessageBoxIcon.Information);
}
//发送给q程L的请求内容串
string sendStr="GET / HTTP/1.1\r\nHost: " + hostName +
"\r\nConnection: Close\r\n\r\n";
//创徏bytes字节数组以{换发送串
byte[] bytesSendStr=new byte[1024];
//发送内容字W串转换成字节byte数组
bytesSendStr=Encoding.ASCII.GetBytes(sendStr);
try
{
//向主机发送请?
socket.Send(bytesSendStr,bytesSendStr.Length,0);
}
catch(Exception ce)
{
MessageBox.Show("发送错?"+ce.Message,"提示信息
,MessageBoxButtons.RetryCancel,MessageBoxIcon.Information);
}
//声明接收q回内容的字W串
string recvStr="";
//声明字节数组Q一ơ接收数据的长度?024字节
byte[] recvBytes=new byte[1024];
//q回实际接收内容的字节数
int bytes=0;
//循环dQ直到接收完所有数?
while(true)
{
bytes=socket.Receive(recvBytes,recvBytes.Length,0);
//d完成后退出@?
if(bytes?0)
break;
//读取的字节数{换ؓ字符?
recvStr+=Encoding.ASCII.GetString(recvBytes,0,bytes);
}
//所d的字W串转换为字节数l?
byte[] content=Encoding.ASCII.GetBytes(recvStr);
try
{
//创徏文g对象实?
FileStream fs=new FileStream(fileName,FileMode.OpenOrCreate,FileAccess.ReadWrite);
//写入文g
fs.Write(content,0,content.Length);
}
catch(Exception fe)
{
MessageBox.Show("文g创徏/写入错误:"+fe.Message,"提示信息",MessageBoxButtons.RetryCancel,MessageBoxIcon.Information);
}
//用Socket
socket.Shutdown(SocketShutdown.Both);
//关闭Socket
socket.Close();
}
}
=============================================
Socket基本~程
服务端:
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
Thread mythread ;
Socket socket;
// 清理所有正在用的资源?/p>
protected override void Dispose( bool disposing )
{
try
{
socket.Close();//释放资源
mythread.Abort ( ) ;//中止U程
}
catch{ }
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}
public static IPAddress GetServerIP()
{
IPHostEntry ieh=Dns.GetHostByName(Dns.GetHostName());
return ieh.AddressList[0];
}
private void BeginListen()
{
IPAddress ServerIp=GetServerIP();
IPEndPoint iep=new IPEndPoint(ServerIp,8000);
socket=new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
byte[] byteMessage=new byte[100];
this.label1.Text=iep.ToString();
socket.Bind(iep);
// do
while(true)
{
try
{
socket.Listen(5);
Socket newSocket=socket.Accept();
newSocket.Receive(byteMessage);
string sTime = DateTime.Now.ToShortTimeString ( ) ;
string msg=sTime+":"+"Message from:";
msg+=newSocket.RemoteEndPoint.ToString()+Encoding.Default.GetString(byteMessage);
this.listBox1.Items.Add(msg);
}
catch(SocketException ex)
{
this.label1.Text+=ex.ToString();
}
}
// while(byteMessage!=null);
}
//开始监?/p>
private void button1_Click(object sender, System.EventArgs e)
{
try
{
mythread = new Thread(new ThreadStart(BeginListen));
mythread.Start();
}
catch(System.Exception er)
{
MessageBox.Show(er.Message,"完成",MessageBoxButtons.OK,MessageBoxIcon.Stop);
}
}
客户端:
using System.Net;
using System.Net.Sockets;
using System.Text;
private void button1_Click(object sender, System.EventArgs e)
{
BeginSend();
}
private void BeginSend()
{
string ip=this.txtip.Text;
string port=this.txtport.Text;
IPAddress serverIp=IPAddress.Parse(ip);
int serverPort=Convert.ToInt32(port);
IPEndPoint iep=new IPEndPoint(serverIp,serverPort);
byte[] byteMessage;
// do
// {
Socket socket=new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
socket.Connect(iep);
byteMessage=Encoding.ASCII.GetBytes(textBox1.Text);
socket.Send(byteMessage);
socket.Shutdown(SocketShutdown.Both);
socket.Close();
// }
// while(byteMessage!=null);
}
Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1487041
q程w䆾验证拨入用户服务 (RADIUS) ?RFC 2865“远En份验证拨入用h?(RADIUS)”和 RFC 2866“RADIUS 记帐”中描述的业界标准协议。RADIUS 用于提供w䆾验证、授权和记帐服务。RADIUS 客户端(通常为拨h务器、VPN 服务器或无线讉K点)?RADIUS 消息的Ş式向 RADIUS 服务器发送用户凭据和q接参数信息。RADIUS 服务器对 RADIUS 客户端请求进行n份验证和授权Qƈ发回 RADIUS 消息响应。RADIUS 客户端也?RADIUS 服务器发?RADIUS 记帐消息。另外,RADIUS 标准支持使用 RADIUS 代理。RADIUS 代理是在启用 RADIUS 的计机之间转发 RADIUS 消息的计机?/p>
RADIUS 消息作ؓ用户数据报协?(UDP) 消息被发送。UDP 端口 1812 用于发?RADIUS w䆾验证消息QUDP 端口 1813 用于发?RADIUS 记帐消息。有些网l访问服务器可能会?UDP 端口 1645 发?RADIUS w䆾验证消息Q而?UDP 端口 1646 发?RADIUS 记帐消息。默认情况下QIAS 支持接收发送到q两?UDP 端口?RADIUS 消息。有x?IAS 所使用?UDP 端口的信息,请参?a >配置 IAS 端口信息.RADIUS 数据包的 UDP 负蝲中只包含一?RADIUS 消息?/p>
RFCs 2865 ?2866 定义了以?RADIUS 消息cdQ?/p>
?/td> |
讉K - h ?RADIUS 客户端发送请求对q接试q行w䆾验证和授权? |
?/td> |
讉K - 接收 ?RADIUS 服务器发送,以响应“访?- h”消息。此消息通知 RADIUS 客户端已对连接尝试进行n份验证和授权? |
?/td> |
讉K - 拒绝 ?RADIUS 服务器发送,以响应“访?- h”消息。此消息通知 RADIUS 客户端连接尝试被拒绝。如果凭据未被验证或q接试未被授权QRADIUS 服务器将发送此消息? |
?/td> |
讉K - 质询 ?RADIUS 服务器发送,以响应“访?- h”消息。此消息是对需要响应的 RADIUS 客户端的质询? |
?/td> |
记帐 - h ?RADIUS 客户端发送,为接受的q接指定记帐信息? |
?/td> |
记帐 - 响应 ?RADIUS 服务器发送,以响应“记?- h”消息。此消息认对记帐请求消息的成功接受和处理? |
RADIUS 消息׃?RADIUS 头和零或多个 RADIUS 属性组成。每?RADIUS 属性指定一则有兌接尝试的信息。例如,存在用户名称、用户密码、用戯求的服务cd和访问服务器?IP 地址?RADIUS 属性。RADIUS 属性用于传?RADIUS 客户端、RADIUS 代理?RADIUS 服务器之间的信息。例如,“访?- h”消息中的属性列表包含有关用户凭据和q接试的参数的信息。相反,“访?- 接受”消息包含有兛_创徏的连接类型、连接限制和特定供应商属?(VSA) 的信息?/p>
注意
?/td> |
您可以在 Windows Server 2003 Standard Edition 中配|?IASQ最多配|?50 ?RADIUS 客户端和 2 个远E?RADIUS 服务器组。您可以采用完全合格的域名或 IP 地址定义 RADIUS 客户端,但不能通过指定 IP 地址范围定义 RADIUS 客户端组。如果将 RADIUS 客户端的完全合格的域名解析ؓ多个 IP 地址Q则 IAS 服务器采?DNS 查询中返回的W一?IP 地址。?Windows Server 2003 Enterprise Edition ?Windows Server 2003 Datacenter Edition 中的 IASQ可以配|无限多?RADIUS 客户端和q程 RADIUS 服务器组。另外,您可以通过指定 IP 地址范围来配|?RADIUS 客户端? |
CQ网l编E我们知道CQ和CQ+的差异之一Q就是他本n没有cdQ所使用的类库是.Net框架中的cd--.Net FrameWork SDK。在.Net FrameWork SDK中ؓ|络~程提供了二个名U空_"System.Net"?System.Net.Sockets"。CQ就是通过q二个名U空间中装的类和方法实现网l通讯的?
首先我们解释一下在|络~程时候,l常遇到的几个概念:同步QsynchronousQ、异步(asynchronousQ、阻塞(BlockQ和非阻塞(UnblockQ:
所谓同步方式,是发送方发送数据包以后Q不{接受方响应Q就接着发送下一个数据包。异步方式就是当发送方发送一个数据包以后Q一直等到接受方响应后,才接着发送下一个数据包。而阻塞套接字是指执行此套接字的网l调用时Q直到调用成功才q回Q否则此套节字就一直阻塞在|络调用上,比如调用StreamReader cȝReadlin ( )Ҏd|络~冲Z的数据,如果调用的时候没有数据到达,那么此Readlin ( )Ҏ一直挂在调用上Q直到读C些数据,此函数调用才q回Q而非d套接字是指在执行此套接字的网l调用时Q不是否执行成功,都立卌回。同栯用StreamReader cȝReadlin ( )Ҏd|络~冲Z数据Q不是否读到数据都立即q回Q而不会一直挂在此函数调用上。在Windows|络通信软g开发中Q最为常用的Ҏ是异步非阻塞套接字。^常所说的C/SQ客L/服务器)l构的Y仉用的方式是异步非阻塞模式的?
其实在用CQ进行网l编E中Q我们ƈ不需要了解什么同步、异步、阻塞和非阻塞的原理和工作机Ӟ因ؓ?Net FrameWrok SDK中已l已l把q些机制l封装好了。下面我们就用CQ开一个具体的|络E序来说明一下问题?
一Q本文中介绍的程序设计及q行环境
Q?Q?微Y视窗2000 服务器版
Q?Q?.Net Framework SDK Beta 2以上版本
二.服务器端E序设计的关键步骤以及解军_法:
在下面接受的E序中,我们采用的是异步d的方式?
Q?Q?首先要要在给定的端口上面创徏一?tcpListener"对象侦听|络上面的请求。当接收到连l请求后通过调用"tcpListener"对象?AcceptSocket"Ҏ产生一个用于处理接入连接请求的Socket的实例。下面是具体实现代码Q?
//创徏一个tcpListener对象Q此对象主要是对l定端口q行侦听
tcpListener = new TcpListener ( 1234 ) ;
//开始侦?
tcpListener.Start ( ) ;
//q回可以用以处理q接的Socket实例
socketForClient = tcpListener.AcceptSocket ( ) ;
Q?Q?接受和发送客L数据Q?
此时Socket实例已经产生Q如果网l上有请求,在请求通过以后QSocket实例构造一?NetworkStream"对象Q?NetworkStream"对象为网l访问提供了基础数据。我们通过名称I间"System.IO"中封装的二个c?StreamReader"?StreamWriter"来实现对"NetworkStream"对象的访问。其?StreamReader"cM的ReadLine ( )Ҏ是?NetworkStream"对象中读取一行字W;"StreamWriter"cM的WriteLine ( )Ҏ是?NetworkStream"对象中写入一行字W串。从而实现在|络上面传输字符Ԍ下面是具体的实现代码Q?
try
{
//如果q回值是"true"Q则产生的套节字已经接受来自q方的连接请?
if ( socketForClient.Connected )
{
ListBox1.Items.Add ( "已经和客L成功q接Q? ) ;
while ( true )
{
//创徏networkStream对象通过|络套节字来接受和发送数?
networkStream = new NetworkStream ( socketForClient ) ;
//从当前数据流中读取一行字W,q回值是字符?
streamReader = new StreamReader ( networkStream ) ;
string msg = streamReader.ReadLine ( ) ;
ListBox1.Items.Add ( "收到客户端信息:" + msg ) ;
streamWriter = new StreamWriter ( networkStream ) ;
if ( textBox1.Text != "" )
{
ListBox1.Items.Add ( "往客户端反馈信息:" + textBox1.Text ) ;
//往当前的数据流中写入一行字W串
streamWriter.WriteLine ( textBox1.Text ) ;
//h当前数据中的数?
streamWriter.Flush ( ) ;
}
}
}
}
catch ( Exception ey )
{
MessageBox.Show ( ey.ToString ( ) ) ;
}
Q?Q?最后别忘了要关闭所以流Q停止侦听网l,关闭套节字,具体如下Q?
//关闭U程和流
networkStream.Close ( ) ;
streamReader.Close ( ) ;
streamWriter.Close ( ) ;
_thread1.Abort ( ) ;
tcpListener.Stop ( ) ;
socketForClient.Shutdown ( SocketShutdown.Both ) ;
socketForClient.Close ( ) ;
三.CQ网l编E服务器端程序的部分源代码(server.csQ?Q?
׃在此ơ程序中我们采用的结构是异步d方式Q所以在实际的程序中Qؓ了不影响服务器端E序的运行速度Q我们在E序中设计了一个线E,使得对网l请求侦听,接受和发送数据都在线E中处理Q请在下面的代码中注意这一点,下面是server.cs的完整代码:
using System ;
using System.Drawing ;
using System.Collections ;
using System.ComponentModel ;
using System.Windows.Forms ;
using System.Data ;
using System.Net.Sockets ;
using System.IO ;
using System.Threading ;
using System.Net ;
//导入E序中用到的名字空?
public class Form1 : Form
{
private ListBox ListBox1 ;
private Button button2 ;
private Label label1 ;
private TextBox textBox1 ;
private Button button1 ;
private Socket socketForClient ;
private NetworkStream networkStream ;
private TcpListener tcpListener ;
private StreamWriter streamWriter ;
private StreamReader streamReader ;
private Thread _thread1 ;
private System.ComponentModel.Container components = null ;
public Form1 ( )
{
InitializeComponent ( ) ;
}
//清除E序中用的各种资源
protected override void Dispose ( bool disposing )
{
if ( disposing )
{
if ( components != null )
{
components.Dispose ( ) ;
}
}
base.Dispose ( disposing ) ;
}
private void InitializeComponent ( )
{
label1 = new Label ( ) ;
button2 = new Button ( ) ;
button1 = new Button ( ) ;
ListBox1 = new ListBox ( ) ;
textBox1 = new TextBox ( ) ;
SuspendLayout ( ) ;
label1.Location = new Point ( 8 , 168 ) ;
label1.Name = "label1" ;
label1.Size = new Size ( 120 , 23 ) ;
label1.TabIndex = 3 ;
label1.Text = "往客户端反馈信息:" ;
//同样的方式设|其他控?q里略去
this.Controls.Add ( button1 ) ;
this.Controls.Add ( textBox1 ) ;
this.Controls.Add ( label1 ) ;
this.Controls.Add ( button2 ) ;
this.Controls.Add ( ListBox1 ) ;
this.MaximizeBox = false ;
this.MinimizeBox = false ;
this.Name = "Form1" ;
this.Text = "CQ的|络~程服务器端Q? ;
this.Closed += new System.EventHandler ( this.Form1_Closed ) ;
this.ResumeLayout ( false ) ;
}
private void Listen ( )
{
//创徏一个tcpListener对象Q此对象主要是对l定端口q行侦听
tcpListener = new TcpListener ( 1234 ) ;
//开始侦?
tcpListener.Start ( ) ;
//q回可以用以处理q接的Socket实例
socketForClient = tcpListener.AcceptSocket ( ) ;
try
{
//如果q回值是"true"Q则产生的套节字已经接受来自q方的连接请?
if ( socketForClient.Connected )
{
ListBox1.Items.Add ( "已经和客L成功q接Q? ) ;
while ( true )
{
//创徏networkStream对象通过|络套节字来接受和发送数?
networkStream = new NetworkStream ( socketForClient ) ;
//从当前数据流中读取一行字W,q回值是字符?
streamReader = new StreamReader ( networkStream ) ;
string msg = streamReader.ReadLine ( ) ;
ListBox1.Items.Add ( "收到客户端信息:" + msg ) ;
streamWriter = new StreamWriter ( networkStream ) ;
if ( textBox1.Text != "" )
{
ListBox1.Items.Add ( "往客户端反馈信息:" + textBox1.Text ) ;
//往当前的数据流中写入一行字W串
streamWriter.WriteLine ( textBox1.Text ) ;
//h当前数据中的数?
streamWriter.Flush ( ) ;
}
}
}
}
catch ( Exception ey )
{
MessageBox.Show ( ey.ToString ( ) ) ;
}
}
static void Main ( )
{
Application.Run ( new Form1 ( ) ) ;
}
private void button1_Click ( object sender , System.EventArgs e )
{
ListBox1.Items .Add ( "服务已经启动Q? ) ;
_thread1 = new Thread ( new ThreadStart ( Listen ) ) ;
_thread1.Start ( ) ;
}
private void button2_Click ( object sender , System.EventArgs e )
{
//关闭U程和流
networkStream.Close ( ) ;
streamReader.Close ( ) ;
streamWriter.Close ( ) ;
_thread1.Abort ( ) ;
tcpListener.Stop ( ) ;
socketForClient.Shutdown ( SocketShutdown.Both ) ;
socketForClient.Close ( ) ;
}
private void Form1_Closed ( object sender , System.EventArgs e )
{
//关闭U程和流
networkStream.Close ( ) ;
streamReader.Close ( ) ;
streamWriter.Close ( ) ;
_thread1.Abort ( ) ;
tcpListener.Stop ( ) ;
socketForClient.Shutdown ( SocketShutdown.Both ) ;
socketForClient.Close ( ) ;
}
}
Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=622873
可见Q传输层位于q个l构的最底层Q当其上面的应用协议层和h/响应层不能满_用程序的Ҏ需要时Q就需要用这一层进行Socket套接字编E?
而在.Net中,System.Net.Sockets 命名I间为需要严密控制网l访问的开发h员提供了 Windows Sockets (Winsock) 接口的托实现。System.Net 命名I间中的所有其他网l访问类都徏立在该套接字Socket实现之上Q如TCPClient、TCPListener ?UDPClient cd装有兛_建到 Internet ?TCP ?UDP q接的详l信息;NetworkStreamcd提供用于|络讉K的基数据等Q常见的许多Internet服务都可以见到Socket的踪影,如Telnet、Http、Email、Echo{,q些服务管通讯协议Protocol的定义不同,但是其基的传输都是采用的Socket?
其实QSocket可以象流Stream一栯视ؓ一个数据通道Q这个通道架设在应用程序端Q客LQ和q程服务器端之间。而后Q数据的dQ接Ӟ和写入(发送)均针对这个通道来进行?
可见Q在应用E序端或者服务器端创ZSocket对象之后Q就可以使用Send/SentToҎ数据发送到q接的Socket,或者用Receive/ReceiveFromҎ接收来自q接Socket的数据?/p>
针对Socket~程Q?NET 框架?Socket cL Winsock32 API 提供的套接字服务的托代码版本。其中ؓ实现|络~程提供了大量的ҎQ大多数情况下,Socket cL法只是将数据送到它们的本机Win32 副本中ƈ处理M必要的安全检查。如果你熟悉Winsock API函数Q那么用Socketcȝ写网l程序会非常ҎQ当Ӟ如果你不曾接触过Q也不会太困难,跟随下面的解_你会发觉使用Socketcd发windows |络应用E序原来有规可寻Q它们在大多数情况下遵@大致相同的步骤?
在用之前,你需要首先创建Socket对象的实例,q可以通过Socketcȝ构造方法来实现Q?
public Socket(AddressFamily addressFamily,SocketType socketType,ProtocolType protocolType);
其中QaddressFamily 参数指定 Socket 使用的寻址ҎQsocketType 参数指定 Socket 的类型,protocolType 参数指定 Socket 使用的协议?
下面的示例语句创Z个SocketQ它可用于在Z TCP/IP 的网l(?InternetQ上通讯?
Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
若要使用 UDP 而不?TCPQ需要更改协议类型,如下面的CZ所C:
Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
一旦创?SocketQ在客户端,你将可以通过ConnectҎq接到指定的服务器,q过Send/SendToҎ向远E服务器发送数据,而后可以通过Receive/ReceiveFrom从服务端接收数据Q而在服务器端Q你需要用BindҎl定所指定的接口Socket与一个本地终l点相联Qƈ通过ListenҎ侦听该接口上的请求,当侦听到用户端的q接Ӟ调用Accept完成q接的操作,创徏新的Socket以处理传入的q接h。用完Socket后,C使用 Shutdown Ҏ用SocketQƈ使用 Close Ҏ关闭 Socket。其间用到的Ҏ/函数有:
Socket.ConnectҎ:建立到远E设备的q接
public void Connect(EndPoint remoteEP)Q有重蝲ҎQ?
Socket.Send Ҏ:从数据中的指CZ|开始将数据发送到q接?Socket?
public int Send(byte[], int, SocketFlags);(有重载方?
Socket.SendTo Ҏ 数据发送到特定l结炏V?
public int SendTo(byte[], EndPoint);Q有重蝲ҎQ?
Socket.ReceiveҎ:数据从q接?Socket 接收到接收缓冲区的特定位|?
public int Receive(byte[],int,SocketFlags);
Socket.ReceiveFromҎQ接收数据缓冲区中特定位|的数据q存储终l点?
public int ReceiveFrom(byte[], int, SocketFlags, ref EndPoint);
Socket.Bind ҎQ Socket 与一个本地终l点相关联:
public void Bind( EndPoint localEP );
Socket.ListenҎQ将 Socket |于侦听状态?
public void Listen( int backlog );
Socket.AcceptҎ:创徏新的 Socket 以处理传入的q接h?
public Socket Accept();
Socket.ShutdownҎ:用?Socket 上的发送和接收
public void Shutdown( SocketShutdown how );
Socket.CloseҎ:强制 Socket q接关闭
public void Close();
可以看出Q以上许多方法包含EndPointcd的参。在Internet中,TCP/IP 使用一个网l地址和一个服务端口号来唯一标识讑֤。网l地址标识|络上的特定讑֤Q端口号标识要连接到的该讑֤上的特定服务。网l地址和服务端口的l合UCؓl结炏V?/p>
?.NET 框架中正是由 EndPoint c表C个终l点Q它提供表示|络资源或服务的抽象Q用以标志网l地址{信息?Net同时也ؓ每个受支持的地址族定义了 EndPoint 的子代;对于 IP 地址族,该类?IPEndPoint。IPEndPoint cd含应用程序连接到L上的服务所需的主机和端口信息Q通过l合服务的主机IP地址和端口号QIPEndPoint cdŞ成到服务的连接点?
用到IPEndPointcȝ时候就不可避免地涉及到计算机IP地址Q?Net中有两种cd以得到IP地址实例Q?
IPAddressc:IPAddress cd含计机?IP |络上的地址。其ParseҎ可将 IP 地址字符串{换ؓ IPAddress 实例。下面的语句创徏一?IPAddress 实例Q?
IPAddress myIP = IPAddress.Parse("192.168.1.2");
Dns c:向?TCP/IP Internet 服务的应用程序提供域名服务。其Resolve Ҏ查询 DNS 服务器以用户友好的域名Q如"host.contoso.com"Q映到数字形式?Internet 地址Q如 192.168.1.1Q。ResolveҎq回一?IPHostEnty 实例Q该实例包含所h名称的地址和别名的列表。大多数情况下,可以使用 AddressList 数组中返回的W一个地址。下面的代码获取一?IPAddress 实例Q该实例包含服务?host.contoso.com ?IP 地址?
IPHostEntry ipHostInfo = Dns.Resolve("host.contoso.com");
IPAddress ipAddress = ipHostInfo.AddressList[0];
你也可以使用GetHostNameҎ得到IPHostEntry实例Q?
IPHosntEntry hostInfo=Dns.GetHostByName("host.contoso.com")
在用以上方法时Q你可能需要处理以下几U异常:
SocketException异常Q访问Socket时操作系l发生错误引?
ArgumentNullException异常Q参CؓI引用引?
ObjectDisposedException异常QSocket已经关闭引发
在掌握上面得知识后,下面的代码将该服务器LQ?host.contoso.com?IP 地址与端口号l合Q以便ؓq接创徏q程l结点:
IPEndPoint ipe = new IPEndPoint(ipAddress,11000);
定了远E设备的地址q择了用于连接的端口后,应用E序可以试建立与远E设备的q接。下面的CZ使用现有?IPEndPoint 实例与远E设备连接,q捕获可能引发的异常Q?
try {
s.Connect(ipe);//试q接
}
//处理参数为空引用异常
catch(ArgumentNullException ae) {
Console.WriteLine("ArgumentNullException : {0}", ae.ToString());
}
//处理操作pȝ异常
catch(SocketException se) {
Console.WriteLine("SocketException : {0}", se.ToString());
}
catch(Exception e) {
Console.WriteLine("Unexpected exception : {0}", e.ToString());
}
需要知道的是:Socket cL持两U基本模式:同步和异步。其区别在于Q在同步模式中,Ҏ行网l操作的函数Q如 Send ?ReceiveQ的调用一直等到操作完成后才将控制q回l调用程序。在异步模式中,q些调用立即q回?
另外Q很多时候,Socket~程视情况不同需要在客户端和服务器端分别予以实现Q在客户端编制应用程序向服务端指定端口发送请求,同时~制服务端应用程序处理该hQ这个过E在上面的阐qC已经提及Q当Ӟq所有的Socket~程都需要你严格~写q两端程序;视应用情况不同,你可以在客户端构造出h字符Ԍ服务器相应端口捕莯个请求,交由其公用服务程序进行处理。以下事例语句中的字W串向q程L提出面hQ?
string Get = "GET / HTTP/1.1\r\nHost: " + server + "\r\nConnection: Close\r\n\r\n";
q程L指定端口接受到这一h后,可利用其公用服务程序进行处理而不需要另行编制服务器端应用程序?
l合q用以上阐述的用Visual C#q行Socket|络E序开发的知识Q下面的E序D完整地实现了Web面下蝲功能。用户只需在窗体上输入q程L名(Dns L名或以点分隔的四部分表示法格式的 IP 地址Q和预保存的本地文g名,q利用专门提供Http服务?0端口Q就可以获取q程L面q保存在本地机指定文件中。如果保存格式是.htm格式Q你可以在Internet览器中打开该页面。适当d代码Q你甚至可以实现一个简单的览器程序?
实现此功能的主要源代码如下:
//"开?按钮事g
private void button1_Click(object sender, System.EventArgs e) {
//取得预保存的文g?
string fileName=textBox3.Text.Trim();
//q程L
string hostName=textBox1.Text.Trim();
//端口
int port=Int32.Parse(textBox2.Text.Trim());
//得到L信息
IPHostEntry ipInfo=Dns.GetHostByName(hostName);
//取得IPAddress[]
IPAddress[] ipAddr=ipInfo.AddressList;
//得到ip
IPAddress ip=ipAddr[0];
//l合E终l点
IPEndPoint hostEP=new IPEndPoint(ip,port);
//创徏Socket 实例
Socket socket=new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
try
{
//试q接
socket.Connect(hostEP);
}
catch(Exception se)
{
MessageBox.Show("q接错误"+se.Message,"提示信息
,MessageBoxButtons.RetryCancel,MessageBoxIcon.Information);
}
//发送给q程L的请求内容串
string sendStr="GET / HTTP/1.1\r\nHost: " + hostName +
"\r\nConnection: Close\r\n\r\n";
//创徏bytes字节数组以{换发送串
byte[] bytesSendStr=new byte[1024];
//发送内容字W串转换成字节byte数组
bytesSendStr=Encoding.ASCII.GetBytes(sendStr);
try
{
//向主机发送请?
socket.Send(bytesSendStr,bytesSendStr.Length,0);
}
catch(Exception ce)
{
MessageBox.Show("发送错?"+ce.Message,"提示信息
,MessageBoxButtons.RetryCancel,MessageBoxIcon.Information);
}
//声明接收q回内容的字W串
string recvStr="";
//声明字节数组Q一ơ接收数据的长度?024字节
byte[] recvBytes=new byte[1024];
//q回实际接收内容的字节数
int bytes=0;
//循环dQ直到接收完所有数?
while(true)
{
bytes=socket.Receive(recvBytes,recvBytes.Length,0);
//d完成后退出@?
if(bytes<=0)
break;
//读取的字节数{换ؓ字符?
recvStr+=Encoding.ASCII.GetString(recvBytes,0,bytes);
}
//所d的字W串转换为字节数l?
byte[] content=Encoding.ASCII.GetBytes(recvStr);
try
{
//创徏文g对象实?
FileStream fs=new FileStream(fileName,FileMode.OpenOrCreate,FileAccess.ReadWrite);
//写入文g
fs.Write(content,0,content.Length);
}
catch(Exception fe)
{
MessageBox.Show("文g创徏/写入错误:"+fe.Message,"提示信息",MessageBoxButtons.RetryCancel,MessageBoxIcon.Information);
}
//用Socket
socket.Shutdown(SocketShutdown.Both);
//关闭Socket
socket.Close();
}
}
E序在WindowsXP中文版?Net Frameworkd 中文正式版、Visual Studio.Net中文正式版下调试通过?br />
Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=604607