国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開APP
userphoto
未登錄

開通VIP,暢享免費(fèi)電子書等14項(xiàng)超值服

開通VIP
C#網(wǎng)絡(luò)編程入門
 

文章作者:chinasnowli
文章出處:虎盟網(wǎng)絡(luò)安全小組(rohu.com)

.NET提供了兩個(gè)用于網(wǎng)絡(luò)編程的名空間: System.Net和System.Net.Socket.這些類和方法可以幫助我們進(jìn)行網(wǎng)絡(luò)編程,通過網(wǎng)絡(luò)進(jìn)行通信.通信可以是面向連接的,也可以是面向無連接的;既可以采用數(shù)據(jù)流模式,也可以采用數(shù)據(jù)報(bào)的模式.廣泛使用的TCP協(xié)議用基于數(shù)據(jù)流的通信,而UDP協(xié)議用于基于數(shù)據(jù)報(bào)的通信.

System.Net.Sokcets.Socket 是System.Net.Sockets名空間下面一個(gè)非常重要的類. 每一個(gè)套接字的實(shí)例都有一個(gè)本地的和一個(gè)遠(yuǎn)程的端點(diǎn)附加在上面.本地的端點(diǎn)包括了當(dāng)前套接字實(shí)例的連接信息.

.NET還提供了其它的一些類用于我們進(jìn)行網(wǎng)絡(luò)編程,像IPEndPoint, IPAddress, SocketException等等. .NET 支持同步和異步兩種在客戶機(jī)和服務(wù)器之間的通信方式..NET提供了不同的方法用于支持這兩種類型的通信.同步的方法工作在阻塞模式,方法在工作完成之前是不返回的.但是異步的方法工作在非阻塞模式,但是立即返回的,可能在操作完成之前.

Dns類

Dns位于System.net名空間下,它用于創(chuàng)建和發(fā)送一個(gè)請(qǐng)求用于從DNS服務(wù)器獲取一個(gè)主機(jī)服務(wù)器的信息.當(dāng)然,在訪問DNS之前,機(jī)器必須首先要連接到網(wǎng)絡(luò)上,當(dāng)在一臺(tái)獨(dú)立的機(jī)器上執(zhí)行DNS查詢時(shí),由于無法連接到DNS服務(wù)器,就會(huì)產(chǎn)生一個(gè) Systm.Net.SocketException異常.這個(gè)類的所有成員方法都是靜態(tài)的.這個(gè)類中最重要的方法是:

public static IPHostEntry GetHostByAddress(string address)

地址應(yīng)該是一個(gè)用點(diǎn)開的正確的IP地址,這個(gè)方法返回一個(gè)IPHostEntry 實(shí)例,它包括了主機(jī)的信息.如果DNS服務(wù)器不可用,這個(gè)方法將產(chǎn)生一個(gè)SocketException異常.

public static string GetHostName()

這個(gè)方法返回本地機(jī)器的DNS服務(wù)器名稱.

public static IPHostEntry Resolve(string hostname)

這個(gè)方法解析一個(gè)DNS主機(jī)名稱或IP地址為一個(gè)IPHostEntry實(shí)例. 主機(jī)名稱應(yīng)該是一個(gè)用點(diǎn)分開的IP地址,如:127.0.0.1www.rohu.com.

IPHostEntry 類
IPHostEntry 類是一個(gè)容器類,它包含INTERNET上主機(jī)的地址信息.這個(gè)類不是線程安全的.下面是這個(gè)類的幾個(gè)重要成員.

AddressList 屬性

該屬性給出一個(gè)IPAddress的數(shù)組,可以獲取或設(shè)置與主機(jī)關(guān)聯(lián)的 IP 地址列表.

Aliases 屬性

該屬性用于獲取或設(shè)置與主機(jī)關(guān)聯(lián)的別名列表。

下面的程序用到了上面提到的兩個(gè)類.

using System;
using System.Net;
using System.Net.Sockets;

class MyClient
{
public static void Main()
{
IPHostEntry IPHost = Dns.Resolve("www.rohu.com");
Console.WriteLine(IPHost.HostName);
string[] aliases = IPHost.Aliases;
Console.WriteLine(alises.Length);

IPAddress[] addr = IPHost.AddressList;
Console.WriteLine(addr.Length);
for(int i=0; i<addr.Length; i++)
{
Console.Writeline(addr[i]);
}
}
}

IPEndPoint 類

這是一個(gè)從抽象類EndPoint繼承而來的一個(gè)類,它將網(wǎng)絡(luò)端點(diǎn)表示為 IP 地址和端口號(hào)。下面展示的是這個(gè)類的使用.

IPEndPoint(long address ,int port)

IPEndPoint(IPAddress addr, int port)

IpHostEntry IPHost = Dns.Resolve("www.rohu.com");

Console.WriteLine(IPHost.HostName);

string[] aliases = IPHost.Aliases;

IPAddress[] addr = IPHost.AddressList;

Console.WriteLine(addr[0]);

EndPoint ep = new IPEndPoint(addr[0], 80);

2005-8-25 19:50:53
倒飛
等級(jí):
文章:
積分:
門派:無門無派
注冊(cè):
2
 

Socket篇

作者: 宋華
Microsoft.Net Framework為應(yīng)用程序訪問Internet提供了分層的、可擴(kuò)展的以及受管轄的網(wǎng)絡(luò)服務(wù),其名字空間System.Net和 System.Net.Sockets包含豐富的類可以開發(fā)多種網(wǎng)絡(luò)應(yīng)用程序。.Net類采用的分層結(jié)構(gòu)允許應(yīng)用程序在不同的控制級(jí)別上訪問網(wǎng)絡(luò),開發(fā)人員可以根據(jù)需要選擇針對(duì)不同的級(jí)別編制程序,這些級(jí)別幾乎囊括了Internet的所有需要--從socket套接字到普通的請(qǐng)求/響應(yīng),更重要的是,這種分層是可以擴(kuò)展的,能夠適應(yīng)Internet不斷擴(kuò)展的需要。

拋開ISO/OSI模型的7層構(gòu)架,單從TCP/IP模型上的邏輯層面上看,.Net類可以視為包含3個(gè)層次:請(qǐng)求/響應(yīng)層、應(yīng)用協(xié)議層、傳輸層。WebReqeust和WebResponse 代表了請(qǐng)求/響應(yīng)層,支持Http、Tcp和Udp的類組成了應(yīng)用協(xié)議層,而Socket類處于傳輸層??梢匀缦率疽猓?


可見,傳輸層位于這個(gè)結(jié)構(gòu)的最底層,當(dāng)其上面的應(yīng)用協(xié)議層和請(qǐng)求/響應(yīng)層不能滿足應(yīng)用程序的特殊需要時(shí),就需要使用這一層進(jìn)行Socket套接字編程。

而在.Net中,System.Net.Sockets 命名空間為需要嚴(yán)密控制網(wǎng)絡(luò)訪問的開發(fā)人員提供了 Windows Sockets (Winsock) 接口的托管實(shí)現(xiàn)。System.Net 命名空間中的所有其他網(wǎng)絡(luò)訪問類都建立在該套接字Socket實(shí)現(xiàn)之上,如TCPClient、TCPListener 和 UDPClient 類封裝有關(guān)創(chuàng)建到 Internet 的 TCP 和 UDP 連接的詳細(xì)信息;NetworkStream類則提供用于網(wǎng)絡(luò)訪問的基礎(chǔ)數(shù)據(jù)流等,常見的許多Internet服務(wù)都可以見到Socket的蹤影,如 Telnet、Http、Email、Echo等,這些服務(wù)盡管通訊協(xié)議Protocol的定義不同,但是其基礎(chǔ)的傳輸都是采用的Socket。

其實(shí),Socket可以象流Stream一樣被視為一個(gè)數(shù)據(jù)通道,這個(gè)通道架設(shè)在應(yīng)用程序端(客戶端)和遠(yuǎn)程服務(wù)器端之間,而后,數(shù)據(jù)的讀?。ń邮眨┖蛯懭耄òl(fā)送)均針對(duì)這個(gè)通道來進(jìn)行。

