C# :socket 通訊基礎使用實例

們在講解Socket編程前,先看幾個和Socket編程緊密相關的概念:

  1. TCP/IP層次模型

? ? 當然這里我們只討論重要的四層

? ? ? ?01,應用層(Application):應用層是個很廣泛的概念,有一些基本相同的系統級TCP/IP應用以及應用協議,也有許多的企業應用和互聯網應用。http協議在應用層運行。

?????? 02,傳輸層(Tanspot):傳輸層包括UDP和TCP,UDP幾乎不對報文進行檢查,而TCP

提供傳輸保證。

? ? ? 03,網絡層(Netwok):網絡層協議由一系列協議組成,包括ICMP、IGMP、RIP、OSPF、IP(v4,v6)等。

? ? ? 04,鏈路層(Link):又稱為物理數據網絡接口層,負責報文傳輸。

? ?然后我們來看下tcp層次模型圖

?

? ? ?從上圖中可以看出,應用程序在應用層運行,在傳輸層,在數據前加上了TCP頭,在

網絡層加上的IP頭,在數據鏈路層加上了幀。

???2,端口

? ? 端口號范圍:0-65535,總共能表示65536個數。

? ?按端口號可分為3大類

  (1)公認端口(WellKnownPorts):從0到1023,它們緊密綁定(binding)于一些服務。通常這些端口的通訊明確表明了某種服務的協議。例如:80端口實際上總是HTTP通訊。

  (2)注冊端口(RegisteredPorts):從1024到49151。它們松散地綁定于一些服務。也就是說有許多服務綁定于這些端口,這些端口同樣用于許多其它目的。例如:許多系統處理動態端口從1024左右開始。

  (3)動態和/或私有端口(Dynamicand/orPrivatePorts):從49152到65535。理論上,不應為服務分配這些端口。實際上,機器通常從1024起分配動態端口。

3.TCP和UDP報文

? 下面一起來看下TCP和UDP的報文圖

?

? ? ? 從圖中我們可以看出TCP和UDP中都有校驗和,但是在UDP報文中,一般不使用校驗和,這樣可以加快數據傳輸的速度,但是數據的準確性可能會受到影響。換句話說,Tcp協議都有校驗和,為了保證傳輸數據的準確性。

3.Socket

? ? ?Socket包括Ip地址和端口號兩部分,程序通過Socket來通信,Socket相當于操作系統的一個組件。Socket作為進程之間通信機制,通常也稱作”套接字”,用于描述IP地址和端口號,是一個通信鏈的句柄。說白了,就是兩個程序通信用的。

生活案例對比:

? ? ? Socket之間的通信可以類比生活中打電話的案例。任何用戶在通話之前,首先要占有一部電話機,相當于申請一個Socket,同時要知道對方的號碼,相當于對方有一個固定的Socket,然后向對方撥號呼叫,相當于發出連接請求。假如對方在場并空閑,拿起 電話話筒,雙方就可以進行通話了。雙方的通話過程,是一方向電話機發出信號和對方從電話機接收信號的過程,相當于向socket發送數據和從socket接收數據。通話結束后,一方掛起電話機,相當于關閉socket,撤銷連接。

?????注意:Socket不僅可以在兩臺電腦之間通信,還可以在同一臺電腦上的兩個程序間通信。

4,端口進階(深入)

? ??通過IP地址確定了網絡中的一臺電腦后,該電腦上可能提供很多提供服務的應用,每一個應用都對應一個端口。

在Internet上有很多這樣的主機,這些主機一般運行了多個服務軟件 ,同時提供幾種服務,每種服務都打開一個Socket,并綁定到一個端口上,不同的端口對應于不同的服務(應用程序)

? ? 例如:http 使用80端口,?? ftp使用21端口???? smtp使用25端口

5.Socket分類

? ? ?Socket主要有兩種類型:

  1. 流式Socket

? ? ? ? ? 是一種面向連接的Socket,針對于面向連接的TCP服務應用,安全,但是效率低

? ? ?2,數據報式Socket

? ? ? ? ? 是一種無連接的Socket,對應于無連接的UDP服務應用,不安全,但效率高

?6. Socket一般應用模式(服務器端和客戶端)

? ? ?服務器端的Socket(至少需要兩個)

? ? ? ? 01.一個負責接收客戶端連接請求(但不負責與客戶端通信)

? ? ? ?02.每成功接收到客戶端的連接便在服務器端產生一個對應的復雜通信的Socket

