日韩欧美国产精品免费一二-日韩欧美国产精品亚洲二区-日韩欧美国产精品专区-日韩欧美国产另-日韩欧美国产免费看-日韩欧美国产免费看清风阁

LOGO OA教程 ERP教程 模切知識交流 PMS教程 CRM教程 開發(fā)文檔 其他文檔  
 
網(wǎng)站管理員

.NET中的TCP、UDP、Socket、WebSocket

freeflydom
2024年9月5日 11:46 本文熱度 1408

做.NET應(yīng)用開發(fā)肯定會用到網(wǎng)絡(luò)通信,而進(jìn)程間通信是客戶端開發(fā)使用頻率較高的場景。

進(jìn)程間通信方式主要有命名管道、消息隊(duì)列、共享內(nèi)存、Socket通信,個人使用最多的是Sokcet相關(guān)。

而Socket也有很多使用方式,Socket、WebSocket、TcpClient、UdpClient,是不是很多?HttpClient與TcpClient、WebSocket之間有什么關(guān)系?這里我們分別介紹下這些通信及使用方式

Socket

Socket是傳輸通信協(xié)議么?No,Socket是一種傳輸層和應(yīng)用層之間、用于實(shí)現(xiàn)網(wǎng)絡(luò)通信的編程接口。Socket可以使用各種協(xié)議如TCP、UDP協(xié)議實(shí)現(xiàn)進(jìn)程通信,TCP/UDP才是傳輸通信協(xié)議

Socket位于傳輸層與應(yīng)用層之間,接口在System.Net.Sockets命名空間下。下面是Socket以TCP通信的DEMO:    

//創(chuàng)建一個 Socket 實(shí)例

    Socket clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

    

    //連接到服務(wù)器

    clientSocket.Connect(new IPEndPoint(IPAddress.Parse("127.0.0.1"), 8000));

    

    //發(fā)送數(shù)據(jù)

    string message = "Hello, Server!";

    byte[] data = Encoding.ASCII.GetBytes(message);

    clientSocket.Send(data);

    

    //接收數(shù)據(jù)

    byte[] buffer = new byte[1024];

    int bytesRead = clientSocket.Receive(buffer);

    Debug.WriteLine(Encoding.ASCII.GetString(buffer, 0, bytesRead));

    

    clientSocket.Close();

TcpClient/UdpClient

TCP/UDP均是位于傳輸層的通信協(xié)議,所以Socket的使用也是位于傳輸層的通信操作

TCP是面向連接,提供可靠、順序的數(shù)據(jù)流傳輸。用于一對一的通信,即一個TCP連接只能有一個發(fā)送方和一個接收方。詳細(xì)連接方式是,先通過三次握手建立連接、然后傳輸數(shù)據(jù),傳輸數(shù)據(jù)完再通過4次揮手關(guān)閉連接。所以適用于需要數(shù)據(jù)完整性和可靠傳輸?shù)膱鼍?/p>

而UDP則是無連接的,不需要建立和維護(hù)連接狀態(tài),不提供確認(rèn)機(jī)制,也不重傳丟失的數(shù)據(jù)報,但也因此傳輸實(shí)時性高,適合低延時、數(shù)據(jù)量小、廣播場景

基于Socket抽象編程接口,TCP、UDP構(gòu)建更高級別抽象網(wǎng)絡(luò)編程TcpClient、UdpClient,它們用于簡化TCP網(wǎng)絡(luò)編程中的常見任務(wù)

TcpClient、UdpClient是 .NET 提供的用于方便管理TCP和UDP網(wǎng)絡(luò)通信的類,下面是對應(yīng)的Demo

Tcp服務(wù)端: 

using System;

using System.Net;

using System.Net.Sockets;

using System.Text;


class TcpServerExample

{

    public static void Main()

    {

        TcpListener listener = new TcpListener(“127.0.0.1", 8000);

        listener.Start();

        Console.WriteLine("Server is listening on port 8000...");


        TcpClient client = listener.AcceptTcpClient();

        NetworkStream stream = client.GetStream();


        byte[] data = new byte[1024];

        int bytesRead = stream.Read(data, 0, data.Length);

        Console.WriteLine("Received: " + Encoding.ASCII.GetString(data, 0, bytesRead));


        byte[] response = Encoding.ASCII.GetBytes("Hello, Client!");

        stream.Write(response, 0, response.Length);


        stream.Close();

        client.Close();

        listener.Stop();

    }

}

TCP客戶端: 

using System;

using System.Net.Sockets;

using System.Text;


class TcpClientExample

{