可見,在應(yīng)用程序端或者服務(wù)器端創(chuàng)建了Socket對(duì)象之后,就可以使用Send/SentTo方法將數(shù)據(jù)發(fā)送到連接的Socket,或者使用Receive/ReceiveFrom方法接收來自連接Socket的數(shù)據(jù);

針對(duì)Socket編程,.NET 框架的 Socket 類是 Winsock32 API 提供的套接字服務(wù)的托管代碼版本。其中為實(shí)現(xiàn)網(wǎng)絡(luò)編程提供了大量的方法,大多數(shù)情況下,Socket 類方法只是將數(shù)據(jù)封送到它們的本機(jī) Win32 副本中并處理任何必要的安全檢查。如果你熟悉Winsock API函數(shù),那么用Socket類編寫網(wǎng)絡(luò)程序會(huì)非常容易,當(dāng)然,如果你不曾接觸過,也不會(huì)太困難,跟隨下面的解說,你會(huì)發(fā)覺使用Socket類開發(fā) windows 網(wǎng)絡(luò)應(yīng)用程序原來有規(guī)可尋,它們?cè)诖蠖鄶?shù)情況下遵循大致相同的步驟。

在使用之前,你需要首先創(chuàng)建Socket對(duì)象的實(shí)例,這可以通過Socket類的構(gòu)造方法來實(shí)現(xiàn):

public Socket(AddressFamily addressFamily,SocketType socketType,ProtocolType protocolType);


其中,addressFamily 參數(shù)指定 Socket 使用的尋址方案,socketType 參數(shù)指定 Socket 的類型,protocolType 參數(shù)指定 Socket 使用的協(xié)議。

下面的示例語(yǔ)句創(chuàng)建一個(gè) Socket,它可用于在基于 TCP/IP 的網(wǎng)絡(luò)(如 Internet)上通訊。

Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);


若要使用 UDP 而不是 TCP,需要更改協(xié)議類型,如下面的示例所示:

Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);


一旦創(chuàng)建 Socket,在客戶端,你將可以通過Connect方法連接到指定的服務(wù)器,并通過Send/SendTo方法向遠(yuǎn)程服務(wù)器發(fā)送數(shù)據(jù),而后可以通過 Receive/ReceiveFrom從服務(wù)端接收數(shù)據(jù);而在服務(wù)器端,你需要使用Bind方法綁定所指定的接口使Socket與一個(gè)本地終結(jié)點(diǎn)相聯(lián),并通過Listen方法偵聽該接口上的請(qǐng)求,當(dāng)偵聽到用戶端的連接時(shí),調(diào)用Accept完成連接的操作,創(chuàng)建新的Socket以處理傳入的連接請(qǐng)求。使用完 Socket 后,記住使用 Shutdown 方法禁用 Socket,并使用 Close 方法關(guān)閉 Socket。其間用到的方法/函數(shù)有:

Socket.Connect方法:建立到遠(yuǎn)程設(shè)備的連接
public void Connect(EndPoint remoteEP)(有重載方法)
Socket.Send 方法:從數(shù)據(jù)中的指示位置開始將數(shù)據(jù)發(fā)送到連接的 Socket。
public int Send(byte[], int, SocketFlags);(有重載方法)
Socket.SendTo 方法 將數(shù)據(jù)發(fā)送到特定終結(jié)點(diǎn)。
public int SendTo(byte[], EndPoint);(有重載方法)
Socket.Receive方法:將數(shù)據(jù)從連接的 Socket 接收到接收緩沖區(qū)的特定位置。
public int Receive(byte[],int,SocketFlags);
Socket.ReceiveFrom方法:接收數(shù)據(jù)緩沖區(qū)中特定位置的數(shù)據(jù)并存儲(chǔ)終結(jié)點(diǎn)。
public int ReceiveFrom(byte[], int, SocketFlags, ref EndPoint);
Socket.Bind 方法:使 Socket 與一個(gè)本地終結(jié)點(diǎn)相關(guān)聯(lián):
public void Bind( EndPoint localEP );
Socket.Listen方法:將 Socket 置于偵聽狀態(tài)。
public void Listen( int backlog );
Socket.Accept方法:創(chuàng)建新的 Socket 以處理傳入的連接請(qǐng)求。
public Socket Accept();
Socket.Shutdown方法:禁用某 Socket 上的發(fā)送和接收
public void Shutdown( SocketShutdown how );
Socket.Close方法:強(qiáng)制 Socket 連接關(guān)閉
public void Close();


可以看出,以上許多方法包含EndPoint類型的參數(shù),在Internet中,TCP/IP 使用一個(gè)網(wǎng)絡(luò)地址和一個(gè)服務(wù)端口號(hào)來唯一標(biāo)識(shí)設(shè)備。網(wǎng)絡(luò)地址標(biāo)識(shí)網(wǎng)絡(luò)上的特定設(shè)備;端口號(hào)標(biāo)識(shí)要連接到的該設(shè)備上的特定服務(wù)。網(wǎng)絡(luò)地址和服務(wù)端口的組合稱為終結(jié)點(diǎn),在 .NET 框架中正是由 EndPoint 類表示這個(gè)終結(jié)點(diǎn),它提供表示網(wǎng)絡(luò)資源或服務(wù)的抽象,用以標(biāo)志網(wǎng)絡(luò)地址等信息。.Net同時(shí)也為每個(gè)受支持的地址族定義了 EndPoint 的子代;對(duì)于 IP 地址族,該類為 IPEndPoint。IPEndPoint 類包含應(yīng)用程序連接到主機(jī)上的服務(wù)所需的主機(jī)和端口信息,通過組合服務(wù)的主機(jī)IP地址和端口號(hào),IPEndPoint 類形成到服務(wù)的連接點(diǎn)。

用到IPEndPoint類的時(shí)候就不可避免地涉及到計(jì)算機(jī)IP地址,.Net中有兩種類可以得到IP地址實(shí)例:

IPAddress類:IPAddress 類包含計(jì)算機(jī)在 IP 網(wǎng)絡(luò)上的地址。其Parse方法可將 IP 地址字符串轉(zhuǎn)換為 IPAddress 實(shí)例。下面的語(yǔ)句創(chuàng)建一個(gè) IPAddress 實(shí)例:

IPAddress myIP = IPAddress.Parse("192.168.1.2");


Dns 類:向使用 TCP/IP Internet 服務(wù)的應(yīng)用程序提供域名服務(wù)。其Resolve 方法查詢 DNS 服務(wù)器以將用戶友好的域名(如"host.contoso.com")映射到數(shù)字形式的 Internet 地址(如 192.168.1.1)。Resolve方法 返回一個(gè) IPHostEnty 實(shí)例,該實(shí)例包含所請(qǐng)求名稱的地址和別名的列表。大多數(shù)情況下,可以使用 AddressList 數(shù)組中返回的第一個(gè)地址。下面的代碼獲取一個(gè) IPAddress 實(shí)例,該實(shí)例包含服務(wù)器 host.contoso.com 的 IP 地址。

IPHostEntry ipHostInfo = Dns.Resolve("host.contoso.com");
IPAddress ipAddress = ipHostInfo.AddressList[0];


你也可以使用GetHostName方法得到IPHostEntry實(shí)例:

IPHosntEntry hostInfo=Dns.GetHostByName("host.contoso.com")


在使用以上方法時(shí),你將可能需要處理以下幾種異常:

SocketException異常:訪問Socket時(shí)操作系統(tǒng)發(fā)生錯(cuò)誤引發(fā)

ArgumentNullException異常:參數(shù)為空引用引發(fā)

ObjectDisposedException異常:Socket已經(jīng)關(guān)閉引發(fā)