? ? ? ? ? 021.在接收到客戶端連接時創建

? ? ? ? ?022. 為每個連接成功的客戶端請求在服務器端都創建一個對應的Socket(負責和客戶端通信)

? ? 客戶端的Socket

  1. 必須指定要連接的服務器地址和端口
  2. 通過創建一個Socket對象來初始化一個到服務器端的TCP連接

?

? ? ? 通過上圖,我們可以看出,首先服務器會創建一個負責監聽的socket,然后客戶端通過socket連接到服務器指定端口,最后服務器端負責監聽的socket,監聽到客戶端有連接過來了,就創建一個負責和客戶端通信的socket。

下面我們來看下Socket更具體的通信過程:

Socket的通訊過程

? 服務器端:

? ? 01,申請一個socket

? ? 02,綁定到一個IP地址和一個端口上

? ? 03,開啟偵聽,等待接收連接

? 客戶端:

? ? 01,申請一個socket

? ?02,連接服務器(指明IP地址和端口號)

? ?服務器端接收到連接請求后,產生一個新的socket(端口大于1024)與客戶端建立連接并進行通信,原監聽socket繼續監聽。

??注意:負責通信的Socket不能無限創建,創建的數量和操作系統有關。

?7.Socket的構造函數

? ? Public Socket(AddressFamily addressFamily,SocketType? socketType,ProtocolType? protocolTYpe)

? ? AddressFamily:指定Socket用來解析地址的尋址方案。例如:InterNetWork指示當Socket使用一個IP版本4地址連接

? ?SocketType:定義要打開的Socket的類型

? ?Socket類使用ProtocolType枚舉向Windows? Sockets? API通知所請求的協議

注意:

? ?1,端口號必須在 1 和 65535之間,最好在1024以后。

? ?2,要連接的遠程主機必須正在監聽指定端口,也就是說你無法隨意連接遠程主機。

如:

IPAddress addr = IPAddress.Parse("127.0.0.1");

IPEndPoint endp = new IPEndPoint(addr,,9000);

???????? 服務端先綁定:serverWelcomeSocket.Bind(endp)

???????? 客戶端再連接:clientSocket.Connect(endp)

? ?3,一個Socket一次只能連接一臺主機

? ?4,Socket關閉后無法再次使用

? 5,每個Socket對象只能與一臺遠程主機連接。如果你想連接到多臺遠程主機,你必須創建多個Socket對象。

8.Socket常用類和方法

? 相關類:

? ?IPAddress:包含了一個IP地址

? ?IPEndPoint:包含了一對IP地址和端口號

?方法:

? ?Socket():創建一個Socket

? ?Bind():綁定一個本地的IP和端口號(IPEndPoint)

? ?Listen():讓Socket偵聽傳入的連接吃那個病,并指定偵聽隊列容量

? ?Connect():初始化與另一個Socket的連接

? ?Accept():接收連接并返回一個新的Socket

? ?Send():輸出數據到Socket

? ?Receive():從Socket中讀取數據

? ?Close():關閉Socket,銷毀連接

? 接下來,我們同一個簡單的服務器和客戶端通信的案例,來看下Sokcet的具體用法,效果圖如下:

服務器端代碼:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;namespace 服務器
{public partial class FServer : Form{IPAddress ip;IPEndPoint point;public FServer(){InitializeComponent();ServerListen();}private void ServerListen()   {//ip地址 ip = IPAddress.Parse(txtIP.Text);// IPAddress ip = IPAddress.Any;//端口號point = new IPEndPoint(ip, int.Parse(txtPort.Text)); //創建監聽用的Socket /*AddressFamily.InterNetWork:使用 IP4地址。SocketType.Stream:支持可靠、雙向、基于連接的字節流,而不重復數據。此類型的 Socket 與單個對方主機進行通信,并且在通信開始之前需要遠程主機連接。Stream 使用傳輸控制協議 (Tcp) ProtocolType 和 InterNetworkAddressFamily。 ProtocolType.Tcp:使用傳輸控制協議。  */  //使用IPv4地址,流式socket方式,tcp協議傳遞數據  Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); //創建好socket后,必須告訴socket綁定的IP地址和端口號。 //讓socket監聽point  try{  //socket監聽哪個端口 socket.Bind(point);  //同一個時間點過來60個客戶端,排隊 socket.Listen(60);  ShowMsg("服務器開始監聽"); Thread thread = new Thread(AcceptInfo);  thread.IsBackground = true;  thread.Start(socket);  }  catch (Exception ex)  {ShowMsg(ex.Message);  }  }//記錄通信用的Socket  Dictionary<string, Socket> dic = new Dictionary<string, Socket>();  // private Socket client; void AcceptInfo(object o){  Socket socket = o as Socket;  while (true) {  //通信用socket try  { //創建通信用的SocketSocket tSocket = socket.Accept();string point = tSocket.RemoteEndPoint.ToString();//IPEndPoint endPoint = (IPEndPoint)client.RemoteEndPoint;//string me = Dns.GetHostName();//得到本機名稱//MessageBox.Show(me);ShowMsg(point + "連接成功!");ComboBoxAddItems(point);dic.Add(point, tSocket);//接收消息Thread th = new Thread(ReceiveMsg);th.IsBackground = true;th.Start(tSocket);}catch (Exception ex){ShowMsg(ex.Message);break; }}}//接收消息 void ReceiveMsg(object o){Socket client = o as Socket;while (true){//接收客戶端發送過來的數據try{//定義byte數組存放從客戶端接收過來的數據byte[] buffer = new byte[1024 * 1024];//將接收過來的數據放到buffer中,并返回實際接受數據的長度int n = client.Receive(buffer);//將字節轉換成字符串string words = Encoding.UTF8.GetString(buffer, 0, n);ShowMsg(client.RemoteEndPoint.ToString() + ":" + words);}catch (Exception ex){if (!client.Connected) ComboBoxRoMoveItems(client.RemoteEndPoint.ToString());ShowMsg(ex.Message); break;}}}delegate void SetTextCallback(string msg);public void ShowMsg(string msg){if (this.txtLog.InvokeRequired){SetTextCallback d = new SetTextCallback(ShowMsg);this.Invoke(d, new object[] { msg });}else{this.txtLog.AppendText(msg + "\r\n");}}delegate void SetComboBox(String msg);public void ComboBoxAddItems(string msg){if (this.cboIpPort.InvokeRequired){SetTextCallback d = new SetTextCallback(ComboBoxAddItems);this.Invoke(d, new object[] { msg });}else{this.cboIpPort.Items.Add(msg);}}public void ComboBoxRoMoveItems(string msg){if (this.cboIpPort.InvokeRequired){SetTextCallback d = new SetTextCallback(ComboBoxRoMoveItems);this.Invoke(d, new object[] { msg });}else{this.cboIpPort.Items.Remove(msg);cboIpPort.SelectedIndex = -1;}}//給客戶端發送消息private void btnSend_Click(object sender, EventArgs e){try{                string ip = cboIpPort.Text;if (cboIpPort.Text.Length > 5){                    byte[] buffer = Encoding.UTF8.GetBytes(txtMsg.Text);dic[ip].Send(buffer);ShowMsg(point.ToString() + ":" + txtMsg.Text);}else{}}catch (Exception ex){ShowMsg(ex.Message);}}private void Clearbtn_Click(object sender, EventArgs e){this.txtLog.Text = "";}}
}

?

客戶端代碼:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Net.Sockets;
using System.Net;
using System.Threading;namespace 客戶端
{public partial class FClient : Form{Socket client;IPAddress ip;IPEndPoint point;bool isExits = false;public FClient(){InitializeComponent();}private void FClient_Load(object sender, EventArgs e){ip = IPAddress.Parse(txtIP.Text);  point = new IPEndPoint(ip, int.Parse(txtPort.Text));Thread serverConnetThread = new Thread(ServerConnetThread);serverConnetThread.IsBackground = true;serverConnetThread.Start();}private void ServerConnet(){try{//連接到服務器  if (client != null) client.Close();client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);client.Connect(point);ShowMsg("連接成功");ShowMsg("服務器:" + client.RemoteEndPoint.ToString());ShowMsg("客戶端:" + client.LocalEndPoint.ToString());//連接成功后,就可以接收服務器發送的信息了 Thread th = new Thread(ReceiveMsg);th.IsBackground = true;th.Start();}catch (Exception ex){ShowMsg(ex.Message);}}private void ServerConnetThread()  {while (!isExits){if (client == null || !client.Connected) {ServerConnet();}Thread.Sleep(5000);}           }//接收服務器的消息void ReceiveMsg(){while (true){try {byte[] buffer = new byte[1024 * 1024];int n = client.Receive(buffer);string s = Encoding.UTF8.GetString(buffer, 0, n);ShowMsg(point.ToString() + ":" + s);}catch (Exception ex){ShowMsg(ex.Message);break;}}           }delegate void SetTextCallback(string msg);public void ShowMsg(string msg){if (this.txtInfo.InvokeRequired){SetTextCallback d = new SetTextCallback(ShowMsg);this.Invoke(d, new object[] { msg });}else{this.txtInfo.AppendText(msg + "\r\n");}}private void btnSend_Click(object sender, EventArgs e){//客戶端給服務器發消息          if (client != null)                {               try{ShowMsg(client.RemoteEndPoint + ":" + txtMsg.Text);byte[] buffer = Encoding.UTF8.GetBytes(txtMsg.Text);                   client.Send(buffer);                    }               catch (Exception ex){                 ShowMsg(ex.Message);                    }              }}private void Clearbtn_Click(object sender, EventArgs e){this.txtInfo.Text = "";}}
}

?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/252093.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/252093.shtml
英文地址,請注明出處:http://en.pswp.cn/news/252093.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

IBM發表論文:可能已找到處理量子計算退相干的方法

在《自然》雜志最近發表的一篇論文中&#xff0c;IBM和其他機構的研究人員設計了兩種量子算法&#xff0c;利用變分量子電路和量子核估計器來訓練一種支持向量機分類器。這兩種算法背后的關鍵思想是使用量子狀態空間作為特征空間表示&#xff0c;有效地構建映射&#xff0c;從原…

PHP + NGINX 控制視頻文件播放,并防止文件下載

最簡單的方法是使用NGINX的 internal 功能 server { listen 80; server_name www.xxx.com;  location / { index index.php index.html index.htm; root /xxx; if (!-e $request_filename) { rewrite ^/index.php(.*)$ /index.php?s$…

可視化調試工具

rosrun rqt_console rqt_console # 查看日志消息&#xff0c;可filter、highlight指定級別。 rosrun rqt_logger_level rqt_logger_level # 可設在日志記錄器的嚴重級別 rosrun rqt_topic rqt_topic # 顯示topic調試信息 rosrun rqt_publisher rqt_publisher # 在界面中管理ro…

C#:委托基礎與事件

通過以下思維導圖&#xff0c;學習委托的基本概念&#xff0c;后面著重講解委托的運用&#xff0c;希望通過最簡單的方式收獲更多的知識。 1.委托的各種寫法 1、委托 委托名new 委托&#xff08;會調用的方法名); 委托名&#xff08;參數&#xff09;; 2、委托 委托名 會調用…

Git Bash關鍵命令

1.默認目錄是C:\Users\用戶名 2.切換目錄&#xff1a;$cd c:\\windows 3.切換到上級目錄&#xff1a;cd ..&#xff0c;中間有空格 4.列出某目錄所有文件&#xff0c;相當于DOS下的dir&#xff1a;ls c:\\windows 5.查看配置信息&#xff1a;git config --list 以下是顯示信息 …

C#:invoke 與 BeginInvoke使用區別

invoke和begininvoke 區別 一直對invoke和begininvoke的使用和概念比較混亂&#xff0c;這兩天看了些資料&#xff0c;對這兩個的用法和原理有了些新的認識和理解。 首先說下&#xff0c;invoke和begininvoke的使用有兩種情況&#xff1a; 1. control中的invoke、begininvoke。…

Django基本命令

Django基本命令 1.創建一個Django 項目 django_admin.py startproject mysite當前目錄下會生成mysite的工程&#xff0c;目錄結構如下&#xff1a; manage.py ----- Django項目里面的工具&#xff0c;通過它可以調用django shell和數據庫等。settings.py ---- 包含了項目的默認…

Git忽略規則.gitignore梳理

對于經常使用Git的朋友來說&#xff0c;.gitignore配置一定不會陌生。廢話不說多了&#xff0c;接下來就來說說這個.gitignore的使用。首先要強調一點&#xff0c;這個文件的完整文件名就是".gitignore"&#xff0c;注意最前面有個“.”。 一般來說每個Git項目中都需…

第二周CoreIDRAW課總結

1.這節課學到了什么知識&#xff1f; 學到了圖像的復制&#xff0c;再制鼠標復制&#xff0c;重復&#xff0c;還有對象的對齊&#xff0c;對象的分布順序。 2.有哪些心得體會&#xff1f; 做了課本的練習&#xff0c;會用窗口里面的泊塢窗造型命令也作出了一個作品。 3.這節課…

axios關于針對請求時長策略設計的思考

前言 在我們的業務請求中&#xff0c;有很多時候會針對有不同時長的需求策略性設置。這里針對這個需求進行詳細的展開。 針對這種情況&#xff0c;我們的timout的一般是根據請求地址來的&#xff0c;所以核心處理技巧便是如何根據不同的request地址去設置不同的timeout. 我們之…

C#:WinForm無邊框窗體移動方法、模仿鼠標單擊標題欄移動窗體位置

方法一&#xff1a;直接通過修改窗體位置從而達到移動窗體的效果 方法二&#xff1a;直接偽裝發送單擊任務欄消息&#xff0c;讓應用程序誤以為單擊任務欄從而移動窗體 方法一 1.定義一個位置信息Point用于存儲鼠標位置 private Point mPoint; 2.給窗體等控件增加MouseDown…

Python 字典刪除元素clear、pop、popitem

同其它python內建數據類型一樣&#xff0c;字典dict也是有一些實用的操作方法。這里我們要說的是字典刪除方法&#xff1a;clear()、pop()和popitem()&#xff0c;這三種方法的作用不同&#xff0c;操作方法及返回值都不相同。接下來就來查看下這些字典特定方法的具體用法是什么…

reactor模式:多線程的reactor模式

上文說到單線程的reactor模式 reactor模式&#xff1a;單線程的reactor模式 單線程的reactor模式并沒有解決IO和CPU處理速度不匹配問題&#xff0c;所以多線程的reactor模式引入線程池的概念&#xff0c;把耗時的IO操作交由線程池處理&#xff0c;處理完了之后再同步到selecti…

Elasticsearch實戰篇——Spring Boot整合ElasticSearch

2019獨角獸企業重金招聘Python工程師標準>>> 當前Spring Boot很是流行&#xff0c;包括我自己&#xff0c;也是在用Spring Boot集成其他框架進行項目開發&#xff0c;所以這一節&#xff0c;我們一起來探討Spring Boot整合ElasticSearch的問題。 本文主要講以下內容…

C#:Dockpanel的一些入門的基本操作

原文鏈接&#xff1a; 一、引用&#xff1a; 1.建立一個WinForm工程&#xff0c;默認生成了一個WinForm窗體Form1&#xff08;此處默認為主窗體&#xff09;。 2.引用—>添加引用—>瀏覽—>weiFenLuo.winFormsUI.Docking.dll。 3.設置Form1窗體屬性IsMdiContainer…

MyBatis中if,where,set標簽

<if>標簽 <select id"findActiveBlogWithTitleLike"resultType"Blog">SELECT * FROM BLOG WHERE state ‘ACTIVE’ <if test"title ! null">AND title like #{title}</if> </select> if標簽通常伴隨著where,set…

Python3基礎 __repr__ 類的實例對象的名字 可以打印文字(1)

引用自&#xff1a;http://www.bubuko.com/infodetail-1918622.html 這個__repr__的作用從下邊的例子中可以看出,返回實例化對象的表達 code: class MyClass() :def __str__(self) :return "我是MyClass的一個實例"def __repr__(self) :return "這回連print都省…

Day03:文件打開;錯誤處理

錯誤處理 try: #要執行的代碼 except 錯誤的類型&#xff08;可選&#xff09;: #發生錯誤時執行的代碼 finally: #有沒有發生錯誤都執行的代碼 復制代碼with open() as 變量名&#xff1a; with提供一種叫上下文管理協議的python技術&#xff0c;系統會自動關閉文件 open() 默…

Python: pip升級報錯了:You are using pip version 10.0.1, however version 20.3.3 is available.

1,Python使用命令&#xff1a;python -m pip install --upgrade pip升級pip的時候報了下面這個錯 2,換了個命令&#xff1a; python -m pip install --upgrade pip -i https://pypi.douban.com/simple 更新成功了&#xff0c;但又報了一個新的錯誤&#xff1a; AttributeError:…

新手上路之Hibernate:第一個Hibernate例子

一、Hibernate概述 &#xff08;一&#xff09;什么是Hibernate&#xff1f; Hibernate核心內容是ORM&#xff08;關系對象模型&#xff09;。可以將對象自動的生成數據庫中的信息&#xff0c;使得開發更加的面向對象。這樣作為程序員就可以使用面向對象的思想來操作數據庫&…