    public static void Main()

    {

        TcpClient client = new TcpClient("127.0.0.1", 8000);

        NetworkStream stream = client.GetStream();


        byte[] message = Encoding.ASCII.GetBytes("Hello, Server!");

        stream.Write(message, 0, message.Length);


        byte[] data = new byte[1024];

        int bytesRead = stream.Read(data, 0, data.Length);

        Debug.WriteLine("Received: " + Encoding.ASCII.GetString(data, 0, bytesRead));


        stream.Close();

        client.Close();

    }

}

Udp服務(wù)端: 

using System;

using System.Net;

using System.Net.Sockets;

using System.Text;


class UdpServerExample

{

    public static void Main()

    {

        UdpClient udpServer = new UdpClient(8000);

        IPEndPoint remoteEP = new IPEndPoint(”127.0.0.1“, 0);


        Console.WriteLine("Server is listening on port 8000...");


        byte[] data = udpServer.Receive(ref remoteEP);

        Console.WriteLine("Received: " + Encoding.ASCII.GetString(data));


        byte[] response = Encoding.ASCII.GetBytes("Hello, Client!");

        udpServer.Send(response, response.Length, remoteEP);


        udpServer.Close();

    }

}

Udp客戶端:

using System;

using System.Net;

using System.Net.Sockets;

using System.Text;


class UdpClientExample

{

    public static void Main()

    {

        UdpClient udpClient = new UdpClient();

        IPEndPoint remoteEP = new IPEndPoint(”127.0.0.1", 8000);


        byte[] message = Encoding.ASCII.GetBytes("Hello, Server!");

        udpClient.Send(message, message.Length, remoteEP);


        byte[] data = udpClient.Receive(ref remoteEP);

        Console.WriteLine("Received: " + Encoding.ASCII.GetString(data));


        udpClient.Close();

    }

}

上面是基本的網(wǎng)絡(luò)通信DEMO,TcpClient用于基于連接、可靠的TCP通信,適用于需要數(shù)據(jù)完整性和可靠傳輸?shù)膱鼍啊dp用于無連接、不保證傳輸?shù)腢DP通信,適用于對實(shí)時性要求高、允許少量數(shù)據(jù)丟失的場景(如視頻流)。會議場景下的傳屏軟件適合用這個協(xié)議,傳屏發(fā)送端固定幀率一直推送,網(wǎng)絡(luò)丟失幾幀問題不大,重要的是延時低了很多。

TcpClient、UdpClient是位于傳輸層的通信類,分別實(shí)現(xiàn)了基于TCP和UDP協(xié)議的通信功能。

HttpClient

講完傳輸層的網(wǎng)絡(luò)通信類,就要說下應(yīng)用層的HttpClient,這是專門用于HTTP協(xié)議的通信

Http與TCP/UDP均是網(wǎng)絡(luò)通信協(xié)議,TCP、UDP位于傳輸層,HTTP傳于應(yīng)用層,而且HTTP是基于TCP面向連接的,它是客戶端單向發(fā)起的半雙工協(xié)議。HTTP1.1之后引入持久連接,允許一個TCP連接進(jìn)行多次請求/響應(yīng)傳輸。HTTP層相比TCP它關(guān)注請求、響應(yīng)的內(nèi)容

HttpClient是Http協(xié)議的通信類,提供了封裝好的、高級的HTTP功能(如發(fā)起GET, POST請求,處理響應(yīng)等)。

HttpClient可以用于Web接口如Restful API的調(diào)用,我這邊Windows應(yīng)用的WebApi基礎(chǔ)組件庫就是用HttpClient實(shí)現(xiàn)的。

HttpClient類,在System.Net.Http.HttpClient命名空間下,HttpClient的內(nèi)部實(shí)現(xiàn)是基于Socket的。也就是說,HttpClient底層使用Socket接口來建立連接并傳輸數(shù)據(jù),但它隱藏了這些細(xì)節(jié),為開發(fā)者提供了一個更簡潔的API。

下面是我基于HttpClient實(shí)現(xiàn)的Web服務(wù)各類操作入口代碼,可以簡單瀏覽下: 

