C 使用mkfifo在linux和dotnet之间进行进程间通信

C 使用mkfifo在linux和dotnet之间进行进程间通信,c,.net-core,ipc,mkfifo,C,.net Core,Ipc,Mkfifo,我们有一个用c编写的应用程序,它向用c#编写的应用程序发送事件/通知。两个应用程序都在同一台linux计算机上运行 C应用程序: C应用程序是开放的,我们修改了源代码(它是开源的),以便它可以向我们的dotnet控制台应用程序发送事件。我们当前发送事件的方式只是将文本附加到文件中。例如,这是我们发送新对等方(ip电话)连接的事件的方式: // place this on chan_sip.c // Example: 1-LN-48T6-E3C5-OFWT|10.0.0.103:5868|189.

我们有一个用c编写的应用程序,它向用c#编写的应用程序发送事件/通知。两个应用程序都在同一台linux计算机上运行

C应用程序:

C应用程序是开放的,我们修改了源代码(它是开源的),以便它可以向我们的dotnet控制台应用程序发送事件。我们当前发送事件的方式只是将文本附加到文件中。例如,这是我们发送新对等方(ip电话)连接的事件的方式:

// place this on chan_sip.c
// Example: 1-LN-48T6-E3C5-OFWT|10.0.0.103:5868|189.217.18.244|10216|Z 3.9.32144 r32121
if(!ast_sockaddr_isnull(&peer->addr))
{
    // lock 
    ast_mutex_lock(&some_lock);

        // write to file
        FILE *pFile;
        pFile=fopen("/var/log/asterisk/peer-subscriptions.txt", "a");
        if(pFile==NULL) { perror("Error opening file."); }
        else {
                fprintf(pFile,"%s|%s|%s|%s|%s\n",
                /* 1-LN-48T6-E3C5-OFWT */   peer->name,
                /* 10.0.0.103:5868     */   pvt->initviasentby,
                /* 189.217.18.244      */   ast_sockaddr_stringify_addr(&peer->addr),
                /* 10216               */   ast_strdupa(ast_sockaddr_stringify_port(&peer->addr)),
                /* Z 3.9.32144         */   peer->useragent
                    // Other:
                    // peer->fullcontact, // sip:1-LN-48T6-E3C5-OFWT@189.217.18.244:10216;rinstance=8b4135488f735cbf;transport=UDP
                    // pvt->via      //  SIP/2.0/UDP 54.81.92.135:20001;branch=z9hG4bK58525e18;rport
                    );
        }
        fclose(pFile);

    // unlock
    ast_mutex_lock(&some_lock);
 }
C#应用程序 c#应用程序是一个控制台应用程序,它打开该文件以读取事件

因此,基本上C应用程序正在写入一个文本文件,而C#应用程序正在读取该文本文件

问题: 随着时间的推移,文件变得越来越大,我不想麻烦地截断它,并在截断的同时创建另一个锁等使用
mkfifo
似乎正是我想要的
。因为我对linux比较陌生,所以我想确保在使用它之前了解它是如何工作的。我知道C语言的基础知识(我不是专家),并希望使用更有效的方法。你们推荐使用mkfifo、namedpipes还是tcp

例1: mkfifo的工作原理非常惊人,只有几行代码,但当我尝试读取大量代码时,它失败了。举个例子:

mkfifo foo.pipe # create a file of type pipe
在终端1上写入该文件

echo "hello world" >> foo.pipe   # writes hello world AND blocks until someone READS from it
tail -f foo.pipe # similar to cat foo.pipe but it keeps reading
在单独的终端上,我执行以下操作:

cat foo.pipe  # it will output hello world. This will block too until someone WRITES to that file
例2: 在终端1上读取该文件

echo "hello world" >> foo.pipe   # writes hello world AND blocks until someone READS from it
tail -f foo.pipe # similar to cat foo.pipe but it keeps reading
在终端2上写入该文件,但需要大量数据

echo ~/.bashrc >> foo.pipe  # write the content of file ~/.bashrc to that file

这不起作用,控制台上只显示该文件的几行如何正确使用mkfifo来阅读所有文本?我是否应该使用另一种方法来代替tcp?

我将使用AF\u UNIX套接字连接。

我刚刚结束使用tcp。我在10秒内发送了10000条短信,没有问题

C代码(客户端)


正如@resiliware所述,最好使用unix套接字

此示例显示了如何使用unix套接字在C和C#之间进行通信:

客户端(用运行在ubuntu上的C编写)

