自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

UNIX Socket:不同進(jìn)程之間能夠直接交換數(shù)據(jù)進(jìn)行進(jìn)程間通信(IPC)

開(kāi)發(fā) 前端
UNIX Socket基于文件系統(tǒng)的抽象概念,使用一個(gè)特殊的文件來(lái)表示套接字。與網(wǎng)絡(luò)套接字不同,UNIX Socket僅限于同一主機(jī)上的進(jìn)程間通信,不涉及網(wǎng)絡(luò)協(xié)議棧的使用。

UNIX socket概念

UNIX Socket(也稱(chēng)為本地套接字或IPC套接字)是一種在同一臺(tái)計(jì)算機(jī)上進(jìn)行進(jìn)程間通信(IPC)的機(jī)制。它提供了一種可靠而高效的方式,使不同進(jìn)程之間能夠直接交換數(shù)據(jù)。UNIX Socket基于文件系統(tǒng)的抽象概念,使用一個(gè)特殊的文件來(lái)表示套接字。與網(wǎng)絡(luò)套接字不同,UNIX Socket僅限于同一主機(jī)上的進(jìn)程間通信,不涉及網(wǎng)絡(luò)協(xié)議棧的使用。

UNIX socket特點(diǎn)

同步和異步通信

UNIX Socket允許進(jìn)程進(jìn)行同步或異步通信。對(duì)于同步通信,發(fā)送進(jìn)程會(huì)阻塞直到接收進(jìn)程接收到數(shù)據(jù);對(duì)于異步通信,發(fā)送進(jìn)程可以繼續(xù)執(zhí)行其他任務(wù)而不需要等待接收進(jìn)程響應(yīng)。

全雙工通信

UNIX Socket允許進(jìn)程在同一個(gè)套接字上進(jìn)行雙向通信,既可以發(fā)送數(shù)據(jù)也可以接收數(shù)據(jù)。

面向字節(jié)流

UNIX Socket以字節(jié)流的形式傳輸數(shù)據(jù),不關(guān)心數(shù)據(jù)的消息邊界。這意味著發(fā)送的數(shù)據(jù)可以分割成多個(gè)部分,也可以將多個(gè)消息組合成一個(gè)單獨(dú)的數(shù)據(jù)塊。

高性能

由于UNIX Socket只涉及本地通信,沒(méi)有網(wǎng)絡(luò)協(xié)議的開(kāi)銷(xiāo),因此它通常比網(wǎng)絡(luò)套接字更高效。

UNIX socket優(yōu)勢(shì)

由于UNIX Socket 使用套接字的概念,類(lèi)似于網(wǎng)絡(luò)套接字,但其使用的是文件系統(tǒng)路徑而不是IP地址和端口號(hào)。 UNIX Socket 具有以下優(yōu)點(diǎn):

  • 可靠性:UNIX Socket 提供可靠的進(jìn)程間通信機(jī)制,數(shù)據(jù)傳輸過(guò)程中會(huì)進(jìn)行錯(cuò)誤檢測(cè)和重傳,確保數(shù)據(jù)的完整性和可靠性。
  • 高效性:UNIX Socket 是基于內(nèi)核的通信機(jī)制,數(shù)據(jù)傳輸過(guò)程中減少了不必要的數(shù)據(jù)拷貝,使得數(shù)據(jù)傳輸更加高效。
  • 低延遲:由于 UNIX Socket 在內(nèi)核層面實(shí)現(xiàn),數(shù)據(jù)傳輸不需要經(jīng)過(guò)網(wǎng)絡(luò)協(xié)議棧,因此具有較低的延遲。
  • 安全性:UNIX Socket 基于文件系統(tǒng)路徑進(jìn)行通信,只有相應(yīng)權(quán)限的進(jìn)程才能進(jìn)行通信,增強(qiáng)了通信的安全性。
  • 靈活性:UNIX Socket 可以在同一臺(tái)計(jì)算機(jī)上的不同進(jìn)程之間進(jìn)行通信,使得進(jìn)程間的交互更加靈活。
  • 支持多種編程語(yǔ)言:UNIX Socket 可以在多種編程語(yǔ)言中使用,如C/C++、Python等,使得不同語(yǔ)言的進(jìn)程之間可以進(jìn)行通信。
  • 跨平臺(tái)兼容性:盡管名字中包含 UNIX,但 UNIX Socket 在許多操作系統(tǒng)上都有支持,包括 Linux、macOS 等。

