C++和C#进度之间通过命名管道通讯(附源码)—下

接上篇:

我利用的是C#支付的一个windows应用程序(pipe_server_csharp)作为劳务器端,而MFC开发的应用程序(NamedPipeClient_vc)作为客户端。客户端和劳动器端要进行频仍的汪洋的通讯,常见的是文件音讯和曲线数据,例如,一共有10条曲线,每条曲线有1000000条double数据。

 

服务器端:

劳动器端是用在VS2005中用C#支付的一个名为pipe_server_csharp的应用程序,唯有一个名为frmServer的主界面。

鉴于管道的相关API函数都是属于kernel32.dll函数,C#中不可能一向调用,所以必须将所要用到的API函数全部封装在一个类NamedPipeNative中。 至于怎么样调用那么些API函数,有趣味的意中人可以上网搜索,或者看自己的另一篇小说《C#中怎么调用命名管道的WinAPI》。

NamedPipeNative类中多少个重点函数如下(大家能够对照那么些重写的API函数和原先的函数有怎样变化):

[DllImport(“kernel32.dll”, SetLastError=true)]

public static extern IntPtr CreateNamedPipe

(

String lpName,                                         
// pipe name

uint dwOpenMode,                                   // pipe open mode

uint dwPipeMode,                                   // pipe-specific modes

uint nMaxInstances,                                // maximum number of instances

uint nOutBufferSize,                           // output buffer size

uint nInBufferSize,                                // input buffer size

uint nDefaultTimeOut,                          // time-out interval

IntPtr pipeSecurityDescriptor        //
SD

);

 

[DllImport(“kernel32.dll”, SetLastError=true)]

public static extern bool
ConnectNamedPipe

(

IntPtr hHandle,                                        
// handle to named pipe

Overlapped lpOverlapped                   // overlapped structure

);

 

[DllImport(“kernel32.dll”, SetLastError=true)]

public static extern IntPtr CreateFile

(

String lpFileName,                          // file
name

uint dwDesiredAccess,                       // access
mode

uint dwShareMode,                                  // share mode

SecurityAttributes attr,                  // SD

uint dwCreationDisposition,          //
how to create

uint dwFlagsAndAttributes,           //
file attributes

uint hTemplateFile);                      // handle to template file

 

[DllImport(“kernel32.dll”, SetLastError=true)]

public static extern bool
ReadFile

(

IntPtr hHandle,    // handle
to file

byte[] lpBuffer,// data buffer字节流

uint nNumberOfBytesToRead,// number of bytes to read

byte[] lpNumberOfBytesRead,// number of bytes read

uint lpOverlapped// overlapped buffer

);

 

[DllImport(“kernel32.dll”, SetLastError=true)]

public static extern bool
WriteFile

(

IntPtr hHandle,    // handle
to file

byte[] lpBuffer,// data buffer字节流

uint nNumberOfBytesToWrite, // number of
bytes to write

byte[] lpNumberOfBytesWritten,   // number
of bytes written

uint lpOverlapped // overlapped buffer

);

 

还有其它一些常量:

public const uint PIPE_ACCESS_DUPLEX = 0x00000003;

public const uint PIPE_ACCESS_OUTBOUND = 0x00000002;

public const uint PIPE_TYPE_BYTE = 0x00000000;

public const uint PIPE_TYPE_MESSAGE =
0x00000004;

在此不一一列举了。

打包之后,在C#中就可以向来调用那个函数和常量了。

 

除此以外,成立了一个类CMyPipe,封装了服务器管道的质量和办法,如创设管道,读写多少等:

 

namespace pipe_server_csharp

{

    public class
CMyPipe