/// <summary>

        /// 請求/推送數(shù)據(jù)

        /// </summary>

        /// <typeparam name="TResponse"></typeparam>

        /// <param name="request"></param>

        /// <returns></returns>

        public async Task<TResponse> RequestAsync<TResponse>(HttpRequest request) where TResponse : HttpResponse, new()

        {

            var requestUrl = request.GetRequestUrl();

            try

            {

                using var client = CreateHttpClient(request);

                var requestMethod = request.GetRequestMethod();

                switch (requestMethod)

                {

                    case RequestMethod.Get:

                        {

                            using var response = await client.GetAsync(requestUrl);

                            return await response.GetTResponseAsync<TResponse>();

                        }

                    case RequestMethod.Post:

                        {

                            using var httpContent = request.GetHttpContent();

                            using var response = await client.PostAsync(requestUrl, httpContent);

                            return await response.GetTResponseAsync<TResponse>();

                        }

                    case RequestMethod.Put:

                        {

                            using var httpContent = request.GetHttpContent();

                            using var response = await client.PutAsync(requestUrl, httpContent);

                            return await response.GetTResponseAsync<TResponse>();

                        }

                    case RequestMethod.Delete:

                        {

                            using var response = await client.DeleteAsync(requestUrl);

                            return await response.GetTResponseAsync<TResponse>();

                        }

                    case RequestMethod.PostForm:

                        {

                            using var requestMessage = new HttpRequestMessage(HttpMethod.Post, requestUrl);

                            using var httpContent = request.GetHttpContent();

                            requestMessage.Content = httpContent;

                            using var response = await client.SendAsync(requestMessage);

                            return await response.GetTResponseAsync<TResponse>();

                        }

                }

                return new TResponse() { Message = $"不支持的請求類型:{requestMethod}" };

            }

            catch (ArgumentNullException e)

            {

                return new TResponse() { Code = NetErrorCodes.ParameterError, Message = e.Message, JsonData = e.StackTrace };

            }

            catch (TimeoutException e)

            {

                return new TResponse() { Code = NetErrorCodes.TimeOut, Message = e.Message, JsonData = e.StackTrace };

            }

            catch (Exception e)

            {

                return new TResponse() { Message = e.Message, JsonData = e.StackTrace };

            }

        }

HttpClient封裝后的網(wǎng)絡(luò)基礎(chǔ)組件調(diào)用方式,也比較簡單。

添加接口請求說明,參數(shù)及請求參數(shù)均統(tǒng)一在一個類文件里定義好: 

/// <summary>

/// 內(nèi)網(wǎng)穿透注冊接口

/// </summary>

[Request("http://frp.supporter.ws.h3c.com/user/register",RequestMethod.Post)]

[DataContract]

internal class RegisterFrpRequest : HttpRequest

{

    public RegisterFrpRequest(string sn, string appName)

    {

        Sn = sn;

        SeverNames = new List<RequestServiceName>()

        {

            new RequestServiceName(appName,"http")

        };

    }

    [DataMember(Name = "sn")]

    public string Sn { get; set; }


    [DataMember(Name = "localServerNames")]

    public List<RequestServiceName> SeverNames { get; set; }

}

再定義請求結(jié)果返回數(shù)據(jù),基類HttpResponse內(nèi)有定義基本參數(shù),狀態(tài)Success、狀態(tài)碼Code、返回描述信息Message: 

[DataContract]

class RegisterFrpResponse : HttpResponse

{


    [DataMember(Name = "correlationId")]

    public string CorrelationId { get; set; }


    [DataMember(Name = "data")]

    public FrpRegisterData Data { get; set; }


    /// <summary>

    /// 是否成功

    /// </summary>

    public bool IsSuccess => Success && Code == 200000 && Data != null;

}

然后,業(yè)務(wù)層可以進(jìn)行簡潔、高效率的調(diào)用:

var netClient = new NetHttpClient();

var response = await netClient.RequestAsync<RegisterFrpResponse>(new RegisterFrpRequest(sn, appName));

如果僅僅只是Data數(shù)據(jù),可以只定義數(shù)據(jù)類型,然后使用泛型HttpResponse作為返回數(shù)據(jù)。

var response1 = await netClient.RequestAsync<HttpResponse<VersionInfo>>(new AppVersionRequest(appId));

WebSocket

WebSocket也是一個應(yīng)用層通信,不同于可以實(shí)現(xiàn)倆類協(xié)議TCP/UDP的Socket,WebSocket是以HTTP/HTTPS連接、以TCP傳輸數(shù)據(jù)。

