我有两个简单的程序设置,通过unix域套接字共享数据。一个程序从队列中读取数据并将其发送到另一个应用程序。在发送之前,每个数据的前面附加四个字节的长度,如果它小于四个字节,则左边的字节是'^'符号。
客户端应用程序然后读取前四个字节,将缓冲区设置为适当的大小,然后读取其余的。我遇到的问题是第一次通过邮件将被完美地发送。在那之后的每隔一段时间都会发送额外的数据,所以像“多么美好的一天”这样的消息就会出现像“多么美好的一天?X?”。所以我觉得缓冲区没有被正确清除,但我似乎无法找到它。
客户代码:
listen(sock, 5);
for (;;)
{
msgsock = accept(sock, 0, 0);
if (msgsock == -1)
perror("accept");
else do
{
char buf[4];
bzero(buf, sizeof(buf));
if ((rval = read(msgsock, buf, 4)) < 0)
perror("reading stream message");
printf("--!%s\n", buf);
string temp = buf;
int pos = temp.find("^");
if(pos != string::npos)
{
temp = temp.substr(0, pos);
}
int sizeOfString = atoi(temp.c_str());
cout << "TEMP STRING: " << temp << endl;
cout << "LENGTH " << sizeOfString << endl;
char feedWord[sizeOfString];
bzero(feedWord, sizeof(feedWord));
if ((rval = read(msgsock, feedWord, sizeOfString)) < 0)
perror("reading stream message");
else if (rval == 0)
printf("Ending connection\n");
else
printf("-->%s\n", feedWord);
bzero(feedWord, sizeof(feedWord));
sizeOfString = 0;
temp.clear();
}
while (rval > 0);
close(msgsock);
}
close(sock);
unlink(NAME);
服务器代码
pthread_mutex_lock(&mylock);
string s;
s.clear();
s = dataQueue.front();
dataQueue.pop();
pthread_mutex_unlock(&mylock);
int sizeOfString = strlen(s.c_str());
char sizeofStringBuffer[10];
sprintf(sizeofStringBuffer, "%i", sizeOfString);
string actualString = sizeofStringBuffer;
int tempSize = strlen(sizeofStringBuffer);
int remainder = 4 - tempSize;
int x;
for(x =0; x < remainder; x++)
{
actualString = actualString + "^";
}
cout << "LENGTH OF ACTUAL STRING: " << sizeOfString << endl;
actualString = actualString + s;
cout << "************************" << actualString << endl;
int length = strlen(actualString.c_str());
char finalString[length];
bzero(finalString, sizeof(finalString));
strcpy(finalString, actualString.c_str());
if (write(sock, finalString, length) < 0)
perror("writing on stream socket");
答案 0 :(得分:2)
不是用“^
”填充数据包长度,而是做得好得多:
snprintf(sizeofStringBuffer, 5, "%04d", sizeOfString);
这样值为0填充 - 那么你不需要解析接收器代码中的'^'字符。
请同时编辑您的调试代码 - 当前代码中只有一个write()
,它与您对协议的描述不符。
理想情况下 - 将发送例程拆分为自己的函数。您还可以利用writev()
来处理包含“length”字段的字符串与保存实际数据的缓冲区的合并,然后将它们作为单个原子write()
发送。
未经测试的代码如下:
int write_message(int s, std::string msg)
{
struct iovec iov[2];
char hdr[5];
char *cmsg = msg.c_str();
int len = msg.length();
snprintf(hdr, 5, "%04d", len); // nb: assumes len <= 9999;
iov[0].iov_base = hdr;
iov[0].iov_len = 4;
iov[1].iov_base = cmsg;
iov[1].iov_len = len;
return writev(s, iov, 2);
}
答案 1 :(得分:2)
您必须检查write
和read
的返回值,不仅是-1
,还有简短(少于请求)的写入/读取。在使用perror
打印错误之后,您似乎也只是继续 - 在那里执行exit(2)
或其他事情。
答案 2 :(得分:0)
两件事:
首先 - 在服务器端,您正在注销数组的末尾。
char finalString[length];
bzero(finalString, sizeof(finalString));
strcpy(finalString, actualString.c_str());
strcpy()
会将length+1
个字符复制到finalString
(字符拉空终止符)。
第二个(最有可能是问题) - 在客户端你不是null终止你读入的字符串,因此printf()
将打印你的字符串,然后堆栈中的任何内容它点击空的点。
将两个缓冲区增加一个,你应该处于更好的状态。