    {

        private string m_PipeName;//管道名全称

        public string PipeName

        {

            get { return
m_PipeName; }

            set { m_PipeName = value; }

        }

 

        private IntPtr m_HPipe;//管道句柄

        public IntPtr HPipe

        {

            get { return
m_HPipe; }

            set { m_HPipe = value; }

        }

 

        public CMyPipe()//无参构造函数

        {

            m_HPipe = (IntPtr)NamedPipeNative.INVALID_HANDLE_VALUE;

            m_PipeName = “\\\\.\\pipe\\robinTest”;

        }

 

        public CMyPipe(string pipeName)//有参构造函数

        {

            m_ACCESS,HPipe = (IntPtr)NamedPipeNative.INVALID_HANDLE_VALUE;

            m_PipeName = pipeName;

        }

 

        ~CMyPipe()//析构函数

        {

            Dispose();

        }

 

        public void
Dispose()

        {

            lock (this)

            {

               
if (m_HPipe != (IntPtr)NamedPipeNative.INVALID_HANDLE_VALUE)

               
{

                   
NamedPipeNative.CloseHandle(m_HPipe);

                   
m_HPipe = (IntPtr)NamedPipeNative.INVALID_HANDLE_VALUE;

               
}

            }

        }

 

        public void
CreatePipe()//创制管道

        {

            m_HPipe = NamedPipeNative.CreateNamedPipe(m_PipeName,

                           
NamedPipeNative.PIPE_ACCESS_DUPLEX,         //
数据双工通讯

                           
NamedPipeNative. PIPE_TYPE_MESSAGE | NamedPipeNative.PIPE_WAIT,                            100,                         // 最大实例个数

                            128,                           // 流出数据缓冲大小

                           
128,                          
// 流入数据缓冲大小

                           
150,                        
// 超时,毫秒

                           
IntPtr.Zero                  // 安全信息

                           
);

            if (m_HPipe.ToInt32() == NamedPipeNative.INVALID_HANDLE_VALUE)

            {

               
frmServer.ActivityRef.AppendText(“创立命名管道失利” );

               
frmServer.ActivityRef.AppendText(Environment.NewLine);

               
return;

            }

            frmServer.ActivityRef.AppendText(“创造命名管道完成” );

            frmServer.ActivityRef.AppendText(Environment.NewLine);          

        }

 

        public void
ReadCurveData()//读取曲线数据

        {

            int nCurvesToRead = 0;

            nCurvesToRead = ReadInt(HPipe);//先读取须要读取的曲线条数,如

            frmServer.CurveDataList.Clear();

            for (int
j = 1; j <= nCurvesToRead; j++)

            {

               
string curveName = ReadString(HPipe);//读取该曲线名称

                int nCount
= 0;

               
nCount = ReadInt(HPipe);//读取该曲线的多寡总数(数组大小)

               
double[] readData = new double[nCount];

               
for (int i = 0;
i < nCount; i++)

               
{

                   
readData[i] = ReadDouble(HPipe);//顺序读取曲线的多寡

               
}

               
CCurve newCurve = new CCurve();

               
newCurve.CurveName = curveName;

               
newCurve.CurveData = readData;

               
frmServer.CurveDataList.Add(newCurve);

            }

        }

 

        public void
ReadTextInfo()//读取文本信息

        {

            string textInfo = ReadString(HPipe);//读取该曲线名称

            frmServer.ActivityRef.AppendText(textInfo + Environment.NewLine);

            frmServer.ActivityRef.AppendText(Environment.NewLine);

        }

 

        public void
ReadData()

        {

            //read data

            int flag =
-1;

            flag = ReadInt(HPipe);//获取当前要读取的数目的音讯

            if (flag ==
0)//flag==0表示读取曲线数据

            {

               
ReadCurveData();

            }

            else if
(flag == 1)//flag==1表示读取文本音讯

            {

               
ReadTextInfo();

            }

        }

 

//写字符串,由于字符串的大小不一,所以先将字符串的大大小小写入,然后写字符串内容,对应的,

//在c++端,读字符串时先读取字符数组大小,从而给字符数组开发相应的长空,然后读取字符串内容。

        public bool
WriteString(IntPtr HPipe, string str)

        {

            byte[] Val = System.Text.Encoding.UTF8.GetBytes(str);

            byte[] dwBytesWrite = new byte[4];

            int len =
Val.Length;

            byte[] lenBytes = System.BitConverter.GetBytes(len);

            if
(NamedPipeNative.WriteFile(HPipe, lenBytes, 4, dwBytesWrite, 0))

               
return (NamedPipeNative.WriteFile(HPipe, Val, (uint)len,
dwBytesWrite, 0));

            else

               
return false;

        }

 

        public string ReadString(IntPtr HPipe)

        {

            string Val
= “”;

            byte[] bytes = ReadBytes(HPipe);

            if (bytes
!= null)

            {

               
Val = System.Text.Encoding.UTF8.GetString(bytes);

            }

            return Val;

        }

 

        public byte[] ReadBytes(IntPtr HPipe)

        {

            //传字节流

            byte[] szMsg = null;

            byte[] dwBytesRead = new byte[4];

            byte[] lenBytes = new byte[4];

            int len;

            if (NamedPipeNative.ReadFile(HPipe, lenBytes, 4, dwBytesRead, 0))//先读大小

            {

                len = System.BitConverter.ToInt32(lenBytes, 0);

               
szMsg = new byte[len];

               
if (!NamedPipeNative.ReadFile(HPipe, szMsg, (uint)len,
dwBytesRead, 0))

               
{

                   
//frmServer.ActivityRef.AppendText(“读取数据失利”);

                   
return null;

               
}

            }

            return szMsg;

        }

 

        public float
ReadFloat(IntPtr HPipe)

        {

            float Val =
0;

            byte[] bytes = new
byte[4]; //单精度需4个字节存储

            byte[] dwBytesRead = new byte[4];

            if (!NamedPipeNative.ReadFile(HPipe, bytes, 4, dwBytesRead, 0))

            {

               
//frmServer.ActivityRef.AppendText(“读取数据退步”);

               
return 0;

            }

            Val = System.BitConverter.ToSingle(bytes, 0);

            return Val;

        }

 

        public double ReadDouble(IntPtr HPipe)

        {

            double Val
= 0;

            byte[] bytes = new
byte[8]; //双精度需8个字节存储

            byte[] dwBytesRead = new byte[4];

 

            if (!NamedPipeNative.ReadFile(HPipe, bytes, 8, dwBytesRead, 0))

            {

               
//frmServer.ActivityRef.AppendText(“读取数据败北”);

               
return 0;

            }

            Val = System.BitConverter.ToDouble(bytes, 0);

            return Val;

        }

 

        public int
ReadInt(IntPtr HPipe)

        {

            int Val =
0;

            byte[] bytes = new
byte[4]; //整型需4个字节存储

            byte[] dwBytesRead = new byte[4];

 

            if (!NamedPipeNative.ReadFile(HPipe, bytes, 4, dwBytesRead, 0))

            {

               
//frmServer.ActivityRef.AppendText(“读取数据失利”);

               
return 0;

            }

            Val = System.BitConverter.ToInt32(bytes, 0);

            return Val;

        }

    }

}

 

 