UNIX Socket適用場(chǎng)景

UNIX Socket可以在不同編程語(yǔ)言中使用,并且廣泛應(yīng)用于各種場(chǎng)景,例如:

  • 進(jìn)程間通信(IPC):不同進(jìn)程之間通過(guò)UNIX Socket進(jìn)行數(shù)據(jù)交換,例如父子進(jìn)程、無(wú)關(guān)進(jìn)程或者共享內(nèi)存的進(jìn)程之間。
  • 本地服務(wù)器和客戶(hù)端:UNIX Socket可用于構(gòu)建本地服務(wù)器,接受來(lái)自客戶(hù)端的連接請(qǐng)求并提供服務(wù)。
  • 網(wǎng)絡(luò)編程的模擬和測(cè)試:在本地開(kāi)發(fā)環(huán)境中,使用UNIX Socket可以模擬網(wǎng)絡(luò)連接,方便進(jìn)行調(diào)試和測(cè)試。
  • 守護(hù)進(jìn)程和系統(tǒng)服務(wù):UNIX Socket作為進(jìn)程間通信的一種方式,可用于實(shí)現(xiàn)守護(hù)進(jìn)程和系統(tǒng)服務(wù)之間的通信。

UNIX Socket 步驟

創(chuàng)建 Socket:

  • 使用 `socket()` 函數(shù)創(chuàng)建一個(gè)套接字,指定協(xié)議組、類(lèi)型和協(xié)議。
  • 常見(jiàn)的協(xié)議族有 `AF_UNIX`(用于 UNIX 域套接字)和 `AF_INET`(用于網(wǎng)絡(luò)套接字)。
  • 常見(jiàn)的類(lèi)型有 `SOCK_STREAM`(用于可靠的面向連接的通信)和 `SOCK_DGRAM`(用于無(wú)連接的通信)。

綁定 Socket 到地址:

  • 對(duì)于 UNIX 域套接字,使用 `bind()` 函數(shù)將套接字綁定到一個(gè)文件路徑。
  • 對(duì)于網(wǎng)絡(luò)套接字,使用 `bind()` 函數(shù)將套接字綁定到一個(gè) IP 地址和端口號(hào)。

 監(jiān)聽(tīng)連接請(qǐng)求(對(duì)于面向連接型套接字):

  • 對(duì)于 UNIX 域套接字,使用 `listen()` 函數(shù)開(kāi)始監(jiān)聽(tīng)連接請(qǐng)求。
  • 對(duì)于網(wǎng)絡(luò)套接字,使用 `listen()` 函數(shù)并指定最大等待連接數(shù)量。

接受連接請(qǐng)求(對(duì)于面向連接型套接字):

  • 使用 `accept()` 函數(shù)接受客戶(hù)端的連接請(qǐng)求,并創(chuàng)建一個(gè)新的套接字用于與客戶(hù)端進(jìn)行通信。

進(jìn)行數(shù)據(jù)傳輸:

  • 對(duì)于面向連接型套接字,使用 `send()` 和 `recv()` 函數(shù)在客戶(hù)端和服務(wù)器之間進(jìn)行數(shù)據(jù)傳輸。
  • 對(duì)于無(wú)連接型套接字,可以使用 `sendto()` 和 `recvfrom()` 函數(shù)進(jìn)行數(shù)據(jù)傳輸。

關(guān)閉 Socket:

  • 使用 `close()` 函數(shù)關(guān)閉套接字,釋放相關(guān)資源。

WPF 接入 UNIX Socket 開(kāi)發(fā)案例

在WPF應(yīng)用程序中創(chuàng)建UNIX Socket的服務(wù)端和客戶(hù)端,可以使用System.Net.Sockets.Socket類(lèi)。

服務(wù)端(Server):

using System;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
using System.Windows;

namespace UnixSocketExample
{
    public partial class MainWindow : Window
    {
        private const string SocketFilePath = "/path/to/unix/socket"; // UNIX Socket文件路徑

        public MainWindow()
        {
            InitializeComponent();
        }

        private async void StartButton_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                var socket = new Socket(AddressFamily.Unix, SocketType.Stream, ProtocolType.Unspecified);

                // 如果Socket文件已存在,則先刪除
                if (System.IO.File.Exists(SocketFilePath))
                {
                    System.IO.File.Delete(SocketFilePath);
                }

