Unix socket streams sending more data, then it should be

I have two simple programs that set up shared data over a unix domain socket. One program reads data from a queue and sends it to another application. Before each piece of data is sent, the leading part is appended with four bytes with a length, if it is less than four bytes, there is a "^" character on the left above the bytes.

The client application then reads the first four bytes, sets the buffer to the appropriate size, and then reads the rest. The problem I am facing is that the first time through the message will be sent fine. Each time thereafter, more data is added, so a message like "what a nice day" will come out as "what a good day?" So I feel like the buffer is not flushing properly, but I cannot find it.

Client code:

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);

      

Server code

                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");      

      

+1


a source to share


3 answers


Instead of deferring your packet length with < ^

, you would be much better off:

snprintf(sizeofStringBuffer, 5, "%04d", sizeOfString);

      

so the value is 0 padded - then you don't need to parse the '^' characters in the receiver code.

Please also edit your debug code - there is only one write()

in the current code and does not match your protocol description.



Ideally, split your dispatch procedure into your own function. You can also use this writev()

to handle combining a string containing a length field with a buffer containing the actual data and then sending it as one atom write()

.

The unverified code follows:

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

      

+2


a source


You should check the return values ​​both write

and read

not only for -1

but also for shorter (less requested) records / reads. It looks like you only continue after printing the error with perror

- do exit(2)

or whatever.



+2


a source


Two things:

First - on the server side, you write the end of your array.

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

      

strcpy()

will copy length+1

characters to finalString

(character will pull the null delimiter).

The second (and most likely will be a problem) is that on the client side you are not null terminating the string you are reading, so it printf()

will print your string and then whatever is on the stack up to the point it is null-terminated.

Increase both buffers by one and you should be in your best shape.

0


a source







All Articles