主程序,读取和展现通讯音信:

    public partial class frmServer : Form

    {

        public static System.Windows.Forms.TextBox ActivityRef;//显示音讯      

        public static ArrayList CurveDataList = new ArrayList();//存储数据

        public static string PipeName = “robinTest”;

        public static string ServeName = “.”;

        public static string FullPipeName = “\\\\”+ServeName+”\\pipe\\”+PipeName;//管道全名

 

        public static CMyPipe ThePipe;//管道实例

 

        private Thread hThread;//线程

 

        public frmServer()

        {

            InitializeComponent();

            frmServer.ActivityRef = this.txtMessage;

            Control.CheckForIllegalCrossThreadCalls = false;//不捕获线程错误调用,那样线程就足以其他线程中开创的事物,这样做也会毁掉了线程的固原

            ThePipe = new CMyPipe(FullPipeName);

            ThePipe.CreatePipe();//创立管道

 

            hThread = new Thread(new
ThreadStart(PipeProcess));

            hThread.IsBackground = true;

            hThread.Name = “Main
Pipe Thread”;

            hThread.Start();//
启动线程.监听管道,进行通讯

            Thread.Sleep(1000);

        }

 

        public void
PipeProcess()

        {

            bool ret =
false;

            try

            {

               
while (true)

               
{

                   
ret = NamedPipeNative.ConnectNamedPipe(ThePipe.HPipe, null);//连接到管道

 

                  
 if (!ret)

                   
{

                       
if (NamedPipeNative.GetLastError() == NamedPipeNative.ERROR_PIPE_CONNECTED)  //
客户还在连年中

                       
{

                           
frmServer.ActivityRef.AppendText(“连接正常,客户还在连年中……” + Environment.NewLine);//此处会出错,因为线程调用的标题

                           
ret = true;

                       
}

                       
if (NamedPipeNative.GetLastError() == NamedPipeNative.ERROR_NO_DATA)         //
客户已经关闭

                       
{

                  
         frmServer.ActivityRef.AppendText(“客户已经关门,等待客户…………” + Environment.NewLine);

                           
NamedPipeNative.DisconnectNamedPipe(ThePipe.HPipe);

                           
continue;

                       
}

                   
}

                    else

                   
{

                       
frmServer.ActivityRef.AppendText(“有客户接入” + Environment.NewLine);                       

                   
}

 

                   
ThePipe.ReadData();//读取数据

               
}

            }

            catch (Exception ex)

            {

               
MessageBox.Show(ex.ToString());

            }

            finally

            {

               
frmServer.ActivityRef.AppendText(“线程退出!”);

            }

        }

    }

  客户机端:

客户端是在VS6.0中用MFC开发的一个单界面应用程序,名为NamedPipeClient_vc。在vc6.0中可以直接调用API函数,不需求封装。

自然,按照规矩,依然将客户端的命名管道相关的品质和措施封装成类CMyPipe,如下:

CString
PipeName = “robinTest”;

CString
ServerName = “.”;

CString
FullPipeName=”\\\\”+ServerName+”\\pipe\\”+PipeName;

 

CMyPipe::CMyPipe()

{

      
m_pThread=NULL;

}

 

CMyPipe::~CMyPipe()

{

      
if(m_pThread)

       {

             
if(TerminateThread(m_pThread->m_hThread,0))

              {

                     if(m_pThread)

                            delete      m_pThread;

                     m_pThread =
NULL;

              }

       }

}

 

//客户端和劳务器端建立连接

void
CMyPipe::ClientCreateFile()

{

       BOOL ret =
::WaitNamedPipe(FullPipeName, 5000);

       if (!ret)

       {

             
//ClientMsg=”管道忙依然没有启动……\n”;

             
return;

       }

       m_hPipe  = ::CreateFile(FullPipeName,

             
GENERIC_READ|GENERIC_WRITE,

             
FILE_SHARE_READ|FILE_SHARE_WRITE,

              NULL,

              OPEN_EXISTING,

              FILE_ATTRIBUTE_NORMAL,

             
NULL);

    if (m_hPipe ==
INVALID_HANDLE_VALUE)

       {

             

        char szErr[256] =
“”;

        DWORD dwErr =
GetLastError();

              sprintf(szErr, “%l”,
dwErr);

       
//ClientMsg=szErr;

        return;

 

    }

      

       //ClientMsg=”打开管道了\n”;

}

 

//写字符串

void
CMyPipe::WriteString(char *szMsg)

{

       DWORD  dwSize = strlen(szMsg)+1,
dwBytesWritten = 0;

       BOOL ret =WriteFile(m_hPipe,
&dwSize, 4, &dwBytesWritten, NULL);

       if (ret)

       {

              BOOL
ret2=WriteFile(m_hPipe, szMsg, dwSize, &dwBytesWritten,
NULL);

       }

}

 

//写单精度

void
CMyPipe::WriteFloat(float szMsg)

{

       DWORD  dwSize = 4, dwBytesWritten =
0;

       BOOL ret=WriteFile(m_hPipe,
&szMsg, dwSize, &dwBytesWritten, NULL);

}

 

//写双精度

void
CMyPipe::WriteDouble(double szMsg)

