在網(wǎng)絡(luò)上讀取文件
在C++中,在網(wǎng)絡(luò)上讀取文件需要有相當(dāng)?shù)木幊碳记桑?NET對此提供了廣泛的支持。事實(shí)上,在網(wǎng)絡(luò)上讀取文件僅僅是基礎(chǔ)類庫中Stream類的另一種應(yīng)用。
首先,為了對TCP/IP端口(在本例中是65000)進(jìn)行監(jiān)聽,我們需要創(chuàng)建一個TCPListener類的實(shí)例。
TCPListenertcpListener=newTCPListener(65000);
一旦創(chuàng)建后,就讓它開始進(jìn)行監(jiān)聽。
tcpListener.Start();
現(xiàn)在就要等待客戶連接的要求了。
SocketsocketForClient=tcpListener.Accept();
TCPListener對象的Accept方法返回一個Socket對象,Accept是一個同步的方法,除非接收到一個連接請求它才會返回。如果連接成功,就可以開始向客戶發(fā)送文件了。
if(socketForClient.Connected)
{
???
接下來,我們需要創(chuàng)建一個NetworkStream類,將報(bào)路傳遞給constructor:
NetworkStreamnetworkStream=newNetworkStream(socketForClient);
然后創(chuàng)建一個StreamWriter對象,只是這次不是在文件上而是在剛才創(chuàng)建的NetworkStream類上創(chuàng)建該對象:
System.IO.StreamWriterstreamWriter=
newSystem.IO.StreamWriter(networkStream);
當(dāng)向該流寫內(nèi)容時(shí),流就通過網(wǎng)絡(luò)被傳輸給客戶端。
客戶端的創(chuàng)建
客戶端軟件就是一個TCPClient類的具體例子,TCPClient類代表連向主機(jī)的一個TCP/IP連接。
TCPClientsocketForServer;
socketForServer=newTCPClient("localHost",65000);
有了TCPClient對象后,我們就可以創(chuàng)建NetworkStream對象了,然后在其上創(chuàng)建StreamReader類:
NetworkStreamnetworkStream=socketForServer.GetStream();
System.IO.StreamReaderstreamReader=
newSystem.IO.StreamReader(networkStream);
現(xiàn)在,只要其中有數(shù)據(jù)就讀取該流,并將結(jié)果輸出到控制臺上。
do
{
outputString=streamReader.ReadLine();
if(outputString!=null)
{
Console.WriteLine(outputString);
}
}
while(outputString!=null);
為了對這一段代碼進(jìn)行測試,可以創(chuàng)建如下一個測試用的文件:
Thisislineone
Thisislinetwo
Thisislinethree
Thisislinefour
這是來自服務(wù)器的輸出:
Output(Server)
Clientconnected
SendingThisislineone
SendingThisislinetwo
SendingThisislinethree
SendingThisislinefour
Disconnectingfromclient...
Exiting...下面是來自客戶端的輸出:
Thisislineone
Thisislinetwo
Thisislinethree
Thisislinefour
屬性和元數(shù)據(jù)
C#和C++之間一個顯著的區(qū)別是它提供了對元數(shù)據(jù)的支持:有關(guān)類、對象、方法等其他實(shí)體的數(shù)據(jù)。屬性可以分為二類:一類以CLR的一部分的形式出現(xiàn),另一種是我們自己創(chuàng)建的屬性,CLR屬性用來支持串行化、排列和COM協(xié)同性等。一些屬性是針對一個組合體的,有些屬性則是針對類或界面,它們也被稱作是屬性目標(biāo)。
將屬性放在屬性目標(biāo)前的方括號內(nèi),屬性就可以作用于它們的屬性目標(biāo)。
[assembly:AssemblyDelaySign(false)]
[assembly:AssemblyKeyFile(".\\keyFile.snk")]
或用逗號將各個屬性分開:
[assembly:AssemblyDelaySign(false),
assembly:AssemblyKeyFile(".\\keyFile.snk")]
自定義的屬性
我們可以任意創(chuàng)建自定義屬性,并在認(rèn)為合適的時(shí)候使用它們。假設(shè)我們需要跟蹤bug的修復(fù)情況,就需要建立一個包含bug的數(shù)據(jù)庫,但需要將bug報(bào)告與專門的修正情況綁定在一塊兒,則可能在代碼中添加如下所示的注釋:
//Bug323fixedbyJesseLiberty1/1/2005.
這樣,在源代碼中就可以一目了然地了解bug的修正情況,但如果如果把相關(guān)的資料保存在數(shù)據(jù)庫中可能會更好,這樣就更方便我們的查詢工作了。如果所有的bug報(bào)告都使用相同的語法那就更好了,但這時(shí)我們就需要一個定制的屬性了。我們可能使用下面的內(nèi)容代替代碼中的注釋:
[BugFix(323,"JesseLiberty","1/1/2005")Comment="Offbyoneerror"]
與C#中的其他元素一樣,屬性也是類。定制化的屬性類需要繼承System.Attribute:
publicclassBugFixAttribute:System.Attribute
我們需要讓編譯器知道這個屬性可以跟什么類型的元素,我們可以通過如下的方式來指定該類型的元素:
[AttributeUsage(AttributeTargets.ClassMembers,AllowMultiple=true)]
AttributeUsage是一個作用于屬性的屬性━━元屬性,它提供的是元數(shù)據(jù)的元數(shù)據(jù),也即有關(guān)元數(shù)據(jù)的數(shù)據(jù)。在這種情況下,我們需要傳遞二個參數(shù),第一個是目標(biāo)(在本例中是類成員。),第二個是表示一個給定的元素是否可以接受多于一個屬性的標(biāo)記。AllowMultiple的值被設(shè)置為true,意味著類成員可以有多于一個BugFixAttribute屬性。如果要聯(lián)合二個屬性目標(biāo),可以使用OR操作符連接它們。
[AttributeUsage(AttributeTargets.Class|AttributeTargets.Interface,AllowMultiple=true)]
上面的代碼將使一個屬性隸屬于一個類或一個界面。
新的自定義屬性被命名為BugFixAttribute。命名的規(guī)則是在屬性名之后添加Attribute。在將屬性指派給一個元素后,編譯器允許我們使用精簡的屬性名調(diào)用這一屬性。因此,下面的代碼是合法的:
[BugFix(123,"JesseLiberty","01/01/05",Comment="Offbyone")]
編譯器將首先查找名字為BugFix的屬性,如果沒有發(fā)現(xiàn),則查找BugFixAttribute。
每個屬性必須至少有一個構(gòu)造器。屬性可以接受二種類型的參數(shù):環(huán)境參數(shù)和命名參數(shù)。在前面的例子中,bugID、編程人員的名字和日期是環(huán)境參數(shù),注釋是命名參數(shù)。環(huán)境參數(shù)被傳遞到構(gòu)造器中的,而且必須按在構(gòu)造器中定義的順序傳遞。
publicBugFixAttribute(intbugID,stringprogrammer,stringdate)
{
this.bugID=bugID;
this.programmer=programmer;
this.date=date;
}
Namedparametersareimplementedasproperties.
在C++中,在網(wǎng)絡(luò)上讀取文件需要有相當(dāng)?shù)木幊碳记桑?NET對此提供了廣泛的支持。事實(shí)上,在網(wǎng)絡(luò)上讀取文件僅僅是基礎(chǔ)類庫中Stream類的另一種應(yīng)用。
首先,為了對TCP/IP端口(在本例中是65000)進(jìn)行監(jiān)聽,我們需要創(chuàng)建一個TCPListener類的實(shí)例。
TCPListenertcpListener=newTCPListener(65000);
一旦創(chuàng)建后,就讓它開始進(jìn)行監(jiān)聽。
tcpListener.Start();
現(xiàn)在就要等待客戶連接的要求了。
SocketsocketForClient=tcpListener.Accept();
TCPListener對象的Accept方法返回一個Socket對象,Accept是一個同步的方法,除非接收到一個連接請求它才會返回。如果連接成功,就可以開始向客戶發(fā)送文件了。
if(socketForClient.Connected)
{
???
接下來,我們需要創(chuàng)建一個NetworkStream類,將報(bào)路傳遞給constructor:
NetworkStreamnetworkStream=newNetworkStream(socketForClient);
然后創(chuàng)建一個StreamWriter對象,只是這次不是在文件上而是在剛才創(chuàng)建的NetworkStream類上創(chuàng)建該對象:
System.IO.StreamWriterstreamWriter=
newSystem.IO.StreamWriter(networkStream);
當(dāng)向該流寫內(nèi)容時(shí),流就通過網(wǎng)絡(luò)被傳輸給客戶端。
客戶端的創(chuàng)建
客戶端軟件就是一個TCPClient類的具體例子,TCPClient類代表連向主機(jī)的一個TCP/IP連接。
TCPClientsocketForServer;
socketForServer=newTCPClient("localHost",65000);
有了TCPClient對象后,我們就可以創(chuàng)建NetworkStream對象了,然后在其上創(chuàng)建StreamReader類:
NetworkStreamnetworkStream=socketForServer.GetStream();
System.IO.StreamReaderstreamReader=
newSystem.IO.StreamReader(networkStream);
現(xiàn)在,只要其中有數(shù)據(jù)就讀取該流,并將結(jié)果輸出到控制臺上。
do
{
outputString=streamReader.ReadLine();
if(outputString!=null)
{
Console.WriteLine(outputString);
}
}
while(outputString!=null);
為了對這一段代碼進(jìn)行測試,可以創(chuàng)建如下一個測試用的文件:
Thisislineone
Thisislinetwo
Thisislinethree
Thisislinefour
這是來自服務(wù)器的輸出:
Output(Server)
Clientconnected
SendingThisislineone
SendingThisislinetwo
SendingThisislinethree
SendingThisislinefour
Disconnectingfromclient...
Exiting...下面是來自客戶端的輸出:
Thisislineone
Thisislinetwo
Thisislinethree
Thisislinefour
屬性和元數(shù)據(jù)
C#和C++之間一個顯著的區(qū)別是它提供了對元數(shù)據(jù)的支持:有關(guān)類、對象、方法等其他實(shí)體的數(shù)據(jù)。屬性可以分為二類:一類以CLR的一部分的形式出現(xiàn),另一種是我們自己創(chuàng)建的屬性,CLR屬性用來支持串行化、排列和COM協(xié)同性等。一些屬性是針對一個組合體的,有些屬性則是針對類或界面,它們也被稱作是屬性目標(biāo)。
將屬性放在屬性目標(biāo)前的方括號內(nèi),屬性就可以作用于它們的屬性目標(biāo)。
[assembly:AssemblyDelaySign(false)]
[assembly:AssemblyKeyFile(".\\keyFile.snk")]
或用逗號將各個屬性分開:
[assembly:AssemblyDelaySign(false),
assembly:AssemblyKeyFile(".\\keyFile.snk")]
自定義的屬性
我們可以任意創(chuàng)建自定義屬性,并在認(rèn)為合適的時(shí)候使用它們。假設(shè)我們需要跟蹤bug的修復(fù)情況,就需要建立一個包含bug的數(shù)據(jù)庫,但需要將bug報(bào)告與專門的修正情況綁定在一塊兒,則可能在代碼中添加如下所示的注釋:
//Bug323fixedbyJesseLiberty1/1/2005.
這樣,在源代碼中就可以一目了然地了解bug的修正情況,但如果如果把相關(guān)的資料保存在數(shù)據(jù)庫中可能會更好,這樣就更方便我們的查詢工作了。如果所有的bug報(bào)告都使用相同的語法那就更好了,但這時(shí)我們就需要一個定制的屬性了。我們可能使用下面的內(nèi)容代替代碼中的注釋:
[BugFix(323,"JesseLiberty","1/1/2005")Comment="Offbyoneerror"]
與C#中的其他元素一樣,屬性也是類。定制化的屬性類需要繼承System.Attribute:
publicclassBugFixAttribute:System.Attribute
我們需要讓編譯器知道這個屬性可以跟什么類型的元素,我們可以通過如下的方式來指定該類型的元素:
[AttributeUsage(AttributeTargets.ClassMembers,AllowMultiple=true)]
AttributeUsage是一個作用于屬性的屬性━━元屬性,它提供的是元數(shù)據(jù)的元數(shù)據(jù),也即有關(guān)元數(shù)據(jù)的數(shù)據(jù)。在這種情況下,我們需要傳遞二個參數(shù),第一個是目標(biāo)(在本例中是類成員。),第二個是表示一個給定的元素是否可以接受多于一個屬性的標(biāo)記。AllowMultiple的值被設(shè)置為true,意味著類成員可以有多于一個BugFixAttribute屬性。如果要聯(lián)合二個屬性目標(biāo),可以使用OR操作符連接它們。
[AttributeUsage(AttributeTargets.Class|AttributeTargets.Interface,AllowMultiple=true)]
上面的代碼將使一個屬性隸屬于一個類或一個界面。
新的自定義屬性被命名為BugFixAttribute。命名的規(guī)則是在屬性名之后添加Attribute。在將屬性指派給一個元素后,編譯器允許我們使用精簡的屬性名調(diào)用這一屬性。因此,下面的代碼是合法的:
[BugFix(123,"JesseLiberty","01/01/05",Comment="Offbyone")]
編譯器將首先查找名字為BugFix的屬性,如果沒有發(fā)現(xiàn),則查找BugFixAttribute。
每個屬性必須至少有一個構(gòu)造器。屬性可以接受二種類型的參數(shù):環(huán)境參數(shù)和命名參數(shù)。在前面的例子中,bugID、編程人員的名字和日期是環(huán)境參數(shù),注釋是命名參數(shù)。環(huán)境參數(shù)被傳遞到構(gòu)造器中的,而且必須按在構(gòu)造器中定義的順序傳遞。
publicBugFixAttribute(intbugID,stringprogrammer,stringdate)
{
this.bugID=bugID;
this.programmer=programmer;
this.date=date;
}
Namedparametersareimplementedasproperties.