一旦握手成功,客戶端和服務(wù)器之間可以進(jìn)行雙向數(shù)據(jù)傳輸,可以傳輸字節(jié)數(shù)據(jù)也可以傳輸文本內(nèi)容。

持久連接:WebSocket 是持久化連接,除非主動關(guān)閉,否則在整個會話期間連接保持開放。

全雙工通信:客戶端和服務(wù)器可以隨時發(fā)送數(shù)據(jù),通信不再是單向的。使用System.Net.WebSockets.ClientWebSocket類來實(shí)現(xiàn)WebSocket通信,通過減少 HTTP 請求/響應(yīng)的開銷、延時較低。

而WebSocket與HttpClient呢,都用于應(yīng)用層的網(wǎng)絡(luò)通信,但它們的用途和通信協(xié)議是不同的。

HttpClient使用 HTTP 協(xié)議,WebSocket使用WebSocket協(xié)議,該協(xié)議在初始連接時通過 HTTP/HTTPS握手,然后轉(zhuǎn)換為基于TCP通信的WebSocket協(xié)議。所以雖然都有使用HTTP協(xié)議,但WebSocket后續(xù)就切換至基于TCP的全雙工通信了

HttpClient基于請求/響應(yīng)模式,每次通信由客戶端向服務(wù)器發(fā)起請求。WebSocket提供全雙工通信,客戶端和服務(wù)器都可以主動發(fā)送數(shù)據(jù)。

HttpClient主要用于訪問 RESTful API、下載文件或者發(fā)送HTTP請求。WebSocket主要用于實(shí)現(xiàn)低延遲的實(shí)時通信,如進(jìn)程間通信、局域網(wǎng)通信等。

我團(tuán)隊(duì)Windows應(yīng)用所使用的進(jìn)程間通信,就是基于WebSocketSharp封裝的。WebSocketSharp是一個功能全面、易于使用的第三方 WebSocket 庫 GitHub - sta/websocket-sharp

至于為啥不直接使用ClientWebSocket。。。是因?yàn)楫?dāng)時團(tuán)隊(duì)還未切換.NET,使用的是.NETFramework。

后面團(tuán)隊(duì)使用的局域網(wǎng)通信基礎(chǔ)組件就是用ClientWebSocket了。

下面是我封裝的部分WebSocket通信代碼,事件發(fā)送(廣播)、以及監(jiān)聽其它客戶端發(fā)送過來的事件消息:

/// <summary>

    /// 發(fā)送消息

    /// </summary>

    /// <typeparam name="TInput">發(fā)送參數(shù)類型</typeparam>

    /// <param name="client">目標(biāo)客戶端</param>

    /// <param name="innerEvent">事件名</param>

    /// <param name="data">發(fā)送參數(shù)</param>

    /// <returns></returns>

    public async Task<ClientResponse> SendAsync<TInput>(string client, InnerEventItem innerEvent, TInput data)

    {

        var message = new ChannelSendingMessage(client, new ClientEvent(innerEvent.EventName, innerEvent.EventId, true), _sourceClient);

        message.SetData<TInput>(data);

        return await SendMessageAsync(ChannelMessageType.ClientCommunication, message);

    }


    /// <summary>

    /// 訂閱消息

    /// </summary>

    /// <param name="client">目標(biāo)客戶端</param>

    /// <param name="innerEvent">事件名稱</param>

    /// <param name="func">委托</param>

    public ClientSubscribedEvent SubscribeFunc(string client, InnerEventItem innerEvent, Func<ClientResponse, object> func)

    {

        var eventName = innerEvent?.EventName;

        if (string.IsNullOrEmpty(eventName) || func == null)

        {

            throw new ArgumentNullException($"{nameof(eventName)}或{nameof(func)},參數(shù)不能為空!");

        }


        var subscribedEvent = new ClientSubscribedEvent(client, innerEvent, func);

        SubscribeEvent(subscribedEvent);

        return subscribedEvent;

    }

    /// <summary>

    /// 訂閱消息

    /// </summary>

    /// <param name="client">目標(biāo)客戶端</param>

    /// <param name="innerEvent">事件名稱</param>

    /// <param name="func">委托</param>

    public ClientSubscribedEvent SubscribeFuncTask(string client, InnerEventItem innerEvent, Func<ClientResponse, Task<object>> func)

    {

        var eventName = innerEvent?.EventName;

        if (string.IsNullOrEmpty(eventName) || func == null)

        {

            throw new ArgumentNullException($"{nameof(eventName)}或{nameof(func)},參數(shù)不能為空!");

        }


        var subscribedEvent = new ClientSubscribedEvent(client, innerEvent, func);

        SubscribeEvent(subscribedEvent);

        return subscribedEvent;

    }


    /// <summary>

    /// 訂閱消息

    /// </summary>

    /// <param name="client">目標(biāo)客戶端</param>

    /// <param name="innerEvent">事件名稱</param>

    /// <param name="action">委托</param>

    public ClientSubscribedEvent Subscribe(string client, InnerEventItem innerEvent, Action<ClientResponse> action)

    {

        var eventName = innerEvent?.EventName;

        if (string.IsNullOrEmpty(eventName) || action == null)

        {

            throw new ArgumentNullException($"{nameof(eventName)}或{nameof(action)},參數(shù)不能為空!");

        }


        var subscribedEvent = new ClientSubscribedEvent(client, innerEvent, action);

        SubscribeEvent(subscribedEvent);

        return subscribedEvent;

    }