                // 綁定并開(kāi)始監(jiān)聽(tīng)UNIX Socket
                socket.Bind(new UnixDomainSocketEndPoint(SocketFilePath));
                socket.Listen(1);

                await Task.Run(() =>
                {
                    while (true)
                    {
                        var clientSocket = socket.Accept(); // 接受客戶(hù)端連接

                        byte[] buffer = Encoding.ASCII.GetBytes("Hello from server"); // 要發(fā)送的數(shù)據(jù)
                        clientSocket.Send(buffer); // 向客戶(hù)端發(fā)送數(shù)據(jù)

                        clientSocket.Close(); // 關(guān)閉客戶(hù)端連接
                    }
                });
            }
            catch (Exception ex)
            {
                MessageBox.Show($"Error: {ex.Message}", "Server Error", MessageBoxButton.OK, MessageBoxImage.Error);
            }
        }
    }
}

客戶(hù)端(Client):

using System;
using System.Net.Sockets;
using System.Text;
using System.Windows;

namespace UnixSocketExample
{
    public partial class MainWindow : Window
    {
        private const string SocketFilePath = "/path/to/unix/socket"; // UNIX Socket文件路徑

        public MainWindow()
        {
            InitializeComponent();
        }

        private void ConnectButton_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                var socket = new Socket(AddressFamily.Unix, SocketType.Stream, ProtocolType.Unspecified);

                socket.Connect(new UnixDomainSocketEndPoint(SocketFilePath)); // 連接到服務(wù)端

                byte[] buffer = new byte[1024];
                int bytesRead = socket.Receive(buffer); // 接收數(shù)據(jù)
                string receivedData = Encoding.ASCII.GetString(buffer, 0, bytesRead);

                ReceiveTextBox.Text = receivedData; // 顯示接收到的數(shù)據(jù)

                socket.Close(); // 關(guān)閉客戶(hù)端連接
            }
            catch (Exception ex)
            {
                MessageBox.Show($"Error: {ex.Message}", "Connection Error", MessageBoxButton.OK, MessageBoxImage.Error);
            }
        }
    }
}

在這個(gè)例子中,主窗口分別包含一個(gè)“Start”按鈕(服務(wù)端)和一個(gè)“Connect”按鈕(客戶(hù)端),以及一個(gè)用于展示接收到的數(shù)據(jù)的文本框。服務(wù)端代碼負(fù)責(zé)創(chuàng)建UNIX Socket并綁定到指定的文件路徑,然后開(kāi)始監(jiān)聽(tīng)連接請(qǐng)求。當(dāng)客戶(hù)端連接時(shí),服務(wù)端向客戶(hù)端發(fā)送一條消息,并關(guān)閉連接??蛻?hù)端代碼負(fù)責(zé)連接到服務(wù)端的UNIX Socket,接收服務(wù)端發(fā)送的數(shù)據(jù),并將接收到的數(shù)據(jù)顯示在文本框中。

UNIX Socket進(jìn)程間通信之序列化

使用UNIX Socket進(jìn)行進(jìn)程間通信時(shí),序列化是一個(gè)重要的問(wèn)題。由于UNIX Socket只能傳輸字節(jié)流,而對(duì)象是無(wú)法直接傳輸?shù)?,因此需要將?duì)象進(jìn)行序列化成字節(jié)流再傳輸,接收方接收到字節(jié)流后再進(jìn)行反序列化還原為對(duì)象。常用的解決方案有:

  • 選擇合適的序列化方式:在.NET框架中有多種序列化方式可供選擇,例如XML序列化、JSON序列化和二進(jìn)制序列化等。您可以根據(jù)實(shí)際需求選擇適合的序列化方式。注意,需要確保序列化方式在進(jìn)程間通信中是兼容的。
  • 定義數(shù)據(jù)傳輸?shù)臄?shù)據(jù)結(jié)構(gòu):使用類(lèi)或結(jié)構(gòu)體來(lái)定義數(shù)據(jù)傳輸?shù)母袷胶徒Y(jié)構(gòu)。這些類(lèi)或結(jié)構(gòu)體需要進(jìn)行序列化和反序列化。
  • 序列化和反序列化:在發(fā)送方,將要傳輸?shù)膶?duì)象進(jìn)行序列化成字節(jié)流,并通過(guò)UNIX Socket發(fā)送;在接收方,接收到字節(jié)流后進(jìn)行反序列化還原為對(duì)象。

