年底了,人浮躁多了,沉不下去心研究技術了,不過昨天終於搶到了回家的票,很開心。
言歸正卷,在WCF出來之后,可能我們玩這些原始的TCP越來越少了,我們知道WCF對TCP進行了再一次的包裝,第一反應給我們的或許是
同構系統用TCP,異構系統用HTTP,那么問題來了,異構系統到底可不可以用TCP呢?至少WCF是玩不了的,因為其他語言沒有針對.net的“服務
引用”,也沒有什么ChannelFactory給你去玩,如果你是一定要追求性能的話,原始的TCP會助你一臂之力的。
我們知道最最原始的是玩Socket,由於Socket比較復雜,但是最靈活,C#里面提供了兩個簡化的包裝類:TcpListener和TcpClient。
一:TcpListener
這個是作為服務器端程序而存在的,我們來看看如何使用這服務端。
1: 開啟監聽地址
1 TcpListener listener = new TcpListener(new System.Net.IPAddress(new byte[] { 127, 0, 0, 1 }), 2222); 2 3 listener.Start();
2:好了,已經開啟了,服務端程序開始監聽該端口的客戶端請求了,那么如何獲取該請求呢?簡單,listener的AcceptTcpClient屬性搞定。
1 var myclient = listener.AcceptTcpClient();
3:我們知道TCP傳的是字節流,通過myclient.GetStream()就可以獲取一個NetworkStream,利用這個Stream就可以進行收發信息了。
<1> 收操作:
1 BinaryReader sr = new BinaryReader(client.GetStream()); 2 3 //客戶端數據 4 var data = sr.ReadString();
<2>發操作:也就是所謂的返回值
1 //處理完了之后要返回數據給客戶端 2 BinaryWriter sw = new BinaryWriter(client.GetStream()); 3 4 sw.Write(string.Format("當前時間:{0},服務端已經處理完畢!", DateTime.Now));
這里要注意的地方就是AcceptTcpClient是阻塞線程的,直到收到客戶端請求才算建立了一個TCP連接,在服務端處理的過程中,后續的客戶端的請求將
會處理等待直到前一個請求處理完,說了這么多,就是每一個請求我們都建議開一個線程專門為其服務,類似這樣。
1 //接受客戶端的連接請求 2 var myclient = listener.AcceptTcpClient(); 3 4 //用工作線程執行用戶的請求 5 Task.Factory.StartNew((obj) => 6 { 7 var client = obj as TcpClient; 8 9 client.Close(); 10 11 }, myclient);
好了,服務器端大概就是這個樣子,再有的就是一些相關屬性配置了,像wcf那樣什么opentime,sendtime啥的。
二:TcpClient
客戶端也很簡單,只要我們Connect一下端口,然后通過NetworkStream再Send一些數據就OK了。
1 TcpClient client = new TcpClient(); 2 3 client.Connect(new System.Net.IPAddress(new byte[] { 127, 0, 0, 1 }), 2222); 4 5 BinaryWriter bw = new BinaryWriter(client.GetStream()); 6 7 bw.Write(string.Format("你好,我來請求你! {0},當前線程:{1}", j, Thread.CurrentThread.ManagedThreadId));
三:模擬
最后我們模擬下,客戶端開啟100個線程,每個線程請求100次,服務器端對每個線程都用工作線程去處理,是不是找到了netTcpBinding的
感覺,最后一個大家都懂的道理就是線程多了不是好事情。
服務端:

1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Net.Sockets; 6 using System.IO; 7 using System.Threading.Tasks; 8 using System.Threading; 9 using System.Net; 10 11 namespace ConsoleApplication1 12 { 13 class Program 14 { 15 static void Main(string[] args) 16 { 17 TcpListener listener = new TcpListener(new System.Net.IPAddress(new byte[] { 127, 0, 0, 1 }), 2222); 18 19 listener.Start(); 20 21 //用專門的線程來接受請求 22 Task.Factory.StartNew(() => 23 { 24 //不間斷的接受客戶端請求 25 while (true) 26 { 27 //接受客戶端的連接請求 28 var myclient = listener.AcceptTcpClient(); 29 30 //用工作線程執行用戶的請求 31 Task.Factory.StartNew((obj) => 32 { 33 var client = obj as TcpClient; 34 35 BinaryReader sr = new BinaryReader(client.GetStream()); 36 37 //客戶端數據 38 var data = sr.ReadString(); 39 40 //客戶端ip 41 var ip = (IPEndPoint)client.Client.RemoteEndPoint; 42 43 Console.WriteLine("當前時間:{0},接受到了來自IP:{1}:{2},的請求,發來的數據為:{3}", DateTime.Now, 44 ip.Address, ip.Port, data); 45 46 Thread.Sleep(1000 * 5); 47 48 //處理完了之后要返回數據給客戶端 49 BinaryWriter sw = new BinaryWriter(client.GetStream()); 50 51 sw.Write(string.Format("當前時間:{0},服務端已經處理完畢!", DateTime.Now)); 52 53 client.Close(); 54 55 }, myclient); 56 } 57 }); 58 59 Console.WriteLine("服務端已經啟動..."); 60 61 Console.Read(); 62 } 63 } 64 }
客戶端:

1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Net.Sockets; 6 using System.IO; 7 using System.Threading; 8 using System.Threading.Tasks; 9 10 namespace ConsoleApplication2 11 { 12 class Program 13 { 14 static void Main(string[] args) 15 { 16 for (int i = 0; i < 100; i++) 17 { 18 Task.Factory.StartNew(() => 19 { 20 for (int j = 0; j < 100; j++) 21 { 22 TcpClient client = new TcpClient(); 23 24 client.Connect(new System.Net.IPAddress(new byte[] { 127, 0, 0, 1 }), 2222); 25 26 BinaryWriter bw = new BinaryWriter(client.GetStream()); 27 28 bw.Write(string.Format("你好,我來請求你! {0},當前線程:{1}", j, Thread.CurrentThread.ManagedThreadId)); 29 30 BinaryReader sr = new BinaryReader(client.GetStream()); 31 32 var s = sr.ReadString(); 33 34 Console.WriteLine("接受到數據:{0}", s); 35 } 36 }); 37 } 38 39 Console.Read(); 40 } 41 } 42 }