C 使用mkfifo在linux和dotnet之间进行进程间通信
我们有一个用c编写的应用程序,它向用c#编写的应用程序发送事件/通知。两个应用程序都在同一台linux计算机上运行 C应用程序: C应用程序是开放的,我们修改了源代码(它是开源的),以便它可以向我们的dotnet控制台应用程序发送事件。我们当前发送事件的方式只是将文本附加到文件中。例如,这是我们发送新对等方(ip电话)连接的事件的方式: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.
// 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);
}