ACCESSC++和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_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);

       }

}

相关文章