C++ 邮件槽写入发送相同内容三次C/C++;

C++ 邮件槽写入发送相同内容三次C/C++;,c++,c,winapi,ipc,C++,C,Winapi,Ipc,我在windows(C/C++)中的邮件槽有问题 我现在正试着做两个简单的程序,但是最后一步的交流不好 这是server.cpp中的我的int main int main() { HANDLE ss, sc, sc2r; LPCTSTR errMsg; ss = CreateMailslot("\\\\.\\mailslot\\ss", 0, MAILSLOT_WAIT_FOREVER, NULL); if (ss == INVALID_HANDLE

我在windows(C/C++)中的邮件槽有问题

我现在正试着做两个简单的程序,但是最后一步的交流不好

这是server.cpp中的我的int main

    int main()
{
HANDLE      ss, sc, sc2r;
   LPCTSTR     errMsg;

   ss = CreateMailslot("\\\\.\\mailslot\\ss", 0, MAILSLOT_WAIT_FOREVER, NULL);
   if (ss == INVALID_HANDLE_VALUE) 
   {
       printf("Invalid ss value");
       return -1;
   }

   for (;;)
   {
       DWORD   msgSize;
       DWORD nr;
       BOOL    err;

       /* Get the size of the next record */
       err = GetMailslotInfo(ss, 0, &msgSize, 0, 0);
           char x[100];
           char nrr[10];

       if (msgSize != (DWORD)MAILSLOT_NO_MESSAGE)
       {
               DWORD   numRead;
               /* Read the record */
               err = ReadFile(ss, x, msgSize, &numRead, 0);
               int wrds=count(x)+1;
               sc = CreateFile("\\\\*\\mailslot\\sc", GENERIC_WRITE, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
               itoa(wrds,nrr,10);

               err = WriteFile(sc, nrr, sizeof(nrr), &nr, 0);
               //cout<<err<<endl;

               //cout<<x;

               //cout<<err;
               strrev(x);
               err=WriteFile(sc, x, sizeof(x), &nr, 0);
           }   
       }
  return(0);
}
intmain()
{
手柄ss、sc、sc2r;
LPCTSTR-errMsg;
ss=CreateMailslot(“\\.\\mailslot\\ss”,0,mailslot\u永远等待,NULL);
if(ss==无效的\u句柄\u值)
{
printf(“无效ss值”);
返回-1;
}
对于(;;)
{
德沃德msgSize;
德沃德;
错误;
/*获取下一条记录的大小*/
err=GetMailslotInfo(ss,0,&msgSize,0,0);
charx[100];
char-nrr[10];
如果(msgSize!=(DWORD)邮箱(无消息)
{
德沃德·努姆雷德;
/*读记录*/
err=ReadFile(ss、x、msgSize和numRead,0);
int wrds=计数(x)+1;
sc=CreateFile(“\\*\\mailslot\\sc”,一般写入,文件共享读取,0,打开现有,文件属性正常,0);
itoa(wrds,nrr,10);
err=WriteFile(sc、nrr、sizeof(nrr)和nr,0);

//cout邮件槽是一种不可依赖的传输方式--邮件可以自由丢弃。为了确保邮件能够通过,发件人使用每个可用的不同协议(将发件人连接到预期的收件人)自动发送邮件一次

你的网络堆栈显然已经设置好了,所以有三个协议将你的发送者连接到你的接收者。因为它们(可能)在本地通信,通过相对可靠的硬件,没有路由器通过丢弃数据包或诸如此类的方式处理拥塞,你可能会得到每个数据包的三个副本

一句话:如果你想使用MailSlot,你几乎必须为每个数据包分配一个序列号,这样你就能够跟踪你何时已经收到了一些信息,这样你就能够识别并忽略接收端的重复信息

或者,不要使用mailslots。如果(出于任何原因)您想要特定于Windows的东西,则命名管道通常更容易。除非您真的为代码的可移植性和可互操作性而烦恼,否则套接字可能更简单。

您会混淆。调用
sizeof(nrr)
将始终返回10。即使缓冲区仅包含2个有效字节,服务器程序也将执行10字节的单次写入

sizeof
替换为
1+strlen
,以解决问题

例如,在server.cpp中,如果
wrds
为1,则
nrr
将在内存中
{0x31,0x00}
。看起来像重复写入的实际上是未初始化内存的一次写入。
strlen
将为您提供有效字符的计数,+1表示终止null

首先使用
*nrr=0
初始化nrr可能是一个好主意。您可以测试
itoa
是否成功使用
if(*nrr)
,并按照您认为合适的方式处理故障


哦,还有一件事:您正在泄漏句柄。这在客户端可能不太重要,但服务器在每次迭代时都会泄漏一个到邮箱的句柄。您应该在每次迭代时重用邮箱句柄或关闭它。

我不知道在Windows下邮箱是否不可靠。网络可能会失败,但也可能会断开套接字。邮箱与命名管道和套接字相比,s有一个优势:接收的消息始终是完整的,不需要按字节数为消息添加前缀,也不需要其他自制的帧机制。@ixe013:我不确定它是否仍然存在于MSDN中,但我所说的大部分内容(温和地)是从Win32文档中转述的(而且,我想我应该补充一点:我已经验证了安装更多的协议会导致接收到更多的每条消息副本)。在网络上,任何未确认/确认的内容通常被认为是“不可靠的”(例如,UDP的方式几乎相同).你说得对@Jerry,邮箱正在使用数据报。我不知道。这是供将来参考的。如果“客户做对了”,那么如何判断服务器发送了三次相同的内容?我尝试过,但仍然是一样的,我是否必须在所有读/写操作中用1+strlen替换sizeof?只是在调用WriteFile时。调用ReadFile时,您还不知道长度。虽然这是一个很好的注释,但不是答案。问题的真正原因是有几个Windows使用Transports发送消息(请参阅Jerry Coffin的回答)…但是您是否有关于多个传输问题的链接?我不知道您和Jerry指的是什么。我/以前的印象是,为给定连接选择了单个传输。
int main()
{
   HANDLE      ss, sc, sc2;
   LPCTSTR     errMsg;
   BOOL        err;
   DWORD       numWritten;

   sc = CreateMailslot("\\\\.\\mailslot\\sc", 0, MAILSLOT_WAIT_FOREVER, NULL);
   ss = CreateFile("\\\\*\\mailslot\\ss", GENERIC_WRITE, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);

   if (ss == INVALID_HANDLE_VALUE) 
   {
       printf("CreateFile failed. ");  
       // Close any mailslot we opened
       if (ss != INVALID_HANDLE_VALUE) CloseHandle(ss);
       return -1;
   }

   char x[100];
   char z[100];

   printf("Write the damn sentence:");
   cin.getline(x,100);
   err = WriteFile(ss, x, sizeof(x), &numWritten, 0);
   if (!err) printf("WriteFile failed. ");
   DWORD rd;

   ReadFile(sc,x,sizeof(x),&rd,NULL);
   cout<<x<<endl;
   ReadFile(sc,z,sizeof(z),&rd,NULL);
   cout<<z;

   return 0;
}