客户端(如果您希望客户端的代码写在C#而不是C上)


谢谢你对resiliware的帮助。我已经在C上找到了示例。但是我如何从dotnet接收这些事件呢?这种方法的一个问题(可能还有其他问题)是,是否有其他应用程序正在使用您的硬编码端口。我手头没有使用AF#UNIX套接字的C#示例,但我相信您可以找到一个。
using System;
using System.Net;
using System.Net.Sockets;
using System.Threading;

public class Ipc_Tcp
{
    // Thread signal.  
    public static ManualResetEvent _semaphore = new ManualResetEvent(false);


    // maximum length of the pending connections queue.
    const int _max_length_pending_connections_queue = 50;

    const ushort _port = 11234;

    static int _counter = 0;


    public static void StartListening()
    {
        IPEndPoint localEndPoint = new IPEndPoint(System.Net.IPAddress.Loopback, _port);
        // Create a TCP/IP socket.  
        Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

        try
        {
            listener.Bind(localEndPoint);
            listener.Listen(_max_length_pending_connections_queue);

            Console.WriteLine("Waiting for a connection...");

            while (true)
            {
                // Set the event to nonsignaled state.  
                _semaphore.Reset();

                // Start an asynchronous socket to listen for connections.  
                
                listener.BeginAccept(new AsyncCallback(AcceptCallback), listener);

                // Wait until a connection is made before continuing.  
                _semaphore.WaitOne();
            }

        }
        catch (Exception e)
        {
            Console.WriteLine("Something bad happened:");
            Console.WriteLine(e.ToString());
            Console.WriteLine("\nPress ENTER to continue...");
            Console.Read();
        }
    }

    // On new connection
    public static void AcceptCallback(IAsyncResult ar)
    {
        // Signal the main thread to continue.  
        _semaphore.Set();

        var cntr = Interlocked.Increment(ref _counter);

        // Get the socket that handles the client request.  
        Socket listener = (Socket)ar.AsyncState;
        Socket socket = listener.EndAccept(ar);

        var data = new byte[1024];
        var i = socket.Receive(data);

        // print message every 100 times
        if (cntr % 100 == 0)
            Console.WriteLine($"[{cntr}] Received data: {System.Text.Encoding.UTF8.GetString(data, 0, i)}");

        // close socket we are only receiving events
        socket.Close();
    }




    public static int Main(String[] args)
    {
        StartListening();
        return 0;
    }
}
#include<stdio.h>
#include<string.h>  //strlen
#include<sys/socket.h>
#include<unistd.h>

int send_data(void)
{
    int sock;
    int conn;

    struct sockaddr saddr = {AF_UNIX, "/tmp/foo.sock"};
    socklen_t saddrlen = sizeof(struct sockaddr) + 6;

    sock = socket(AF_UNIX, SOCK_STREAM, 0);
    conn = connect(sock, &saddr, saddrlen);

    char BUFF[1024];

    char *message;
    message = "hello world";
    if( send(sock , message , strlen(message) , 0) < 0)
    {
        printf("Send failed \n");
        close(sock);
        return 3;
    }

    // I am not sure if I should close both or only the socket. 
    close(conn);
    close(sock);

    return 0;
}

int main(int argc , char *argv[])
{
    // send 5000 messages
    for(int i=0; i<4000; i++)
    {
        send_data();
        // sleep 1 millisecond
        usleep(1000);
    }
    
    return 0;
}
using System;
using System.Net.Sockets;
using System.Threading;

class Program
{
    // unix Endpoint that we will use
    const string path = "/tmp/foo.sock";

    // Thread signal.  
    public static ManualResetEvent _semaphore = new ManualResetEvent(false);

    // maximum length of the pending connections queue.
    const int _max_length_pending_connections_queue = 100;

    // Counts the number of messages received
    static int _counter = 0;

    public static void StartListening()
    {
        if (System.IO.File.Exists(path))
            System.IO.File.Delete(path);

        // create unix socket
        var listener = new Socket(AddressFamily.Unix, SocketType.Stream, ProtocolType.Unspecified);

        try
        {
            // listener.Bind(localEndPoint);
            listener.Bind(new UnixDomainSocketEndPoint(path));

            listener.Listen(_max_length_pending_connections_queue);

            Console.WriteLine("Waiting for a connection...");

            // keep listening for connections
            while (true)
            {
                // Set the event to nonsignaled state.  
                _semaphore.Reset();

                // Start an asynchronous socket to listen for connections.  

                listener.BeginAccept(new AsyncCallback(AcceptCallback), listener);

                // Wait until a connection is made before continuing.  
                _semaphore.WaitOne();
            }

        }
        catch (Exception e)
        {
            Console.WriteLine("Something bad happened:");
            Console.WriteLine(e.ToString());
            Console.WriteLine("\nPress ENTER to continue...");
            Console.Read();
        }
    }

    // On new connection
    public static void AcceptCallback(IAsyncResult ar)
    {
        // Signal the main thread to continue.  
        _semaphore.Set();

        var cntr = Interlocked.Increment(ref _counter);

        // Get the socket that handles the client request.  
        Socket listener = (Socket)ar.AsyncState;
        Socket socket = listener.EndAccept(ar);

        var data = new byte[1024];
        var i = socket.Receive(data);

        // print message every 100 times
        //if (cntr % 100 == 0)
        Console.WriteLine($"[{cntr}] Received data: {System.Text.Encoding.UTF8.GetString(data, 0, i)}");

        // close socket we are only receiving events
        socket.Close();

    }

    static void Main(string[] args)
    {
        StartListening();        
    }
}
        using (var socket = new Socket(AddressFamily.Unix, SocketType.Stream, ProtocolType.Unspecified))
        {
            socket.Connect(new UnixDomainSocketEndPoint(path));

            // send hello world
            var dataToSend = System.Text.Encoding.UTF8.GetBytes("Hello-world!");

            socket.Send(dataToSend);
        }