在掌握上面得知識(shí)后,下面的代碼將該服務(wù)器主機(jī)( host.contoso.com的 IP 地址與端口號(hào)組合,以便為連接創(chuàng)建遠(yuǎn)程終結(jié)點(diǎn):

IPEndPoint ipe = new IPEndPoint(ipAddress,11000);


確定了遠(yuǎn)程設(shè)備的地址并選擇了用于連接的端口后,應(yīng)用程序可以嘗試建立與遠(yuǎn)程設(shè)備的連接。下面的示例使用現(xiàn)有的 IPEndPoint 實(shí)例與遠(yuǎn)程設(shè)備連接,并捕獲可能引發(fā)的異常:

try {
s.Connect(ipe);//嘗試連接
}
//處理參數(shù)為空引用異常
catch(ArgumentNullException ae) {
Console.WriteLine("ArgumentNullException : {0}", ae.ToString());
}
//處理操作系統(tǒng)異常
catch(SocketException se) {
Console.WriteLine("SocketException : {0}", se.ToString());
}
catch(Exception e) {
Console.WriteLine("Unexpected exception : {0}", e.ToString());
}


需要知道的是:Socket 類支持兩種基本模式:同步和異步。其區(qū)別在于:在同步模式中,對(duì)執(zhí)行網(wǎng)絡(luò)操作的函數(shù)(如 Send 和 Receive)的調(diào)用一直等到操作完成后才將控制返回給調(diào)用程序。在異步模式中,這些調(diào)用立即返回。

另外,很多時(shí)候,Socket編程視情況不同需要在客戶端和服務(wù)器端分別予以實(shí)現(xiàn),在客戶端編制應(yīng)用程序向服務(wù)端指定端口發(fā)送請(qǐng)求,同時(shí)編制服務(wù)端應(yīng)用程序處理該請(qǐng)求,這個(gè)過程在上面的闡述中已經(jīng)提及;當(dāng)然,并非所有的Socket編程都需要你嚴(yán)格編寫這兩端程序;視應(yīng)用情況不同,你可以在客戶端構(gòu)造出請(qǐng)求字符串,服務(wù)器相應(yīng)端口捕獲這個(gè)請(qǐng)求,交由其公用服務(wù)程序進(jìn)行處理。以下事例語(yǔ)句中的字符串就向遠(yuǎn)程主機(jī)提出頁(yè)面請(qǐng)求:

string Get = "GET / HTTP/1.1\r\nHost: " + server + "\r\nConnection: Close\r\n\r\n";


遠(yuǎn)程主機(jī)指定端口接受到這一請(qǐng)求后,就可利用其公用服務(wù)程序進(jìn)行處理而不需要另行編制服務(wù)器端應(yīng)用程序。

綜合運(yùn)用以上闡述的使用Visual C#進(jìn)行Socket網(wǎng)絡(luò)程序開發(fā)的知識(shí),下面的程序段完整地實(shí)現(xiàn)了Web頁(yè)面下載功能。用戶只需在窗體上輸入遠(yuǎn)程主機(jī)名(Dns 主機(jī)名或以點(diǎn)分隔的四部分表示法格式的 IP 地址)和預(yù)保存的本地文件名,并利用專門提供Http服務(wù)的80端口,就可以獲取遠(yuǎn)程主機(jī)頁(yè)面并保存在本地機(jī)指定文件中。如果保存格式是.htm格式,你就可以在Internet瀏覽器中打開該頁(yè)面。適當(dāng)添加代碼,你甚至可以實(shí)現(xiàn)一個(gè)簡(jiǎn)單的瀏覽器程序。


實(shí)現(xiàn)此功能的主要源代碼如下:

//"開始"按鈕事件
private void button1_Click(object sender, System.EventArgs e) {
//取得預(yù)保存的文件名
string fileName=textBox3.Text.Trim();
//遠(yuǎn)程主機(jī)
string hostName=textBox1.Text.Trim();
//端口
int port=Int32.Parse(textBox2.Text.Trim());
//得到主機(jī)信息
IPHostEntry ipInfo=Dns.GetHostByName(hostName);
//取得IPAddress[]
IPAddress[] ipAddr=ipInfo.AddressList;
//得到ip
IPAddress ip=ipAddr[0];
//組合出遠(yuǎn)程終結(jié)點(diǎn)
IPEndPoint hostEP=new IPEndPoint(ip,port);
//創(chuàng)建Socket 實(shí)例
Socket socket=new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
try
{
//嘗試連接
socket.Connect(hostEP);
}
catch(Exception se)
{
MessageBox.Show("連接錯(cuò)誤"+se.Message,"提示信息
,MessageBoxButtons.RetryCancel,MessageBoxIcon.Information);
}
//發(fā)送給遠(yuǎn)程主機(jī)的請(qǐng)求內(nèi)容串
string sendStr="GET / HTTP/1.1\r\nHost: " + hostName +
"\r\nConnection: Close\r\n\r\n";
//創(chuàng)建bytes字節(jié)數(shù)組以轉(zhuǎn)換發(fā)送串
byte[] bytesSendStr=new byte[1024];
//將發(fā)送內(nèi)容字符串轉(zhuǎn)換成字節(jié)byte數(shù)組
bytesSendStr=Encoding.ASCII.GetBytes(sendStr);
try
{
//向主機(jī)發(fā)送請(qǐng)求
socket.Send(bytesSendStr,bytesSendStr.Length,0);
}
catch(Exception ce)
{
MessageBox.Show("發(fā)送錯(cuò)誤:"+ce.Message,"提示信息
,MessageBoxButtons.RetryCancel,MessageBoxIcon.Information);
}
//聲明接收返回內(nèi)容的字符串
string recvStr="";
//聲明字節(jié)數(shù)組,一次接收數(shù)據(jù)的長(zhǎng)度為1024字節(jié)
byte[] recvBytes=new byte[1024];
//返回實(shí)際接收內(nèi)容的字節(jié)數(shù)
int bytes=0;
//循環(huán)讀取,直到接收完所有數(shù)據(jù)
while(true)
{
bytes=socket.Receive(recvBytes,recvBytes.Length,0);
//讀取完成后退出循環(huán)
if(bytes<=0)
break;
//將讀取的字節(jié)數(shù)轉(zhuǎn)換為字符串
recvStr+=Encoding.ASCII.GetString(recvBytes,0,bytes);
}
//將所讀取的字符串轉(zhuǎn)換為字節(jié)數(shù)組
byte[] content=Encoding.ASCII.GetBytes(recvStr);
try
{
//創(chuàng)建文件流對(duì)象實(shí)例
FileStream fs=new FileStream(fileName,FileMode.OpenOrCreate,FileAccess.ReadWrite);
//寫入文件
fs.Write(content,0,content.Length);
}
catch(Exception fe)
{
MessageBox.Show("文件創(chuàng)建/寫入錯(cuò)誤:"+fe.Message,"提示信息",MessageBoxButtons.RetryCancel,MessageBoxIcon.Information);
}
//禁用Socket
socket.Shutdown(SocketShutdown.Both);
//關(guān)閉Socket
socket.Close();
}
}


程序在WindowsXP中文版、.Net Frameworkd 中文正式版、Visual Studio.Net中文正式版下調(diào)試通過

2005-8-25 20:09:59
倒飛
等級(jí):
文章:
積分:
門派:無門無派
注冊(cè):
3
 

網(wǎng)絡(luò)編程之TCP

 

前一篇《Visual C#.Net網(wǎng)絡(luò)程序開發(fā)之Socket》中說到:支持Http、Tcp和Udp的類組成了TCP/IP三層模型(請(qǐng)求響應(yīng)層、應(yīng)用協(xié)議層、傳輸層)的中間層-應(yīng)用協(xié)議層,該層的類比位于最底層的Socket類提供了更高層次的抽象,它們封裝 TCP 和 UDP 套接字的創(chuàng)建,不需要處理連接的細(xì)節(jié),這使得我們?cè)诰帉懱捉幼旨?jí)別的協(xié)議時(shí),可以更多地嘗試使用


