C Socket網路程式設計學習 4 6

2021-08-26 14:23:08 字數 4887 閱讀 6103

c# socket網路程式設計學習(4-->6)

2023年05月03日

[b]c# socket[/b][b]網路程式設計學習[/b][b](4) - tcp[/b][b]訊息邊界處理[/b][b] [/b]

在前面的幾篇中,講了關於套接字socket以及利用套接字助手類來進行服務端和客戶端之間的通訊,在此中間並沒有對傳送的資訊進行任何的處理。在本篇中將會講一下tcp通訊時的資訊邊界問題。

通 過套接字或其助手類來接收資訊時,是從快取區里一次性把全部的緣存都讀取出來,只要你設定的快取夠大,它就能讀取這麼多,這樣就會導致這樣的情況出現。如 果服務端連續傳送資訊到客戶端,如我連續傳送字串「message 1」、「message 2」、「message 3」、「message 4」、「message 5」,我預想的是在客戶端也是能夠收到這樣的五個完整的字串,如果用前二篇中講的方法,在同台機子上測試的話,是正常的,因為同台機子上網路資訊傳送出 現的異常會比較少,但如果把客戶端與服務端部署在不同的機器上,則會出現一些異想不到的現象。你會發現接收到的字元都被打亂了,會出現如 「3message 4」的字串,這樣的話,我們就不能把服務端傳送的資訊正常的還原。這個就是訊息的邊界問題,要解決這個問題,方法有很多,現抽取其中幾個來講一下:

1、固定尺寸的訊息

這 是最簡單但也是最昂貴的解決tcp訊息問題的方案。就是要設計一種協議,永遠以固定的長度傳遞訊息,通過將所有的訊息都設定為固定的尺寸,在從遠端裝置中 接收到完整的訊息時,tcp接收程式就能夠了解傳送的情況了。用這各地意味著必須將短訊息加長,造成網路頻寬資源的浪費。

2、使用訊息尺寸資訊

這個方案允許使用可變長度的訊息,惟一的不足就是接收端的遠端設定必須了解每乙個變長訊息的確切長度。具體的方法是,在傳送訊息的時候,一起傳送該訊息的長度。那麼在客戶端接收的時候就能知道該訊息的長度是多少,再來讀取訊息。

3、使用訊息標記

當我們得到socket連線的乙個networkstream物件時,可以通過下面的方法得到streamwriter和streamreader物件。

1networkstream ns = s.getstream();

2 streamreader sr = new streamreader(ns);

3 streamwriter sw = new streamwriter(ns);

這樣我們就可以通過streamwriter來傳送訊息,通過streamreader來接收訊息:

1//傳送訊息

2string welcome = "welcome to my test sever ";

3 4 sw.writeline(welcome);

5 sw.flush();

接收訊息:

1//接收訊息

2string data = "";

3data = sr.readline();

這樣是不是比以前的做法更簡單了,而且同時也解決了tcp訊息邊界問題了。

但是用這各方法必須得注意以下二點:

1、 這種方法其實就是利用訊息標記來解決邊界問題的,這裡的標記就是換行符,也就是說,streamwriter中的writeline()和 streamreader中的readline()一定要成對使用,不然如果傳送的資訊中沒有換行符,則客戶機中用readline()讀取資訊時,將無 法結束,將堵塞程式的執行,一直等待換行符。

2、另外還要保證在傳送的訊息本身不應該帶有換行符,如果訊息本身帶有換行符,則這些換行符將被readline()方法錯誤地作為標記,影響資料的完整性。

[b]c# socket[/b][b]網路程式設計學習[/b][b](5) - [/b][b]傳送和接收實體類資料[/b][b] [/b]

在前面講述的篇幅中,傳送的都是文字資訊,我們只要通過encoding中的幾個方法把文字轉化成二進位制陣列就可以利用socket來傳輸了,這對於一些 基本的資訊傳輸能夠得到滿足,但對於一些複雜的訊息交流,則有些「吃力」。我們有時候會把一些資訊封閉在乙個類中,如果socket能夠傳送類物件,那麼 一些複雜的問題能夠通過物件導向來解決了,即方便又安全。大家都知道,要想在網路上傳輸資訊,必須要經過序列化才行,所以在傳送類物件時,首選必須對該類 物件進行序列化,才能夠在網路上進行傳輸。

序列化類物件有三種序列化方法:

1、xml序列化

2、binary序列化

3、soap序列化