作者:唐宋元明清2188
出處:http://www.cnblogs.com/kybs0/
本文版權(quán)歸作者和博客園共有,歡迎轉(zhuǎn)載,但未經(jīng)作者同意必須在文章頁面給出原文連接,否則保留追究法律責(zé)任的權(quán)利。



該文章在 2024/9/5 11:46:49 編輯過
關(guān)鍵字查詢
相關(guān)文章
正在查詢...
點(diǎn)晴ERP是一款針對中小制造業(yè)的專業(yè)生產(chǎn)管理軟件系統(tǒng),系統(tǒng)成熟度和易用性得到了國內(nèi)大量中小企業(yè)的青睞。
點(diǎn)晴PMS碼頭管理系統(tǒng)主要針對港口碼頭集裝箱與散貨日常運(yùn)作、調(diào)度、堆場、車隊(duì)、財務(wù)費(fèi)用、相關(guān)報表等業(yè)務(wù)管理,結(jié)合碼頭的業(yè)務(wù)特點(diǎn),圍繞調(diào)度、堆場作業(yè)而開發(fā)的。集技術(shù)的先進(jìn)性、管理的有效性于一體,是物流碼頭及其他港口類企業(yè)的高效ERP管理信息系統(tǒng)。
點(diǎn)晴WMS倉儲管理系統(tǒng)提供了貨物產(chǎn)品管理,銷售管理,采購管理,倉儲管理,倉庫管理,保質(zhì)期管理,貨位管理,庫位管理,生產(chǎn)管理,WMS管理系統(tǒng),標(biāo)簽打印,條形碼,二維碼管理,批號管理軟件。
點(diǎn)晴免費(fèi)OA是一款軟件和通用服務(wù)都免費(fèi),不限功能、不限時間、不限用戶的免費(fèi)OA協(xié)同辦公管理系統(tǒng)。
Copyright 2010-2025 ClickSun All Rights Reserved

主站蜘蛛池模板: 国产一级a毛一级a视频 | 国产v综合v亚洲欧美大另类 | 在线观看视频 | 好看的电影电视剧大全 | 欧美综合激情网 | 韩精品欧美综合区 | 成人国产欧美大片一区 | 国产精品亚洲专区在线观看 | 欧美性黑人极品hd另类 | 91视频国产大片 | 一区二区三区在线免费看 | 免费看黑人 | 日韩电影大片手机在线观看 | 起碰视频在线 | 综合亚洲欧美日韩一区二区 | 欧美有色 | 性一交一乱一伦一 | 亚洲成a人片在线v | 亚洲欧美国产精品制服 | 国产在线观看一级二级三级 | 国产网站大全在线观看 | 亚洲一区二区在线播放 | 亚洲精品福利电影在线观看 | 亚洲偷自拍拍综合网 | 人成综合网络 | 国产精品美脚玉 | 中文字幕日产熟女乱码 | 日韩欧美国产偷亚洲清高 | 亚洲国产高清在线不卡 | 国产欧美日本韩国另类 | 国产精品综合色区在线观看 | 免费在线观看a视频 | 色狗电影网 | 高清欧美日韩 | 大地影院mv在线观看视频免费 | 欧美浓毛 | 在野外被三个男人躁一夜 | 最新国产99热这里只有精品 | 亚洲日韩天堂网中文字幕 | 亚洲人成网线在线播放va | 国产日本欧美在线一区二区 |