TCPClient 、 UDPClient和TcpListener,而不是直接向 Socket 中寫。它們之間的這種層次關(guān)系示意如下:

  可見,TcpClient 類基于 Socket 類構(gòu)建,這是它能夠以更高的抽象程度提供 TCP 服務(wù)的基礎(chǔ)。正因?yàn)檫@樣,許多應(yīng)用層上的通訊協(xié)議,比如FTP(File Transfers Protocol)文件傳輸協(xié)議、HTTP(Hypertext Transfers Protocol)超文本傳輸協(xié)議等都直接創(chuàng)建在TcpClient等類之上。

  TCPClient 類使用 TCP 從 Internet 資源請(qǐng)求數(shù)據(jù)。TCP 協(xié)議建立與遠(yuǎn)程終結(jié)點(diǎn)的連接,然后使用此連接發(fā)送和接收數(shù)據(jù)包。TCP 負(fù)責(zé)確保將數(shù)據(jù)包發(fā)送到終結(jié)點(diǎn)并在數(shù)據(jù)包到達(dá)時(shí)以正確的順序?qū)ζ溥M(jìn)行組合。

  從名字上就可以看出,TcpClient類專為客戶端設(shè)計(jì),它為 TCP 網(wǎng)絡(luò)服務(wù)提供客戶端連接。TcpClient 提供了通過網(wǎng)絡(luò)連接、發(fā)送和接收數(shù)據(jù)的簡(jiǎn)單方法。

  若要建立 TCP 連接,必須知道承載所需服務(wù)的網(wǎng)絡(luò)設(shè)備的地址(IPAddress)以及該服務(wù)用于通訊的 TCP 端口 (Port)。Internet 分配號(hào)碼機(jī)構(gòu) (Internet Assigned Numbers Authority, IANA) 定義公共服務(wù)的端口號(hào)(你可以訪問 http://www.iana.org/assignments/port-numbers獲得這方面更詳細(xì)的資料)。IANA 列表中所沒有的服務(wù)可使用 1,024 到 65,535 這一范圍中的端口號(hào)。要?jiǎng)?chuàng)建這種連接,你可以選用TcpClient類的三種構(gòu)造函數(shù)之一:

  1、public TcpClient()當(dāng)使用這種不帶任何參數(shù)的構(gòu)造函數(shù)時(shí),將使用本機(jī)默認(rèn)的ip地址并將使用默認(rèn)的通信端口號(hào)0。這樣情況下,如果本機(jī)不止一個(gè)ip地址,將無法選擇使用。以下語(yǔ)句示例了如何使用默認(rèn)構(gòu)造函數(shù)來創(chuàng)建新的 TcpClient:

TcpClient tcpClientC = new TcpClient();

  2、public TcpClient(IPEndPoint)使用本機(jī)IPEndPoint創(chuàng)建TcpClient的實(shí)例對(duì)象。上一篇介紹過了,IPEndPoint將網(wǎng)絡(luò)端點(diǎn)表示為IP地址和端口號(hào),在這里它用于指定在建立遠(yuǎn)程主機(jī)連接時(shí)所使用的本地網(wǎng)絡(luò)接口(IP 地址)和端口號(hào),這個(gè)構(gòu)造方法為使用本機(jī)IPAddress和Port提供了選擇余地。下面的語(yǔ)句示例了如何使用本地終結(jié)點(diǎn)創(chuàng)建 TcpClient 類的實(shí)例:

IPHostEntry ipInfo=Dns.GetHostByName("www.tuha.net");//主機(jī)信息
IPAddressList[] ipList=ipInfo.AddressList;//IP地址數(shù)組
IPAddress ip=ipList[0];//多IP地址時(shí)一般用第一個(gè)
IPEndPoint ipEP=new IPEndPoint(ip,4088);//得到網(wǎng)絡(luò)終結(jié)點(diǎn)
try{
TcpClient tcpClientA = new TcpClient(ipLocalEndPoint);
}
catch (Exception e ) {
Console.WriteLine(e.ToString());
}

  到這里,你可能會(huì)感到困惑,客戶端要和服務(wù)端創(chuàng)建連接,所指定的IP地址及通信端口號(hào)應(yīng)該是遠(yuǎn)程服務(wù)器的呀!事實(shí)上的確如此,使用以上兩種構(gòu)造函數(shù),你所實(shí)現(xiàn)的只是TcpClient實(shí)例對(duì)象與IP地址和Port端口的綁定,要完成連接,你還需要顯式指定與遠(yuǎn)程主機(jī)的連接,這可以通過TcpClient類的Connect方法來實(shí)現(xiàn), Connet方法使用指定的主機(jī)名和端口號(hào)將客戶端連接到 遠(yuǎn)程主機(jī):

  1)、public void Connect(IPEndPoint); 使用指定的遠(yuǎn)程網(wǎng)絡(luò)終結(jié)點(diǎn)將客戶端連接到遠(yuǎn)程 TCP 主機(jī)。

public void Connect(IPAddress, int); 使用指定的 IP 地址和端口號(hào)將客戶端連接到 TCP 主機(jī)。

public void Connect(string, int); 將客戶端連接到指定主機(jī)上的指定端口。

  需要指出的是,Connect方法的所有重載形式中的參數(shù)IPEndPoint網(wǎng)絡(luò)終結(jié)點(diǎn)、IPAddress以及表現(xiàn)為string的Dns主機(jī)名和int指出的Port端口均指的是遠(yuǎn)程服務(wù)器。

  以下示例語(yǔ)句使用主機(jī)默認(rèn)IP和Port端口號(hào)0與遠(yuǎn)程主機(jī)建立連接:

TcpClient tcpClient = new TcpClient();//創(chuàng)建TcpClient對(duì)象實(shí)例
try{
tcpClient.Connect("www.contoso.com",11002);//建立連接
}
catch (Exception e ){
Console.WriteLine(e.ToString());
}

3、public TcpClient(string, int);初始化 TcpClient 類的新實(shí)例并連接到指定主機(jī)上的指定端口。與前兩個(gè)構(gòu)造函數(shù)不一樣,這個(gè)構(gòu)造函數(shù)將自動(dòng)建立連接,你不再需要額外調(diào)用Connect方法,其中 string類型的參數(shù)表示遠(yuǎn)程主機(jī)的Dns名,如:www.tuha.net。

  以下示例語(yǔ)句調(diào)用這一方法實(shí)現(xiàn)與指定主機(jī)名和端口號(hào)的主機(jī)相連:

try{
TcpClient tcpClientB = new TcpClient("www.tuha.net", 4088);
}
catch (Exception e ) {
Console.WriteLine(e.ToString());
}

  前面我們說,TcpClient類創(chuàng)建在Socket之上,在Tcp服務(wù)方面提供了更高層次的抽象,體現(xiàn)在網(wǎng)絡(luò)數(shù)據(jù)的發(fā)送和接受方面,是TcpClient使用標(biāo)準(zhǔn)的Stream流處理技術(shù),使得它讀寫數(shù)據(jù)更加方便直觀,同時(shí),.Net框架負(fù)責(zé)提供更豐富的結(jié)構(gòu)來處理流,貫穿于整個(gè).Net框架中的流具有更廣泛的兼容性,構(gòu)建在更一般化的流操作上的通用方法使我們不再需要困惑于文件的實(shí)際內(nèi)容(HTML、XML 或其他任何內(nèi)容),應(yīng)用程序都將使用一致的方法(Stream.Write、Stream.Read) 發(fā)送和接收數(shù)據(jù)。另外,流在數(shù)據(jù)從 Internet 下載的過程中提供對(duì)數(shù)據(jù)的即時(shí)訪問,可以在部分?jǐn)?shù)據(jù)到達(dá)時(shí)立即開始處理,而不需要等待應(yīng)用程序下載完整個(gè)數(shù)據(jù)集。.Net中通過 NetworkStream類實(shí)現(xiàn)了這些處理技術(shù)。

  NetworkStream 類包含在.Net框架的System.Net.Sockets 命名空間里,該類專門提供用于網(wǎng)絡(luò)訪問的基礎(chǔ)數(shù)據(jù)流。NetworkStream 實(shí)現(xiàn)通過網(wǎng)絡(luò)套接字發(fā)送和接收數(shù)據(jù)的標(biāo)準(zhǔn).Net 框架流機(jī)制。NetworkStream 支持對(duì)網(wǎng)絡(luò)數(shù)據(jù)流的同步和異步訪問。NetworkStream 從 Stream 繼承,后者提供了一組豐富的用于方便網(wǎng)絡(luò)通訊的方法和屬性。

  同其它繼承自抽象基類Stream的所有流一樣,NetworkStream網(wǎng)絡(luò)流也可以被視為一個(gè)數(shù)據(jù)通道,架設(shè)在數(shù)據(jù)來源端(客戶Client)和接收端(服務(wù)Server)之間,而后的數(shù)據(jù)讀取及寫入均針對(duì)這個(gè)通道來進(jìn)行。

  .Net框架中,NetworkStream流支持兩方面的操作:

  1、 寫入流。寫入是從數(shù)據(jù)結(jié)構(gòu)到流的數(shù)據(jù)傳輸。

  2、讀取流。讀取是從流到數(shù)據(jù)結(jié)構(gòu)(如字節(jié)數(shù)組)的數(shù)據(jù)傳輸。

  與普通流Stream不同的是,網(wǎng)絡(luò)流沒有當(dāng)前位置的統(tǒng)一概念,因此不支持查找和對(duì)數(shù)據(jù)流的隨機(jī)訪問。相應(yīng)屬性CanSeek 始終返回 false,而 Seek 和 Position 方法也將引發(fā) NotSupportedException。

  基于Socket上的應(yīng)用協(xié)議方面,你可以通過以下兩種方式獲取NetworkStream網(wǎng)絡(luò)數(shù)據(jù)流:

  1、使用NetworkStream構(gòu)造函數(shù):public NetworkStream(Socket, FileAccess, bool);(有重載方法),它用指定的訪問權(quán)限和指定的 Socket 所屬權(quán)為指定的 Socket 創(chuàng)建 NetworkStream 類的新實(shí)例,使用前你需要?jiǎng)?chuàng)建Socket對(duì)象實(shí)例,并通過Socket.Connect方法建立與遠(yuǎn)程服務(wù)端的連接,而后才可以使用該方法得到網(wǎng)絡(luò)傳輸流。示例如下:

Socket s=new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);//創(chuàng)建客戶端Socket對(duì)象實(shí)例
try{
s.Connect("www.tuha.net",4088);//建立與遠(yuǎn)程主機(jī)的連接
}
catch(Exception e){
MessageBox.show("連接錯(cuò)誤:" +e.Message);
}
try{
NetworkStream stream=new NetworkStream(s,FileAccess.ReadWrite,false);//取得網(wǎng)絡(luò)傳輸流
}

  2、通過TcpClient.GetStream方法:public NetworkStream etStream();它返回用于發(fā)送和接收數(shù)據(jù)的基礎(chǔ)網(wǎng)絡(luò)流NetworkStream。GetStream 通過將基礎(chǔ) Socket 用作它的構(gòu)造函數(shù)參數(shù)來創(chuàng)建 NetworkStream 類的實(shí)例。使用前你需要先創(chuàng)TcpClient對(duì)象實(shí)例并建立與遠(yuǎn)程主機(jī)的連接,示例如下:

TcpClient tcpClient = new TcpClient();//創(chuàng)建TcpClient對(duì)象實(shí)例
Try{
tcpClient.Connect("www.tuha.net",4088);//嘗試與遠(yuǎn)程主機(jī)相連
}
catch(Exception e){
MessageBox.Show("連接錯(cuò)誤:"+e.Message);
}
try{
NetworkStream stream=tcpClient.GetStream();//獲取網(wǎng)絡(luò)傳輸流
}
catch(Exception e)
{
MessageBox.Show("TcpClient錯(cuò)誤:"+e.Message);
}

  通過以上方法得到NetworkStream網(wǎng)絡(luò)流之后,你就可以使用標(biāo)準(zhǔn)流讀寫方法Write和Read來發(fā)送和接受數(shù)據(jù)了。

  以上是.Net下使用TcpClient類實(shí)現(xiàn)客戶端編程的技術(shù)資料,為了向客戶端提供這些服務(wù),我們還需要編制相應(yīng)的服務(wù)端程序,前一篇《Visual C#.Net網(wǎng)絡(luò)程序開發(fā)-Socket篇》上曾經(jīng)提到, Socket作為其他網(wǎng)絡(luò)協(xié)議的基礎(chǔ),既可以面向客戶端開發(fā),也可以面向服務(wù)端開發(fā),在傳輸層面上使用較多,而在應(yīng)用協(xié)議層面上,客戶端我們采用構(gòu)建于 Socket類之上的TcpClient取代Socket;相應(yīng)地,構(gòu)建于Socket之上的TcpListener提供了更高理念級(jí)別的 TCP 服務(wù),使得我們能更方便地編寫服務(wù)端應(yīng)用程序。正是因?yàn)檫@樣的原因,像FTP 和 HTTP 這樣的應(yīng)用層協(xié)議都是在 TcpListener 類的基礎(chǔ)上建立的。

  .Net中的TCPListener 用于監(jiān)視TCP 端口上的傳入請(qǐng)求,通過綁定本機(jī)IP地址和相應(yīng)端口(這兩者應(yīng)與客戶端的請(qǐng)求一致)創(chuàng)建TcpListener對(duì)象實(shí)例,并由Start方法啟動(dòng)偵聽;當(dāng) TcpListener偵聽到用戶端的連接后,視客戶端的不同請(qǐng)求方式,通過AcceptTcpClient 方法接受傳入的連接請(qǐng)求并創(chuàng)建 TcpClient 以處理請(qǐng)求,或者通過AcceptSocket 方法接受傳入的連接請(qǐng)求并創(chuàng)建 Socket 以處理請(qǐng)求。最后,你需要使用 Stop 關(guān)閉用于偵聽傳入連接的 Socket,你必須也關(guān)閉從 AcceptSocket 或 AcceptTcpClient 返回的任何實(shí)例。這個(gè)過程詳細(xì)解說如下:

  首先,創(chuàng)建TcpListener對(duì)象實(shí)例,這通過TcpListener類的構(gòu)造方法來實(shí)現(xiàn):

public TcpListener(port);//指定本機(jī)端口
public TcpListener(IPEndPoint)//指定本機(jī)終結(jié)點(diǎn)
public TcpListener(IPAddress,port)//指定本機(jī)IP地址及端口

  以上方法中的參數(shù)在前面多次提到,這里不再細(xì)述,唯一需要提醒的是,這些參數(shù)均針對(duì)服務(wù)端主機(jī)。下面的示例演示創(chuàng)建 TcpListener 類的實(shí)例:

IPHostEntry ipInfo=Dns.Resolve("127.0.0.1");//主機(jī)信息
IPAddressList[] ipList=ipInfo.IPAddressList;//IP數(shù)組
IPAddress ip=ipList[0];//IP
try{
TcpListener tcpListener = new TcpListener(ipAddress, 4088);//創(chuàng)建TcpListener對(duì)象實(shí)例以偵聽用戶端連接
}
catch ( Exception e){
MessageBox.Show("TcpListener錯(cuò)誤:"+e.Message);
}

  隨后,你需要調(diào)用Start方法啟動(dòng)偵聽:

public void Start();

  其次,當(dāng)偵聽到有用戶端連接時(shí),需要接受掛起的連接請(qǐng)求,這通過調(diào)用以下兩方法之一來完成連接:

public Socket AcceptSocket();
public TcpClient AcceptTcpClient();

  前一個(gè)方法返回代表客戶端的Socket對(duì)象,隨后可以通過Socket 類的 Send 和 Receive 方法與遠(yuǎn)程計(jì)算機(jī)通訊;后一個(gè)方法返回代表客戶端的TcpClient對(duì)象,隨后使用上面介紹的 TcpClient.GetStream 方法獲取 TcpClient 的基礎(chǔ)網(wǎng)絡(luò)流 NetworkStream,并使用流讀寫Read/Write方法與遠(yuǎn)程計(jì)算機(jī)通訊。

  最后,請(qǐng)記住關(guān)閉偵聽器:public void Stop();

  同時(shí)關(guān)閉其他連接實(shí)例:public void Close();