案例演示如何使用BinaryFormatter進(jìn)行對(duì)象的二進(jìn)制序列化和反序列化:

using System;
using System.IO;
using System.Net.Sockets;
using System.Runtime.Serialization.Formatters.Binary;

// 發(fā)送方
var socket = new Socket(AddressFamily.Unix, SocketType.Stream, ProtocolType.Unspecified);
socket.Connect(new UnixDomainSocketEndPoint("/path/to/unix/socket"));

var data = new MyData { Name = "Alice", Age = 30 }; // 要傳輸?shù)膶?duì)象

var formatter = new BinaryFormatter();
using (var stream = new MemoryStream())
{
    formatter.Serialize(stream, data); // 對(duì)象序列化到內(nèi)存流中
    var buffer = stream.ToArray(); // 獲取字節(jié)流數(shù)據(jù)
    socket.Send(buffer); // 發(fā)送字節(jié)流
}

socket.Close();

// 接收方
var listener = new Socket(AddressFamily.Unix, SocketType.Stream, ProtocolType.Unspecified);
listener.Bind(new UnixDomainSocketEndPoint("/path/to/unix/socket"));
listener.Listen(1);

var clientSocket = listener.Accept();
var receivedBuffer = new byte[1024];
var bytesRead = clientSocket.Receive(receivedBuffer); // 接收字節(jié)流

using (var stream = new MemoryStream(receivedBuffer, 0, bytesRead))
{
    var receivedData = formatter.Deserialize(stream) as MyData; // 字節(jié)流反序列化為對(duì)象
    Console.WriteLine($"Received: {receivedData.Name}, {receivedData.Age}");
}

clientSocket.Close();
listener.Close();

// 要傳輸?shù)臄?shù)據(jù)結(jié)構(gòu)
[Serializable]
public class MyData
{
    public string Name { get; set; }
    public int Age { get; set; }
}

在這個(gè)示例中,發(fā)送方將MyData對(duì)象進(jìn)行二進(jìn)制序列化,并通過(guò)UNIX Socket發(fā)送字節(jié)流。接收方接收到字節(jié)流后,使用相同的二進(jìn)制序列化方式進(jìn)行反序列化還原為MyData對(duì)象。要注意的是,由于不同平臺(tái)和不同開(kāi)發(fā)環(huán)境的序列化機(jī)制可能存在差異,因此在進(jìn)行跨平臺(tái)的進(jìn)程間通信時(shí),需要確保序列化方式的兼容性。另外,如果要序列化的對(duì)象是自定義類(lèi)或結(jié)構(gòu)體,需要將其標(biāo)記為可序列化(使用[Serializable]特性)才能進(jìn)行序列化和反序列化操作。

責(zé)任編輯:姜華 來(lái)源: 今日頭條
相關(guān)推薦

2019-11-08 14:47:49

TCPIP網(wǎng)絡(luò)

2019-11-27 10:36:11

進(jìn)程通信IPC

2021-02-14 21:05:05

通信消息系統(tǒng)

2017-08-06 00:05:18

進(jìn)程通信開(kāi)發(fā)

2011-08-08 10:02:55

iPhone開(kāi)發(fā) 進(jìn)程 通信

2024-07-12 08:22:05

C#SendMessag技術(shù)

2010-01-05 10:00:48

Linux進(jìn)程間通信

2023-09-13 08:33:17

2020-11-04 07:17:42

Nodejs通信進(jìn)程

2011-06-22 17:09:50

QT 進(jìn)程 通信

2023-05-10 07:53:08

.Net開(kāi)發(fā)多進(jìn)程通信方式

2024-08-28 14:13:26

2023-02-03 17:28:44

HIDLAndroid硬件

2020-11-18 09:06:04

Python

2021-09-30 10:45:33

Linux進(jìn)程通信

2013-03-28 13:14:45

AIDL進(jìn)程間通信Android使用AI

2018-01-12 14:35:00

Linux進(jìn)程共享內(nèi)存

2017-06-19 13:36:12

Linux進(jìn)程消息隊(duì)列

2019-07-09 10:31:51

面試通信進(jìn)程

2021-07-07 20:29:20

Socket進(jìn)程遷移
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)