我在Windows(C / C ++)中遇到MailSlots问题。
我正在尝试制作两个简单的程序,但最后一步的沟通并不好。
这是我在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);
}
以下是客户来源:
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;
}
好像服务器发送了三次相同的东西。我在调试器中对客户端进行了测试,他说得对,但无法弄清楚为什么服务器发送三次相同的东西。
你有什么建议吗?
答案 0 :(得分:2)
Mailslots是一种不可靠的传输 - 消息可以自由删除。为了确保消息通过,发送方使用每个可用的不同协议(将该发送方连接到预期的接收方)自动发送消息一次。
您的网络堆栈显然已设置好,因此有三种协议可将您的发件人连接到接收器。由于它们(可能)在本地进行通信,通过相对可靠的硬件而没有通过丢弃数据包来处理拥塞的路由器,或类似的任何东西,你可能会得到三个每个数据包的副本。
底线:如果你想使用邮件槽,你几乎必须为每个数据包分配一个序列号,这样你就可以跟踪你已经收到的东西,这样你就能够识别并忽略接收方的重复。
或者,只是不要使用邮件槽。如果(无论出于何种原因)您需要特定于Windows的内容,则命名管道通常更容易。除非您的代码实际上受到可移植性和可互操作性的困扰,否则套接字可能更简单。
答案 1 :(得分:0)
您将sizeof
与strlen
混淆。调用sizeof(nrr)
将始终返回10.服务器程序将执行10个字节的单次写入,即使缓冲区仅包含2个有效字节。
将sizeof
替换为1+strlen
以解决问题。
例如,如果wrds
为1,则在server.cpp中,nrr
将在内存中为{ 0x31, 0x00 }
。看起来像重复写入的内容实际上是对未初始化内存的单次写入。 strlen
将为您提供有效字符的计数,终止为空的+1。
首先使用*nrr = 0
初始化nrr可能是个好主意。您可以使用itoa
测试if(*nrr)
成功,并根据需要处理失败。
哦,还有一件事:你正在泄漏手柄。在客户端中可能没什么关系,但是服务器在每次迭代时都会泄漏邮件槽的句柄。您应该重复使用邮件槽句柄或在每次迭代时关闭它。