{

       DWORD  dwSize = 8, dwBytesWritten =
0;

       BOOL ret=WriteFile(m_hPipe,
&szMsg, dwSize, &dwBytesWritten, NULL);

}

 

//写整型

void
CMyPipe::WriteInt(int szMsg)

{

       DWORD  dwSize = 4, dwBytesWritten =
0;

       BOOL ret=WriteFile(m_hPipe,
&szMsg, dwSize, &dwBytesWritten, NULL);

}

 

void
CMyPipe::ClosePipe()

{

      
CloseHandle(m_hPipe);

}

 

//读字符串

char *
CMyPipe::ReadString()

{

       char
*readStr;

       DWORD  drSize=0, dwBytesRead =
0;

       BOOL ret =ReadFile(m_hPipe,
&drSize, 4, &dwBytesRead, NULL);

       if (ret)

       {

              readStr=new
char[drSize];

              BOOL
ret2=ReadFile(m_hPipe, readStr, drSize, &dwBytesRead,
NULL);

       }

       return
readStr;

}

 

 

int
CMyPipe::ReadInt()

{

       int
intRead=0;

       DWORD  drSize=4, dwBytesRead =
0;

       BOOL ret =ReadFile(m_hPipe,
&intRead, drSize, &dwBytesRead, NULL);

       return
intRead;

}

 

float
CMyPipe::ReadFloat()

{

       float
floatRead=0;

       DWORD  drSize=4, dwBytesRead =
0;

       BOOL ret =ReadFile(m_hPipe,
&floatRead, drSize, &dwBytesRead, NULL);

       return
floatRead;

}

 

double
CMyPipe::ReadDouble()

{

       double
floatRead=0;

       DWORD  drSize=8, dwBytesRead =
0;

       BOOL ret =ReadFile(m_hPipe,
&floatRead, drSize, &dwBytesRead, NULL);

       return
floatRead;

}

 

而主程序NamedPipeClient_vcDlg.cpp如下:

CMyPipe
thePipe;

 

//连接服务器管道

void
CNamedPipeClient_vcDlg::OnOpen()

{

       // TODO: Add your control
notification handler code here

      
thePipe.ClientCreateFile();

}

 

//发送数据

void
CNamedPipeClient_vcDlg::OnWrite()

{

       // TODO: Add your control
notification handler code here

       WriteData();

}

//关闭管道

void
CNamedPipeClient_vcDlg::OnClose()

{

       // TODO: Add your control
notification handler code here

      
thePipe.ClosePipe();

}

//写曲线数据(注意写入的一一,读的时候也要根据那个顺序)

void
CNamedPipeClient_vcDlg::WriteCurveData()

{

       int
nCurvesToWrite=10;

      
thePipe.WriteInt(nCurvesToWrite);//先写入要传送的曲线总条数

       for (int j = 1; j <=
nCurvesToWrite; j++)

       {

              char *curveName=
“curve”;//

             
thePipe.WriteString(curveName);//写该曲线名称

              int nCount =
10000;//该曲线的多寡总数(数组大小)

             
thePipe.WriteInt(nCount);

              double *writeData=new
double[nCount];

              for (int i = 0; i <
nCount; i++)

              {

                    
writeData[i]=i;//给每个曲线数据赋初值

                    
thePipe.WriteDouble(writeData[i]);//顺序写曲线的数额

              }

       }

}

//写文本音讯

void
CNamedPipeClient_vcDlg::WriteTextInfo(char *textInfo)

{

      
thePipe.WriteString(textInfo);

}

 

void
CNamedPipeClient_vcDlg::WriteData()

{

       int flag=1;//传递的信息的标识,0代表曲线数据,1代表文本新闻

       if (flag==0)

       {

             
thePipe.WriteInt(flag);

             
WriteCurveData();

       }

       else if
(flag==1)

       {

             
thePipe.WriteInt(flag);

              char *
charWrite=”hedafasfddsafdsafdsafdsafdsafsafdsafdsafdsafsaaaa”;

             
WriteTextInfo(charWrite);

       }

}

相关文章