0

Im trying to do a simple client tcp (I have a server already working). I have defined 2 variables:

  1. std::vector<unsigned char> buffer(1000);
  2. std::vector<std::vector<unsigned char>> buff; buffer I use it ot read chains of unsigned characters, when reading is done i store it on buff and I start reading again. I have defined all the process of adress, port, etc and when it comes to send strings of buffer I have problems. Here's what i tried so far:

    while(!buff.empty()){
        // Sockets Layer Call: send(
        n = send(sockfd, buff.back(), buff.back.size(), 0);
        std::this_thread::sleep_for(std::chrono::milliseconds(delay)) ;
        buff.pop_back();
    
        if (n < 0){
            std::cout<<"ERROR writting to socket"<<std::endl;
            exit(1);
        }
    }
    

I tried adding (char *) , also reinterpret_cast, but noithing seems to work. Any clue?

Thanks

Lomezno
  • 90
  • 11
  • in general, you _cannot_ just send objects over sockets, you need to _serialize_ them (and then deserialize the message on the receiving end). – Useless Jul 05 '17 at 12:59
  • 2
    `strlen` is wrong, the correct size is available from `vector::size()`. – Ben Voigt Jul 05 '17 at 13:00
  • Is `buff` a vector of *strings*? More specifically a vector of *C-style zero.-terminated strings*? First of all, if you want to use strings use `std::string` instead of vectors of characters. Secondly, `buff.back()` gives you a *vector*, not something you can pass to `strlen`. Lastly you never remove anything from `buff` leading to an infinite loop. – Some programmer dude Jul 05 '17 at 13:00
  • @Borgleader: `buff` is a vector of vector, he's trying to get the length of one single array stored inside `buff`. Of course, you can't just cast a vector object to a pointer. – Ben Voigt Jul 05 '17 at 13:01
  • 1
    On an unrelated note, check for error *directly* after you call `send`. Because otherwise the error code (which you for some reason don't report) can change and will be otherwise irrelevant or even undefined. – Some programmer dude Jul 05 '17 at 13:02
  • 1
    @BenVoigt Yes, I realized that after, comment removed. (in my defense, having buff and buffer, which are both vector is confusing) – Borgleader Jul 05 '17 at 13:02
  • I know i missed the `pop_back`. `buff` is a vector containing vectors with unsigned chars. Why I use it like this instead of `string`? because it's for binary data, using `string` wont cover all the 256 values that i need for this case. About `strlen`, yes you are right, `size()` is the one to use here. – Lomezno Jul 05 '17 at 13:07
  • It might be better to delete the buffer only *after* you check to see of the send worked or not. Otherwise you may delete something that hasn't been sent. – Galik Jul 05 '17 at 13:15
  • @Galik I cannot do that, once the sending process starts i cannot stop it. This little client is ment to send several files over tcp. So the only thing I can do is to wait and see on destination what happened – Lomezno Jul 05 '17 at 13:20
  • It may be worth looking at this answer for robust socket code: https://stackoverflow.com/a/2014066/3807729 – Galik Jul 05 '17 at 13:34

2 Answers2

0

Here's one way you could do it:

   std::vector<std::vector<unsigned char>> buff;
   //...
   for (std::vector<std::vector<unsigned char>> i = buff.begin(); 
        i != buff.end(); ++i)
   {
     std::vector<char>::iterator next = i->begin();
     while (next != i->end())
     {
       // if you don't have std::distance, use i->end() - next
       n = send(sockfd, &(*next), std::distance(next, i->end()), 0);
       if (n < 0)
       {
         std::cout<<"ERROR writing to socket"<<std::endl;
           exit(1);
       }
       next += n;
       if (n != i->end())
       {
         std::this_thread::yield();
       }
     }
   }
Michaël Roy
  • 6,338
  • 1
  • 15
  • 19
-1

if you're trying to send all vectors within a vector, you're more or less on the right track... your loop however will never terminate as you never pop the last element from buff

while(!buff.empty()){
    // Sockets Layer Call: send(
    n = send(sockfd, &(buff.back()[0]), buff.back().size(), 0);
    buff.pop_back();   // need to remove what you just sent?
    std::this_thread::sleep_for(std::chrono::milliseconds(delay)) ;

    if (n < 0){
        std::cout<<"ERROR writting to socket"<<std::endl;
        exit(1);
    }
}
Eyal Cinamon
  • 939
  • 5
  • 16
  • 1
    This instruction is what i was looking for `&(buff.back()[0])`. Thanks. May I ask, why the `[0]` ? could I also use `&(buff.back().data())` ? – Lomezno Jul 05 '17 at 13:11
  • `&(buff.back()[0])` points to the first element of `vector` - is there a guarantee that elements of a vector are all in the same place, so first element + `buff.back().size()` bytes will cover all the vector and no garbage? – u354356007 Jul 05 '17 at 13:12
  • 2
    There is no guarantee that a socket send() will send the entire buffer. And buff is a LIFO buffer? – Michaël Roy Jul 05 '17 at 13:17
  • @MichaëlRoy It actually doesnt matter if LIFO or FIFO as far as the data is properly transfered without loss. – Lomezno Jul 05 '17 at 13:24
  • 1
    It is not. Some socket implementations will only take so many bytes in at a time. That's why send() returns the number of bytes accepted. – Michaël Roy Jul 05 '17 at 13:27
  • 1
    @lomezno Sometimes data ordering does matter. :) – Michaël Roy Jul 05 '17 at 13:33
  • @MichaëlRoy I know, but not in this particular case :) I was checking the size of `send()` and for my case it send up to 2000bytes, which is more than enough for me. – Lomezno Jul 05 '17 at 13:35