下面的示例完整體現(xiàn)了上面的過程:

bool done = false;
TcpListener listener = new TcpListener(13);// 創(chuàng)建TcpListener對(duì)象實(shí)例(13號(hào)端口提供時(shí)間服務(wù))
listener.Start();//啟動(dòng)偵聽
while (!done) {//進(jìn)入無限循環(huán)以偵聽用戶連接
TcpClient client = listener.AcceptTcpClient();//偵聽到連接后創(chuàng)建客戶端連接TcpClient
NetworkStream ns = client.GetStream();//得到網(wǎng)絡(luò)傳輸流
byte[] byteTime = Encoding.ASCII.GetBytes(DateTime.Now.ToString());//預(yù)發(fā)送的內(nèi)容(此為服務(wù)端時(shí)間)轉(zhuǎn)換為字節(jié)數(shù)組以便寫入流
try {
ns.Write(byteTime, 0, byteTime.Length);//寫入流
ns.Close();//關(guān)閉流
client.Close();//關(guān)閉客戶端連接
}
catch (Exception e) {
MessageBox.Show("流錯(cuò)誤:"+e.Message)
}

  綜合運(yùn)用上面的知識(shí),下面的實(shí)例實(shí)現(xiàn)了簡(jiǎn)單的網(wǎng)絡(luò)通訊-雙機(jī)互連,針對(duì)客戶端和服務(wù)端分別編制了應(yīng)用程序。客戶端創(chuàng)建到服務(wù)端的連接,向遠(yuǎn)程主機(jī)發(fā)送連接請(qǐng)求連接信號(hào),并發(fā)送交談內(nèi)容;遠(yuǎn)程主機(jī)端接收來自客戶的連接,向客戶端發(fā)回確認(rèn)連接的信號(hào),同時(shí)接收并顯示客戶端的交談內(nèi)容。在這個(gè)基礎(chǔ)上,發(fā)揮你的創(chuàng)造力,你完全可以開發(fā)出一個(gè)基于程序語(yǔ)言(C#)級(jí)的聊天室!

  客戶端主要源代碼:

public void SendMeg()//發(fā)送信息
{
try
{


int port=Int32.Parse(textBox3.Text.ToString());//遠(yuǎn)程主機(jī)端口
try
{
tcpClient=new TcpClient(textBox1.Text,port);//創(chuàng)建TcpClient對(duì)象實(shí)例 }
catch(Exception le)
{
MessageBox.Show("TcpClient Error:"+le.Message);
}
string strDateLine=DateTime.Now.ToShortDateString()+" "+DateTime.Now.ToLongTimeString();//得到發(fā)送時(shí)客戶端時(shí)間
netStream=tcpClient.GetStream();//得到網(wǎng)絡(luò)流
sw=new StreamWriter(netStream);//創(chuàng)建TextWriter,向流中寫字符
string words=textBox4.Text;//待發(fā)送的話
string content=strDateLine+words;//待發(fā)送內(nèi)容
sw.Write(content);//寫入流
sw.Close();//關(guān)閉流寫入器
netStream.Close();//關(guān)閉網(wǎng)絡(luò)流
tcpClient.Close();//關(guān)閉客戶端連接
}
catch(Exception ex)
{
MessageBox.Show("Sending Message Failed!"+ex.Message);
}
textBox4.Text="";//清空
}

  服務(wù)器端主要源代碼:

public void StartListen()//偵聽特定端口的用戶請(qǐng)求
{
//ReceiveMeg();
isLinked=false; //連接標(biāo)志
try
{
int port=Int32.Parse(textBox1.Text.ToString());//本地待偵聽端口
serverListener=new TcpListener(port);//創(chuàng)建TcpListener對(duì)象實(shí)例
serverListener.Start(); //啟動(dòng)偵聽
}
catch(Exception ex)
{
MessageBox.Show("Can‘t Start Server"+ex.Message);
return;
}
isLinked=true;
while(true)//進(jìn)入無限循環(huán)等待用戶端連接
{
try
{
tcpClient=serverListener.AcceptTcpClient();//創(chuàng)建客戶端連接對(duì)象
netStream=tcpClient.GetStream();//得到網(wǎng)絡(luò)流
sr=new StreamReader(netStream);//流讀寫器
}
catch(Exception re)
{
MessageBox.Show(re.Message);
}
string buffer="";
string received="";
received+=sr.ReadLine();//讀流中一行
while(received.Length!=0)
{
buffer+=received;
buffer+="\r\n";
//received="";
received=sr.ReadLine();
}
listBox1.Items.Add(buffer);//顯示
//關(guān)閉
sr.Close();
netStream.Close();
tcpClient.Close();
}
}

2005-8-25 20:11:56
倒飛
等級(jí):
文章:
積分:
門派:無門無派
注冊(cè):
4
 

Visual C#.Net網(wǎng)絡(luò)程序開發(fā)-Tcp篇(2)
作者: 宋華 www.ASPCool.com 時(shí)間:2002-5-5 下午 05:36:39 閱讀次數(shù):7053


前面我們說,TcpClient類創(chuàng)建在Socket之上,在Tcp服務(wù)方面提供了更高層次的抽象,體現(xiàn)在網(wǎng)絡(luò)數(shù)據(jù)的發(fā)送和接受方面,是 TcpClient使用標(biāo)準(zhǔn)的Stream流處理技術(shù),使得它讀寫數(shù)據(jù)更加方便直觀,同時(shí),.Net框架負(fù)責(zé)提供更豐富的結(jié)構(gòu)來處理流,貫穿于整個(gè). Net框架中的流具有更廣泛的兼容性,構(gòu)建在更一般化的流操作上的通用方法使我們不再需要困惑于文件的實(shí)際內(nèi)容(HTML、XML 或其他任何內(nèi)容),應(yīng)用程序都將使用一致的方法(Stream.Write、Stream.Read) 發(fā)送和接收數(shù)據(jù)。另外,流在數(shù)據(jù)從 Internet 下載的過程中提供對(duì)數(shù)據(jù)的即時(shí)訪問,可以在部分?jǐn)?shù)據(jù)到達(dá)時(shí)立即開始處理,而不需要等待應(yīng)用程序下載完整個(gè)數(shù)據(jù)集。.Net中通過 NetworkStream類實(shí)現(xiàn)了這些處理技術(shù)。

NetworkStream 類包含在.Net框架的System.Net.Sockets 命名空間里,該類專門提供用于網(wǎng)絡(luò)訪問的基礎(chǔ)數(shù)據(jù)流。NetworkStream 實(shí)現(xiàn)通過網(wǎng)絡(luò)套接字發(fā)送和接收數(shù)據(jù)的標(biāo)準(zhǔn).Net 框架流機(jī)制。NetworkStream 支持對(duì)網(wǎng)絡(luò)數(shù)據(jù)流的同步和異步訪問。NetworkStream 從 Stream 繼承,后者提供了一組豐富的用于方便網(wǎng)絡(luò)通訊的方法和屬性。

同其它繼承自抽象基類Stream的所有流一樣,NetworkStream網(wǎng)絡(luò)流也可以被視為一個(gè)數(shù)據(jù)通道,架設(shè)在數(shù)據(jù)來源端(客戶Client)和接收端(服務(wù)Server)之間,而后的數(shù)據(jù)讀取及寫入均針對(duì)這個(gè)通道來進(jìn)行。

.Net框架中,NetworkStream流支持兩方面的操作:

1、 寫入流。寫入是從數(shù)據(jù)結(jié)構(gòu)到流的數(shù)據(jù)傳輸。

示 意 圖


2、讀取流。讀取是從流到數(shù)據(jù)結(jié)構(gòu)(如字節(jié)數(shù)組)的數(shù)據(jù)傳輸。

示 意 圖

與普通流Stream不同的是,網(wǎng)絡(luò)流沒有當(dāng)前位置的統(tǒng)一概念,因此不支持查找和對(duì)數(shù)據(jù)流的隨機(jī)訪問。相應(yīng)屬性CanSeek 始終返回 false,而 Seek 和 Position 方法也將引發(fā) NotSupportedException。

基于Socket上的應(yīng)用協(xié)議方面,你可以通過以下兩種方式獲取NetworkStream網(wǎng)絡(luò)數(shù)據(jù)流:

1、使用NetworkStream構(gòu)造函數(shù):public NetworkStream(Socket, FileAccess, bool);(有重載方法),它用指定的訪問權(quán)限和指定的 Socket 所屬權(quán)為指定的 Socket 創(chuàng)建 NetworkStream 類的新實(shí)例,使用前你需要?jiǎng)?chuàng)建Socket對(duì)象實(shí)例,并通過Socket.Connect方法建立與遠(yuǎn)程服務(wù)端的連接,而后才可以使用該方法得到網(wǎng)絡(luò)傳輸流。示例如下:

Socket s=new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);//創(chuàng)建客戶端Socket對(duì)象實(shí)例
try{
s.Connect("www.tuha.net",4088);//建立與遠(yuǎn)程主機(jī)的連接
}
catch(Exception e){
MessageBox.show("連接錯(cuò)誤:" +e.Message);
}
try{
NetworkStream stream=new NetworkStream(s,FileAccess.ReadWrite,false);//取得網(wǎng)絡(luò)傳輸流
}


2、通過TcpClient.GetStream方法:public NetworkStream etStream();它返回用于發(fā)送和接收數(shù)據(jù)的基礎(chǔ)網(wǎng)絡(luò)流NetworkStream。GetStream 通過將基礎(chǔ) Socket 用作它的構(gòu)造函數(shù)參數(shù)來創(chuàng)建 NetworkStream 類的實(shí)例。使用前你需要先創(chuàng)TcpClient對(duì)象實(shí)例并建立與遠(yuǎn)程主機(jī)的連接,示例如下:

TcpClient tcpClient = new TcpClient();//創(chuàng)建TcpClient對(duì)象實(shí)例
Try{
tcpClient.Connect("www.tuha.net",4088);//嘗試與遠(yuǎn)程主機(jī)相連
}
catch(Exception e){
MessageBox.Show("連接錯(cuò)誤:"+e.Message);
}
try{
NetworkStream stream=tcpClient.GetStream();//獲取網(wǎng)絡(luò)傳輸流
}
catch(Exception e)
{
MessageBox.Show("TcpClient錯(cuò)誤:"+e.Message);
}


通過以上方法得到NetworkStream網(wǎng)絡(luò)流之后,你就可以使用標(biāo)準(zhǔn)流讀寫方法Write和Read來發(fā)送和接受數(shù)據(jù)了。

以上是.Net下使用TcpClient類實(shí)現(xiàn)客戶端編程的技術(shù)資料,為了向客戶端提供這些服務(wù),我們還需要編制相應(yīng)的服務(wù)端程序,前一篇《Visual C#.Net網(wǎng)絡(luò)程序開發(fā)-Socket篇》上曾經(jīng)提到, Socket作為其他網(wǎng)絡(luò)協(xié)議的基礎(chǔ),既可以面向客戶端開發(fā),也可以面向服務(wù)端開發(fā),在傳輸層面上使用較多,而在應(yīng)用協(xié)議層面上,客戶端我們采用構(gòu)建于 Socket類之上的TcpClient取代Socket;相應(yīng)地,構(gòu)建于Socket之上的TcpListener提供了更高理念級(jí)別的 TCP 服務(wù),使得我們能更方便地編寫服務(wù)端應(yīng)用程序。正是因?yàn)檫@樣的原因,像FTP 和 HTTP 這樣的應(yīng)用層協(xié)議都是在 TcpListener 類的基礎(chǔ)上建立的。

.Net中的TCPListener 用于監(jiān)視TCP 端口上的傳入請(qǐng)求,通過綁定本機(jī)IP地址和相應(yīng)端口(這兩者應(yīng)與客戶端的請(qǐng)求一致)創(chuàng)建TcpListener對(duì)象實(shí)例,并由Start方法啟動(dòng)偵聽;當(dāng) TcpListener偵聽到用戶端的連接后,視客戶端的不同請(qǐng)求方式,通過AcceptTcpClient 方法接受傳入的連接請(qǐng)求并創(chuàng)建 TcpClient 以處理請(qǐng)求,或者通過AcceptSocket 方法接受傳入的連接請(qǐng)求并創(chuàng)建 Socket 以處理請(qǐng)求。最后,你需要使用 Stop 關(guān)閉用于偵聽傳入連接的 Socket,你必須也關(guān)閉從 AcceptSocket 或 AcceptTcpClient 返回的任何實(shí)例。這個(gè)過程詳細(xì)解說如下:

首先,創(chuàng)建TcpListener對(duì)象實(shí)例,這通過TcpListener類的構(gòu)造方法來實(shí)現(xiàn):

public TcpListener(port);//指定本機(jī)端口
public TcpListener(IPEndPoint)//指定本機(jī)終結(jié)點(diǎn)
public TcpListener(IPAddress,port)//指定本機(jī)IP地址及端口


以上方法中的參數(shù)在前面多次提到,這里不再細(xì)述,唯一需要提醒的是,這些參數(shù)均針對(duì)服務(wù)端主機(jī)。下面的示例演示創(chuàng)建 TcpListener 類的實(shí)例:

IPHostEntry ipInfo=Dns.Resolve("127.0.0.1");//主機(jī)信息
IPAddressList[] ipList=ipInfo.IPAddressList;//IP數(shù)組
IPAddress ip=ipList[0];//IP
try{
TcpListener tcpListener = new TcpListener(ipAddress, 4088);//創(chuàng)建TcpListener對(duì)象實(shí)例以偵聽用戶端連接
}
catch ( Exception e){
MessageBox.Show("TcpListener錯(cuò)誤:"+e.Message);
}


隨后,你需要調(diào)用Start方法啟動(dòng)偵聽:

public void Start();


其次,當(dāng)偵聽到有用戶端連接時(shí),需要接受掛起的連接請(qǐng)求,這通過調(diào)用以下兩方法之一來完成連接:

public Socket AcceptSocket();
public TcpClient AcceptTcpClient();


前一個(gè)方法返回代表客戶端的Socket對(duì)象,隨后可以通過Socket 類的 Send 和 Receive 方法與遠(yuǎn)程計(jì)算機(jī)通訊;后一個(gè)方法返回代表客戶端的TcpClient對(duì)象,隨后使用上面介紹的 TcpClient.GetStream 方法獲取 TcpClient 的基礎(chǔ)網(wǎng)絡(luò)流 NetworkStream,并使用流讀寫Read/Write方法與遠(yuǎn)程計(jì)算機(jī)通訊。

最后,請(qǐng)記住關(guān)閉偵聽器:public void Stop();

同時(shí)關(guān)閉其他連接實(shí)例:public void Close();

下面的示例完整體現(xiàn)了上面的過程:

