當然這里我們只討論重要的四層 01,應(yīng)用層(Application):應(yīng)用層是個很廣泛的概念,,有一些基本相同的系統(tǒng)級TCP/IP應(yīng)用以及應(yīng)用協(xié)議,,也有許多的企業(yè)應(yīng)用和互聯(lián)網(wǎng)應(yīng)用。http協(xié)議在應(yīng)用層運行,。 02,,傳輸層(Tanspot):傳輸層包括UDP和TCP,UDP幾乎不對報文進行檢查,,而TCP 提供傳輸保證,。 03,網(wǎng)絡(luò)層(Netwok):網(wǎng)絡(luò)層協(xié)議由一系列協(xié)議組成,,包括ICMP,、IGMP、RIP,、OSPF,、IP(v4,v6)等。 04,,鏈路層(Link):又稱為物理數(shù)據(jù)網(wǎng)絡(luò)接口層,,負責報文傳輸。 然后我們來看下tcp層次模型圖 從上圖中可以看出,,應(yīng)用程序在應(yīng)用層運行,,在傳輸層,在數(shù)據(jù)前加上了TCP頭,,在 網(wǎng)絡(luò)層加上的IP頭,,在數(shù)據(jù)鏈路層加上了幀。 2,,端口 端口號范圍:0-65535,,總共能表示65536個數(shù)。 按端口號可分為3大類 ?。?)公認端口(WellKnownPorts):從0到1023,,它們緊密綁定(binding)于一些服務(wù)。通常這些端口的通訊明確表明了某種服務(wù)的協(xié)議,。例如:80端口實際上總是HTTP通訊,。 ?。?)注冊端口(RegisteredPorts):從1024到49151。它們松散地綁定于一些服務(wù),。也就是說有許多服務(wù)綁定于這些端口,這些端口同樣用于許多其它目的,。例如:許多系統(tǒng)處理動態(tài)端口從1024左右開始,。 (3)動態(tài)和/或私有端口(Dynamicand/orPrivatePorts):從49152到65535,。理論上,,不應(yīng)為服務(wù)分配這些端口。實際上,,機器通常從1024起分配動態(tài)端口,。 3.TCP和UDP報文 下面一起來看下TCP和UDP的報文圖 從圖中我們可以看出TCP和UDP中都有校驗和,但是在UDP報文中,,一般不使用校驗和,,這樣可以加快數(shù)據(jù)傳輸?shù)乃俣龋菙?shù)據(jù)的準確性可能會受到影響,。換句話說,,Tcp協(xié)議都有校驗和,為了保證傳輸數(shù)據(jù)的準確性,。 3.Socket Socket包括Ip地址和端口號兩部分,,程序通過Socket來通信,Socket相當于操作系統(tǒng)的一個組件,。Socket作為進程之間通信機制,,通常也稱作”套接字”,用于描述IP地址和端口號,,是一個通信鏈的句柄,。說白了,就是兩個程序通信用的,。 生活案例對比: Socket之間的通信可以類比生活中打電話的案例,。任何用戶在通話之前,首先要占有一部電話機,,相當于申請一個Socket,,同時要知道對方的號碼,相當于對方有一個固定的Socket,,然后向?qū)Ψ綋芴柡艚?,相當于發(fā)出連接請求。假如對方在場并空閑,,拿起 電話話筒,,雙方就可以進行通話了。雙方的通話過程,是一方向電話機發(fā)出信號和對方從電話機接收信號的過程,,相當于向socket發(fā)送數(shù)據(jù)和從socket接收數(shù)據(jù),。通話結(jié)束后,一方掛起電話機,,相當于關(guān)閉socket,,撤銷連接。 注意:Socket不僅可以在兩臺電腦之間通信,,還可以在同一臺電腦上的兩個程序間通信,。 4,端口進階(深入) 通過IP地址確定了網(wǎng)絡(luò)中的一臺電腦后,,該電腦上可能提供很多提供服務(wù)的應(yīng)用,,每一個應(yīng)用都對應(yīng)一個端口。 在Internet上有很多這樣的主機,,這些主機一般運行了多個服務(wù)軟件 ,,同時提供幾種服務(wù),每種服務(wù)都打開一個Socket,,并綁定到一個端口上,,不同的端口對應(yīng)于不同的服務(wù)(應(yīng)用程序) 例如:http 使用80端口, ftp使用21端口 smtp使用25端口 5.Socket分類 Socket主要有兩種類型:
是一種面向連接的Socket,,針對于面向連接的TCP服務(wù)應(yīng)用,,安全,但是效率低 2,,數(shù)據(jù)報式Socket 是一種無連接的Socket,,對應(yīng)于無連接的UDP服務(wù)應(yīng)用,不安全,,但效率高 6. Socket一般應(yīng)用模式(服務(wù)器端和客戶端) 服務(wù)器端的Socket(至少需要兩個) 01.一個負責接收客戶端連接請求(但不負責與客戶端通信) 02.每成功接收到客戶端的連接便在服務(wù)器端產(chǎn)生一個對應(yīng)的復雜通信的Socket 021.在接收到客戶端連接時創(chuàng)建 022. 為每個連接成功的客戶端請求在服務(wù)器端都創(chuàng)建一個對應(yīng)的Socket(負責和客戶端通信) 客戶端的Socket
通過上圖,,我們可以看出,首先服務(wù)器會創(chuàng)建一個負責監(jiān)聽的socket,,然后客戶端通過socket連接到服務(wù)器指定端口,,最后服務(wù)器端負責監(jiān)聽的socket,監(jiān)聽到客戶端有連接過來了,,就創(chuàng)建一個負責和客戶端通信的socket,。 下面我們來看下Socket更具體的通信過程: Socket的通訊過程 服務(wù)器端: 01,申請一個socket 02,,綁定到一個IP地址和一個端口上 03,,開啟偵聽,等待接收連接 客戶端: 01,,申請一個socket 02,,連接服務(wù)器(指明IP地址和端口號) 服務(wù)器端接收到連接請求后,,產(chǎn)生一個新的socket(端口大于1024)與客戶端建立連接并進行通信,原監(jiān)聽socket繼續(xù)監(jiān)聽,。 注意:負責通信的Socket不能無限創(chuàng)建,,創(chuàng)建的數(shù)量和操作系統(tǒng)有關(guān)。 7.Socket的構(gòu)造函數(shù) Public Socket(AddressFamily addressFamily,SocketType socketType,ProtocolType protocolTYpe) AddressFamily:指定Socket用來解析地址的尋址方案,。例如:InterNetWork指示當Socket使用一個IP版本4地址連接 SocketType:定義要打開的Socket的類型 Socket類使用ProtocolType枚舉向Windows Sockets API通知所請求的協(xié)議 注意: 1,,端口號必須在 1 和 65535之間,最好在1024以后,。 2,要連接的遠程主機必須正在監(jiān)聽指定端口,,也就是說你無法隨意連接遠程主機,。 如: IPAddress addr = IPAddress.Parse("127.0.0.1"); IPEndPoint endp = new IPEndPoint(addr,,9000); 服務(wù)端先綁定:serverWelcomeSocket.Bind(endp) 客戶端再連接:clientSocket.Connect(endp) 3,一個Socket一次只能連接一臺主機 4,Socket關(guān)閉后無法再次使用 5,每個Socket對象只能與一臺遠程主機連接。如果你想連接到多臺遠程主機,,你必須創(chuàng)建多個Socket對象,。 8.Socket常用類和方法 相關(guān)類: IPAddress:包含了一個IP地址 IPEndPoint:包含了一對IP地址和端口號 方法: Socket():創(chuàng)建一個Socket Bind():綁定一個本地的IP和端口號(IPEndPoint) Listen():讓Socket偵聽傳入的連接吃那個病,并指定偵聽隊列容量 Connect():初始化與另一個Socket的連接 Accept():接收連接并返回一個新的Socket Send():輸出數(shù)據(jù)到Socket Receive():從Socket中讀取數(shù)據(jù) Close():關(guān)閉Socket,,銷毀連接 接下來,,我們同一個簡單的服務(wù)器和客戶端通信的案例,來看下Sokcet的具體用法,,效果圖如下:
關(guān)鍵代碼: 服務(wù)器端代碼: 1 private void Form1_Load(object sender, EventArgs e) 2 3 { 4 5 Control.CheckForIllegalCrossThreadCalls = false; 6 7 } 8 9 10 11 private void btnListen_Click(object sender, EventArgs e) 12 13 { 14 15 //ip地址 16 17 IPAddress ip = IPAddress.Parse(txtIP.Text); 18 19 // IPAddress ip = IPAddress.Any; 20 21 //端口號 22 23 IPEndPoint point=new IPEndPoint(ip,int.Parse(txtPort.Text)); 24 25 //創(chuàng)建監(jiān)聽用的Socket 26 27 /* 28 29 * AddressFamily.InterNetWork:使用 IP4地址,。 30 31 SocketType.Stream:支持可靠、雙向,、基于連接的字節(jié)流,,而不重復數(shù)據(jù)。此類型的 Socket 與單個對方主機進行通信,,并且在通信開始之前需要遠程主機連接,。Stream 使用傳輸控制協(xié)議 (Tcp) ProtocolType 和 InterNetworkAddressFamily。 32 33 ProtocolType.Tcp:使用傳輸控制協(xié)議,。 34 35 */ 36 37 //使用IPv4地址,,流式socket方式,tcp協(xié)議傳遞數(shù)據(jù) 38 39 Socket socket=new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp); 40 41 //創(chuàng)建好socket后,,必須告訴socket綁定的IP地址和端口號,。 42 43 //讓socket監(jiān)聽point 44 45 try 46 47 { 48 49 //socket監(jiān)聽哪個端口 50 51 socket.Bind(point); 52 53 //同一個時間點過來10個客戶端,排隊 54 55 socket.Listen(10); 56 57 ShowMsg("服務(wù)器開始監(jiān)聽"); 58 59 Thread thread = new Thread(AcceptInfo); 60 61 thread.IsBackground = true; 62 63 thread.Start(socket); 64 65 } 66 67 catch (Exception ex) 68 69 { 70 71 72 73 ShowMsg(ex.Message); 74 75 } 76 77 } 78 79 //記錄通信用的Socket 80 81 Dictionary<string,Socket> dic=new Dictionary<string, Socket>(); 82 83 // private Socket client; 84 85 void AcceptInfo(object o) 86 87 { 88 89 Socket socket = o as Socket; 90 91 while (true) 92 93 { 94 95 //通信用socket 96 97 try 98 99 { 100 101 //創(chuàng)建通信用的Socket 102 103 Socket tSocket = socket.Accept(); 104 105 string point = tSocket.RemoteEndPoint.ToString(); 106 107 //IPEndPoint endPoint = (IPEndPoint)client.RemoteEndPoint; 108 109 //string me = Dns.GetHostName();//得到本機名稱 110 111 //MessageBox.Show(me); 112 113 ShowMsg(point + "連接成功,!"); 114 115 cboIpPort.Items.Add(point); 116 117 dic.Add(point, tSocket); 118 119 //接收消息 120 121 Thread th = new Thread(ReceiveMsg); 122 123 th.IsBackground = true; 124 125 th.Start(tSocket); 126 127 } 128 129 catch (Exception ex) 130 131 { 132 133 ShowMsg(ex.Message); 134 135 break; 136 137 } 138 139 } 140 141 } 142 143 //接收消息 144 145 void ReceiveMsg(object o) 146 147 { 148 149 Socket client = o as Socket; 150 151 while (true) 152 153 { 154 155 //接收客戶端發(fā)送過來的數(shù)據(jù) 156 157 try 158 159 { 160 161 //定義byte數(shù)組存放從客戶端接收過來的數(shù)據(jù) 162 163 byte[] buffer = new byte[1024 * 1024]; 164 165 //將接收過來的數(shù)據(jù)放到buffer中,,并返回實際接受數(shù)據(jù)的長度 166 167 int n = client.Receive(buffer); 168 169 //將字節(jié)轉(zhuǎn)換成字符串 170 171 string words = Encoding.UTF8.GetString(buffer, 0, n); 172 173 174 175 ShowMsg(client.RemoteEndPoint.ToString() + ":" + words); 176 177 } 178 179 catch (Exception ex) 180 181 { 182 183 ShowMsg(ex.Message); 184 185 break; 186 187 } 188 189 } 190 191 } 192 193 194 195 void ShowMsg(string msg) 196 197 { 198 199 txtLog.AppendText(msg+"\r\n"); 200 201 } 202 203 204 205 private void Form1_FormClosing(object sender, FormClosingEventArgs e) 206 207 { 208 209 //主窗體關(guān)閉時關(guān)閉子線程 210 211 212 213 } 214 215 //給客戶端發(fā)送消息 216 217 private void btnSend_Click(object sender, EventArgs e) 218 219 { 220 221 try 222 223 { 224 225 ShowMsg(txtMsg.Text); 226 227 string ip = cboIpPort.Text; 228 229 byte[] buffer = Encoding.UTF8.GetBytes(txtMsg.Text); 230 231 dic[ip].Send(buffer); 232 233 // client.Send(buffer); 234 235 } 236 237 catch (Exception ex) 238 239 { 240 241 ShowMsg(ex.Message); 242 243 } 244 245 246 247 }
客戶端代碼: 1 Socket client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 2 3 private void btnConnection_Click(object sender, EventArgs e) 4 5 { 6 7 //連接到的目標IP 8 9 IPAddress ip = IPAddress.Parse(txtIP.Text); 10 11 //IPAddress ip = IPAddress.Any; 12 13 //連接到目標IP的哪個應(yīng)用(端口號!) 14 15 IPEndPoint point=new IPEndPoint(ip,int.Parse(txtPort.Text)); 16 17 try 18 19 { 20 21 //連接到服務(wù)器 22 23 client.Connect(point); 24 25 ShowMsg("連接成功"); 26 27 ShowMsg("服務(wù)器" + client.RemoteEndPoint.ToString()); 28 29 ShowMsg("客戶端:" + client.LocalEndPoint.ToString()); 30 31 //連接成功后,,就可以接收服務(wù)器發(fā)送的信息了 32 33 Thread th=new Thread(ReceiveMsg); 34 35 th.IsBackground = true; 36 37 th.Start(); 38 39 } 40 41 catch (Exception ex) 42 43 { 44 45 ShowMsg(ex.Message); 46 47 } 48 49 } 50 51 //接收服務(wù)器的消息 52 53 void ReceiveMsg() 54 55 { 56 57 while (true) 58 59 { 60 61 try 62 63 { 64 65 byte[] buffer = new byte[1024 * 1024]; 66 67 int n = client.Receive(buffer); 68 69 string s = Encoding.UTF8.GetString(buffer, 0, n); 70 71 ShowMsg(client.RemoteEndPoint.ToString() + ":" + s); 72 73 } 74 75 catch (Exception ex) 76 77 { 78 79 ShowMsg(ex.Message); 80 81 break; 82 83 } 84 85 } 86 87 88 89 } 90 91 92 93 void ShowMsg(string msg) 94 95 { 96 97 txtInfo.AppendText(msg+"\r\n"); 98 99 } 100 101 102 103 private void btnSend_Click(object sender, EventArgs e) 104 105 { 106 107 //客戶端給服務(wù)器發(fā)消息 108 109 if (client!=null) 110 111 { 112 113 try 114 115 { 116 117 ShowMsg(txtMsg.Text); 118 119 byte[] buffer = Encoding.UTF8.GetBytes(txtMsg.Text); 120 121 client.Send(buffer); 122 123 } 124 125 catch (Exception ex) 126 127 { 128 129 ShowMsg(ex.Message); 130 131 } 132 133 } 134 135 136 137 } 138 139 140 141 private void ClientForm_Load(object sender, EventArgs e) 142 143 { 144 145 Control.CheckForIllegalCrossThreadCalls = false; 146 147 } 好了,,到這里我們對Socket的討論就告一個段落了,。希望以后還有時間來研究這方面的知識。因為我深深的知道,,能和大家探討也是一種幸福,。 2013年3月7日0:00點
|
|
來自: 空城66 > 《網(wǎng)絡(luò)編程》