2009-05-21 63 views
1

我有两个简单的程序设置,通过unix域套接字共享数据。一个程序从队列中读取数据并将其发送到其他应用程序。在发送之前,每段数据的前面加上四个字节的长度,如果小于四个字节,则剩下的字节是'^'符号。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");  

回答

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); 
} 
+0

这看起来像是一个很好的解决方案,但我对readv如何处理有些困惑。在阅读方面,我只是将一个缓冲区设置为iov [0]的大小。iov_len然后用iov [1] .iov_base填充该缓冲区? – whatWhat 2009-05-22 22:50:40

2

你必须同时检查writeread的返回值不仅-1但对于短(小于请求)写入/读取。你似乎只是在perror打印错误后才继续 - 做一个exit(2)什么的。

0

两件事情:

第一 - 在服务器端,你写了你的数组的末尾。

char finalString[length]; 
bzero(finalString, sizeof(finalString)); 
strcpy(finalString, actualString.c_str()); 

strcpy()length+1字符复制到finalString(字符拉空终止)。

其次(也可能是问题) - 在客户端,您不是null,会终止您读入的字符串,因此printf()将打印您的字符串,然后是堆栈中的任何内容,直到它命中null。

增加两个缓冲区一个,你应该是更好的形状。