bool done = false;
TcpListener listener = new TcpListener(13);// 創(chuàng)建TcpListener對(duì)象實(shí)例(13號(hào)端口提供時(shí)間服務(wù))
listener.Start();//啟動(dòng)偵聽
while (!done) {//進(jìn)入無限循環(huán)以偵聽用戶連接
TcpClient client = listener.AcceptTcpClient();//偵聽到連接后創(chuàng)建客戶端連接TcpClient
NetworkStream ns = client.GetStream();//得到網(wǎng)絡(luò)傳輸流
byte[] byteTime = Encoding.ASCII.GetBytes(DateTime.Now.ToString());//預(yù)發(fā)送的內(nèi)容(此為服務(wù)端時(shí)間)轉(zhuǎn)換為字節(jié)數(shù)組以便寫入流
try {
ns.Write(byteTime, 0, byteTime.Length);//寫入流
ns.Close();//關(guān)閉流
client.Close();//關(guān)閉客戶端連接
}
catch (Exception e) {
MessageBox.Show("流錯(cuò)誤:"+e.Message)
}

[此貼子已經(jīng)被作者于2005-8-25 20:21:22編輯過]
2005-8-25 20:20:06
倒飛
等級(jí):
文章:
積分:
門派:無門無派
注冊(cè):
5
 

Visual C#.Net網(wǎng)絡(luò)程序開發(fā)-Tcp篇(3)

我們知道C#和C++的差異之一,就是他本身沒有類庫(kù),所使用的類庫(kù)是.Net框架中的類庫(kù)--.Net FrameWork SDK。在.Net FrameWork SDK中為網(wǎng)絡(luò)編程提供了二個(gè)名稱空間:"System.Net"和"System.Net.Sockets"。C#就是通過這二個(gè)名稱空間中封裝的類和方法實(shí)現(xiàn)網(wǎng)絡(luò)通訊的。

  首先我們解釋一下在網(wǎng)絡(luò)編程時(shí)候,經(jīng)常遇到的幾個(gè)概念:同步(synchronous)、異步(asynchronous)、阻塞(Block)和非阻塞(Unblock):

  所謂同步方式,就是發(fā)送方發(fā)送數(shù)據(jù)包以后,不等接受方響應(yīng),就接著發(fā)送下一個(gè)數(shù)據(jù)包。異步方式就是當(dāng)發(fā)送方發(fā)送一個(gè)數(shù)據(jù)包以后,一直等到接受方響應(yīng)后,才接著發(fā)送下一個(gè)數(shù)據(jù)包。而阻塞套接字是指執(zhí)行此套接字的網(wǎng)絡(luò)調(diào)用時(shí),直到調(diào)用成功才返回,否則此套節(jié)字就一直阻塞在網(wǎng)絡(luò)調(diào)用上,比如調(diào)用 StreamReader 類的Readlin ( )方法讀取網(wǎng)絡(luò)緩沖區(qū)中的數(shù)據(jù),如果調(diào)用的時(shí)候沒有數(shù)據(jù)到達(dá),那么此Readlin ( )方法將一直掛在調(diào)用上,直到讀到一些數(shù)據(jù),此函數(shù)調(diào)用才返回;而非阻塞套接字是指在執(zhí)行此套接字的網(wǎng)絡(luò)調(diào)用時(shí),不管是否執(zhí)行成功,都立即返回。同樣調(diào)用 StreamReader 類的Readlin ( )方法讀取網(wǎng)絡(luò)緩沖區(qū)中數(shù)據(jù),不管是否讀到數(shù)據(jù)都立即返回,而不會(huì)一直掛在此函數(shù)調(diào)用上。在Windows網(wǎng)絡(luò)通信軟件開發(fā)中,最為常用的方法就是異步非阻塞套接字。平常所說的C/S(客戶端/服務(wù)器)結(jié)構(gòu)的軟件采用的方式就是異步非阻塞模式的。

  其實(shí)在用C#進(jìn)行網(wǎng)絡(luò)編程中,我們并不需要了解什么同步、異步、阻塞和非阻塞的原理和工作機(jī)制,因?yàn)樵?Net FrameWrok SDK中已經(jīng)已經(jīng)把這些機(jī)制給封裝好了。下面我們就用C#開一個(gè)具體的網(wǎng)絡(luò)程序來說明一下問題。

  一.本文中介紹的程序設(shè)計(jì)及運(yùn)行環(huán)境

  ?。?).微軟視窗2000 服務(wù)器版

   (2)..Net Framework SDK Beta 2以上版本

  二.服務(wù)器端程序設(shè)計(jì)的關(guān)鍵步驟以及解決辦法:

  在下面接受的程序中,我們采用的是異步阻塞的方式。

 ?。?).首先要要在給定的端口上面創(chuàng)建一個(gè)"tcpListener"對(duì)象偵聽網(wǎng)絡(luò)上面的請(qǐng)求。當(dāng)接收到連結(jié)請(qǐng)求后通過調(diào)用 "tcpListener"對(duì)象的"AcceptSocket"方法產(chǎn)生一個(gè)用于處理接入連接請(qǐng)求的Socket的實(shí)例。下面是具體實(shí)現(xiàn)代碼:

//創(chuàng)建一個(gè)tcpListener對(duì)象,此對(duì)象主要是對(duì)給定端口進(jìn)行偵聽
tcpListener = new TcpListener ( 1234 ) ;
//開始偵聽
tcpListener.Start ( ) ;
//返回可以用以處理連接的Socket實(shí)例
socketForClient = tcpListener.AcceptSocket ( ) ;

 ?。?).接受和發(fā)送客戶端數(shù)據(jù):

  此時(shí)Socket實(shí)例已經(jīng)產(chǎn)生,如果網(wǎng)絡(luò)上有請(qǐng)求,在請(qǐng)求通過以后,Socket實(shí)例構(gòu)造一個(gè)"NetworkStream"對(duì)象, "NetworkStream"對(duì)象為網(wǎng)絡(luò)訪問提供了基礎(chǔ)數(shù)據(jù)流。我們通過名稱空間"System.IO"中封裝的二個(gè)類"StreamReader"和 "StreamWriter"來實(shí)現(xiàn)對(duì)"NetworkStream"對(duì)象的訪問。其中"StreamReader"類中的ReadLine ( )方法就是從"NetworkStream"對(duì)象中讀取一行字符;"StreamWriter"類中的WriteLine ( )方法就是對(duì)"NetworkStream"對(duì)象中寫入一行字符串。從而實(shí)現(xiàn)在網(wǎng)絡(luò)上面?zhèn)鬏斪址?,下面是具體的實(shí)現(xiàn)代碼:

try
{
//如果返回值是"true",則產(chǎn)生的套節(jié)字已經(jīng)接受來自遠(yuǎn)方的連接請(qǐng)求
if ( socketForClient.Connected )
{
ListBox1.Items.Add ( "已經(jīng)和客戶端成功連接!" ) ;
while ( true )
{
//創(chuàng)建networkStream對(duì)象通過網(wǎng)絡(luò)套節(jié)字來接受和發(fā)送數(shù)據(jù)
networkStream = new NetworkStream ( socketForClient ) ;
//從當(dāng)前數(shù)據(jù)流中讀取一行字符,返回值是字符串
streamReader = new StreamReader ( networkStream ) ;
string msg = streamReader.ReadLine ( ) ;
ListBox1.Items.Add ( "收到客戶端信息:" + msg ) ;
streamWriter = new StreamWriter ( networkStream ) ;
if ( textBox1.Text != "" )
{
ListBox1.Items.Add ( "往客戶端反饋信息:" + textBox1.Text ) ;
//往當(dāng)前的數(shù)據(jù)流中寫入一行字符串
streamWriter.WriteLine ( textBox1.Text ) ;
//刷新當(dāng)前數(shù)據(jù)流中的數(shù)據(jù)
streamWriter.Flush ( ) ;
}
}
}
}
catch ( Exception ey )
{
MessageBox.Show ( ey.ToString ( ) ) ;
}


 ?。?).最后別忘了要關(guān)閉所以流,停止偵聽網(wǎng)絡(luò),關(guān)閉套節(jié)字,具體如下:

//關(guān)閉線程和流
networkStream.Close ( ) ;
streamReader.Close ( ) ;
streamWriter.Close ( ) ;
_thread1.Abort ( ) ;
tcpListener.Stop ( ) ;
socketForClient.Shutdown ( SocketShutdown.Both ) ;
socketForClient.Close ( ) ; 
本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊舉報(bào)。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
你也可以寫個(gè)聊天程序
C# .net2.0 套接字編程實(shí)例 UDP TCP通信
C#TCPClient應(yīng)用-一個(gè)簡(jiǎn)單的消息發(fā)送和接收 (轉(zhuǎn)) - PlayMan0211 ...
C# 實(shí)現(xiàn)基本的套接字TCP通信
C#網(wǎng)絡(luò)編程(基本概念和操作) - Part.1 - C# 編程 - TraceFact....
以異步的方式操作TCP/IP套接字
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長(zhǎng)圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服