溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Socket Basic Concepts

發布時間:2020-05-30 09:35:34 來源:網絡 閱讀:404 作者:skydxd 欄目:編程語言

Socket Basic Concepts


Socket Basic Concepts 

首先介紹Socket的一些基本概念

Socket是操作系統提供的一系列網絡編程接口。

網絡模型分若干層,也有一些協議,比如TCP協議,UDP協議等,這些都是抽象的定義,在硬件以及操作系統級別上有一些對應的實現,Socket可以看做操作系統為開發人員提供的一系列網絡編程接口,它封裝了一些協議的細節,比如怎么組織數據包,怎么發送數據之類的。

Socket編程的幾個基本概念 

Endpoint
Endpoin指定要連接到哪里,Endpoint包括兩部分內容,IP和Port,IP地址和端口組合起來才能唯一指定遠程的通信端。

AddressFamily
怎么尋址,有了IP地址之后就是如何尋址的問題,常用的尋址方案是IP V4和IP V6兩種類型,windows操作系統從VISTA和Windows 20008起默認支持IPV6。

Protocol
使用什么協議進行通信,比如TCP協議或者UDP協議,下面介紹Socket類型的時候還會涉及TCP和UDP等協議的介紹。

Socket類型

Socket有三種常用類型:Stream, Dgram, Raw

Stream流類型,支持可靠、雙向、基于連接的字節流,使用TCP協議。

Dgram數據報類型,支持數據報,即最大長度固定的無連接、不可靠消息。消息可能會丟失或重復并可能在到達時不按順序排列,使用UDP協議。

Raw類型支持對基礎傳輸協議的訪問,需要自己生成數據包。網上有一些RAW的例子,比如D.O.S***,ARP***,網絡監控之類的。

本文只討論Stream類型的Socket編程,RAW和Dgram不在討論之列,也就是只討論基于TCP協議的編程。

一些常見的概念問題

Socket和TCP/IP有什么關系?

Socket和TCP/IP不是一個層面的概念,Socket是操作系統提供的操作TCP數據的編程接口。

Sockets V4、Sockets V5有什么區別?

經??吹揭恍┸浖梢栽O置Sockets4/Sockets5代理,簡單說他們是客戶端與外網服務器之間通訊的協議,Sockets是位于應用層與傳輸層之間的中間層。 Sockets V4支持TCP, Sockets V5支持TCP/UDP,支持安全認證,支持IPV6。

Socket能夠同時接受和發送數據嗎?

TCP協議是雙工的

Socket如何保證數據按順序到達?

TCP協議來保證

Socket的基本通信模型模型

客戶端:

Socket()
Connect
Send
Close

服務器端:

Socket()
Bind
Listen
Accept
Receive
Send
Close

客戶端和服務器端模型是不一樣的,兩邊是非對稱的。

 .Net Socket API


下面是.Net Socket編程最基本的幾個類,位于命名空間System.Net.Sockets

Socket Socket接口類
TcpClient TCP客戶端類
TcpListener TCP偵聽類
NetworkStream 用于網絡訪問的基礎數據流

其他經常用到的輔助類,位于命名空間System.Net

Dns 域名解析
EndPoint  標識網絡地址
IPAddress  IP地址。
NetworkCredential 基于密碼的身份驗證方案,不支持基于公鑰的身份驗證方法(比如ssl)

一個Socket的簡單例子

輸入網址,獲得HTML頁面的一段演示代碼,只是演示Socket對象的幾個主要功能,不具有實用價值。

基本步驟為:建立Socket對象,連接服務器,發送數據,然后接受數據,對應上一章介紹的Socket通信模型。

代碼

01 <span style="font-size: 10pt;">private string DownloadPage(string path)
02         {
03             Uri uri = new Uri(path);
04             Encoding encoding = Encoding.UTF8;// .GetEncoding("gb2312");
05  
06             string requestHeader = BuildRequestHeader(uri);
07             byte[] requestBytes = encoding.GetBytes(requestHeader);
08             byte[] receivedBytes = new byte[1024 * 100];
09  
10             Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
11             socket.Connect(uri.Host,uri.Port);
12             socket.Send(requestBytes);
13  
14             int receivedBytesLength = socket.Receive(receivedBytes);
15             socket.Shutdown(SocketShutdown.Both);
16             socket.Close();
17  
18             string html = string.Empty;
19             if (receivedBytesLength &gt; 0)
20             {
21                 html = encoding.GetString(receivedBytes, 0, receivedBytesLength);
22             }
23             return html;
24         }</span>


構造HTTP Header的代碼如下,注意不要忘了Http頭模板的最后一行

01 <span style="font-size: 10pt;">private string BuildRequestHeader(Uri uri)
02         {
03             string httpHeaderTemplate = @"GET {url} HTTP/1.1
04 Connection: Close
05 Host: {host}
06  
07 ";
08             return httpHeaderTemplate.Replace("{url}", uri.AbsolutePath)
09                 .Replace("{host}", uri.Host);
10  
11         }</span>


30秒思考題:這段簡單代碼有什么問題?

我們定義的用來接收數據的數組大小是固定的,如果要接受的數據超過數組大小怎么辦? 可以定義一個緩沖區,每次接受固定大小的數據,直到接收完成為止。示例代碼如下:

01 <span style="font-size: 10pt;">MemoryStream ms = new MemoryStream();
02             while (true)
03             {
04                 Console.WriteLine("Available :{0}", socket.Available);
05                 int receivedBytesLength = socket.Receive(receivedBytes, 0, receivedBytes.Length, SocketFlags.None);
06                 if (receivedBytesLength &gt; 0)
07                 {
08                     ms.Write(receivedBytes, 0, receivedBytesLength);
09                 }
10                 else
11                 {
12                     break;
13                 }
14             }
15  
16             string html = string.Empty;
17             if (ms.Length &gt; 0)
18             {
19                 html = encoding.GetString(ms.ToArray(), 0, (int)ms.Length);
20             }</span>


Socket的緩沖區

Socket接收數據時,操作系統先把數據接收到緩沖區,然后通知程序,socket.Available 是從已經從網絡接收的、可供讀取的數據的字節數,這個值是指緩沖區中已接收數據的字節數,不是實際的數據大小。而且如果網絡有延遲,Send之后馬上讀取Available屬性不一定能讀到正確的值,所以不能利用socket.Available來判斷總共要接受的字節數。

在上面的方法中,如果沒有可讀取的數據,則 Receive 方法將一直處于阻止狀態,直到有數據可用,如果Server端也沒有正確關閉連接,程序很容易死在這里,可以通過Socket.ReceiveTimeout來設置Socket對象接受數據的超時時間。

30秒思考題:為什么這樣下載的頁面有時候和瀏覽器下載的頁面不一樣?
>>gzip,chunked編碼,重定向等

NetworkStream的例子

前面講過基于TCP協議的Socket是Steam類型的,在操作系統中,為了簡化編程,把設備、文件等都看作流對象,統一編程接口。NetworkStream類提供了在阻止模式下通過Socket套接字發送和接收數據的方法,.Net還提供了TcpClient和TcpListener類,用于簡化同步阻止模式下通過TCP協議連接、發送和接收流數據。下面的例子是這幾個對象的簡單介紹,省略了一些細節,也不具有實用價值。

這個例子模擬計算機遠程控制,先新起一個線程模擬服務進程,在這個線程中創建一個TcpListener對象,等待客戶端連接。用戶在客戶端界面點了“連接”按鈕后,UI線程創建TcpClient對象,等待用戶輸入dos命令,用戶輸入dos命令,按執行按鈕,這時TcpClient對象把用戶輸入的命令發送給TcpListener對象,服務進程執行完命令后,將執行結果反饋給TcpClient對象。

部分代碼。
       

01 <span style="font-size: 10pt;">private void StartServer()
02         {
03             TcpListener server = new TcpListener(IPAddress.Any, 10000);
04             server.Start();
05             Debug.WriteLine("Server: start");
06  
07             TcpClient client = server.AcceptTcpClient();
08             Debug.WriteLine("Server : connection accept");
09             NetworkStream stream = client.GetStream();
10  
11             Process process = new Process();
12             process.StartInfo.FileName = "cmd.exe";
13             process.StartInfo.UseShellExecute = false;
14             process.StartInfo.RedirectStandardInput = true;
15             process.StartInfo.RedirectStandardOutput = true;
16             process.StartInfo.RedirectStandardError = true;
17             process.StartInfo.CreateNoWindow = false;
18             process.Start();
19  
20             process.OutputDataReceived += (Object sender, DataReceivedEventArgs e) =>
21             {
22                 byte[] bytes = Encoding.GetEncoding("gb2312").GetBytes(e.Data + "\r\n");
23                 stream.Write(bytes, 0, bytes.Length);
24             };
25             process.BeginOutputReadLine();
26              
27             while (true)
28             {
29                 Byte[] buffer = new Byte[1024 * 10];
30                 int length = stream.Read(buffer, 0, buffer.Length);
31                 if (length == 0)
32                 {
33                     Debug.WriteLine("Server: read 0 byte");
34                     break;
35                 }
36  
37                 string command = Encoding.GetEncoding("gb2312").GetString(buffer, 0, length);
38                 Debug.WriteLine("Server: receive {0} ", command);
39  
40                 StreamWriter Writer = process.StandardInput;
41                 Writer.WriteLine(command);
42                 Writer.Flush();
43             }
44  
45             server.Stop();
46             process.WaitForExit(1000);
47             process.Close();
48             Debug.WriteLine("Server: close");
49         }
50  
51         TcpClient client;
52         private void ConnectButton_Click(object sender, EventArgs e)
53         {
54             client = new TcpClient();
55             client.Connect("localhost", 10000);
56             Console.WriteLine("Client: connect");
57             StartButton.Enabled = true;
58         }
59  
60         private void StartButton_Click(object sender, EventArgs e)
61         {
62             if (CommandTextBox.Text.Trim().Length == 0)
63             {
64                 return;
65             }
66  
67             string request = CommandTextBox.Text.Trim();
68             byte[] bytes = Encoding.GetEncoding("gb2312").GetBytes(request);
69             NetworkStream stream = client.GetStream();
70             stream.Write(bytes, 0, bytes.Length);
71              
72             Console.WriteLine("Client: request {0}", request);
73             MessageTextBox.AppendText("\r\nresponse from server:\r\n");
74              
75             byte[] buffer = new byte[1024];
76             do{
77                 int receivedBytesLength = stream.Read(buffer, 0, buffer.Length);
78                 if(receivedBytesLength > 0)
79                 {
80                     string text = Encoding.GetEncoding("gb2312").GetString(buffer, 0, receivedBytesLength);
81                     MessageTextBox.AppendText(text);
82                     MessageTextBox.AppendText("\r\n");
83                 }
84                 else
85                 {
86                     break;
87                 }
88             }while(stream.DataAvailable);
89         }</span>


向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

亚洲午夜精品一区二区_中文无码日韩欧免_久久香蕉精品视频_欧美主播一区二区三区美女