這幾種序列化方法,運用方法相類似,只不過用到的類不一樣。在這裡也不一一講述了,有興趣的朋友可以到網上搜一搜,相信會有不少的收穫。這裡主要講一下利用soap序列化來傳送訊息。

1、首先我們先來建立乙個實體類,用來做訊息的載體類物件

1using system;

2using system.collections.generic;

3using system.text;

45namespace sbwconsole633

34 /**

35 /// 指令型別

36 ///

37 public operatetype operatetype

38 40 set

41 }

42 /**

43 /// 指令資訊

44 ///

45 public operateinfo operateinfo

46 48 set

49 }

50 /**

51 /// asp資料庫連線字串

52 ///

53 public string connstring

54 56 set

57 }

58 /**

59 /// 子伺服器ip

60 ///

61 public string clientip

62 64 set

65 }

66 /**

67 /// asp伺服器ip

68 ///

69 public string serverip

70 72 set

73 }

74 }

7576 /**

77 /// 指令型別

78 ///

79 public enum operatetype

80 94

95 /**

96 /// 指令資訊

97 ///

98 public enum operateinfo

99 117}

1182、傳送前先把類物件進行soap序列化訊息傳送方法

1public static void send(networkstream ns, socketdata sd)

2 這裡利用

iformatter formatter = new soapformatter();

memorystream mem = new memorystream();

formatter.serialize(mem, sd);

對類物件sd進行序列化。在這裡還有乙個細節值得一提,那就是訊息邊界問題的處理,這裡是利用傳送訊息的長度方法來實現。**如下:

1int memsize = (int)mem.length;

2 byte size = bitconverter.getbytes(memsize);

3 ns.write(size, 0, 4);

通過bitconverter.getbytes()方法可以把資料型別轉化為二進位制陣列,從而可以在網路上傳送,所以在接收的時候先接收訊息長度,再通過該長度來迴圈讀取完整的訊息。

3、接收訊息接收訊息方法

1public static socketdata receive(networkstream ns)

2 20

21 iformatter formatter = new soapformatter();

22 mem.position = 0;

23 sd = (socketdata)formatter.deserialize(mem);

24 mem.close();

25 }

26 else

27 30 return sd;

31 }

通過sd = (socketdata)formatter.deserialize(mem);還原資料為類物件,就可以對此類物件進行訪問了。用xml序列化或用二 進製序列化也是類似,只不過把序列化的方法改一下就可以了,一般來說用二進位制序列化得到的資料最小,占用頻寬也最小,而用xml和soap來序列化,都是 序列化為xml格式,所以資料比較大,占用頻寬比較大。但用xml或soap序列化,相容性高,可以相容不同系統之間的通訊,而二進位制不行。可以說各有利 弊,可以根據實際情況來選擇哪一種序列化。

[b]c# socket[/b][b]網路程式設計學習[/b][b](6) - [/b][b]使用執行緒池提高效能[/b][b] [/b]

在前幾篇介紹中,不論是服務端的偵聽還是客戶端的連線都是通過新建乙個執行緒去執行特定功能的。在這種情況下,一量有乙個新客戶端需要連線,則又得建立新的 執行緒,而當程式建立新執行緒時,往往需要大量的內部開銷,這對程式的效能有一定的影響。在.net庫中提供了一種方法,可以避免一些開銷。而在socket 通訊中還有另一種訪求那就是非同步socket,我不知道用這種方式的效能如何,在這裡且不管這種形式,主要來看一下用執行緒池解決問題。

如果要為執行緒池中的執行緒註冊乙個代表,則用下面的格式:

threadpool.queueuserworkitem(new waitcallback(counter));

下面我們來看看怎麼樣運用到我上面講的例子中去:

原有執行緒呼叫:

clientthread = new thread(new threadstart(receivedata));

clientthread.start();

用執行緒池只要一句就可以了:

threadpool.queueuserworkitem(new waitcallback(receivedata));

C Socket 網路程式設計

過程 img 入門級的測試程式 1 客戶端 include include pragma comment lib,ws2 32.lib tcp 客戶端 void main void if lobyte wsadata.wversion 1 hibyte wsadata.wversion 1 載入套接...

CSocket類網路程式設計 MFC

visual c 的mfc提供了csocket類用來實現網路通訊。下面介紹vc 在windows 95中實現socket的 csocket 類相關成員函式 這些成員函式實際上是從casyncsocket 類繼承來的 的使用。1 bool create uint nsocketport 0,int n...

C Socket程式設計

socket基本程式設計 服務端 using system.net using system.net.sockets using system.text using system.threading thread mythread socket socket 清理所有正在使用的資源。protecte...