1

I'm currently working on a socket program.

Is it possible to use the stream insertion operator as in the use case below ?

__sin >> var; // similar to cin >> var;

where the body of the function is something like

var = remoteConsole.getline();

so i can use the function in place of cin when im working with my remote console, in a remote location I know i can use something like

cin.getLine() or var= remoteConsole.cin()

but im trying to avoid that.

Im starting to think that what im trying to do is impossible though it seems easy, i may have to dump the idea. I've had a good look around but everything i try is littered with compile errors. any help would be appreciated. Thank you

EDIT

for those who were unclear as to what i was talking about (which i tryed to clearly explain) i was trying to make a function with the same syntax as cin but instead of getting the input from a console, getting it from somewhere else, ie a socket. i was having trouble creating a function that took << or >> instead of ( and ). i wanted the syntax to be the same as cin >> and cout <<. my question should have been, where do i start on the road to doing this?.

Ive found out a way to do it, but im not shure how safe it will be. I created two struct's and overloaded the << in one and >> in the other

struct out_t {
    template<typename T>
    out_t& operator << (T&& x)  {
        // Send x to the socket
        // Use console for now
        cout << x;
    return *this;
    }
};

out_t socout;

struct in_t {
    template<typename T>
    in_t& operator >> (T&& x)  {
        // get x from the socket and wait untill done so;
        // Use console for now
        cin >> x;
        return *this;
    }
};

in_t socin;

so now i can use

socout << "Some message"; // which i can now send to an external console
socin >> strValue;//  i can request the data needed from external program/computer

sorry if i didn't explain this well to start with. there may be room for improvements but im quite happy with this. if this is not the way to go, could somebody please please advise me of the proper way.

Thanks all;

  • 4
    So where exactly is the problem? It's just a matter of implementing an `operator >>` overload in the end. – AliciaBytes May 22 '14 at 23:25
  • 2
    You forgot to ask a question. – David Schwartz May 22 '14 at 23:31
  • By the way. Do not use that name, `__sin`, in your code. Identifiers with double underscores are reserved for the implementation. http://stackoverflow.com/questions/228783/what-are-the-rules-about-using-an-underscore-in-a-c-identifier/228797#228797 – Benjamin Lindley May 22 '14 at 23:47
  • I think he's trying to figure out that he wants to make a streambuf replacement that works with socket streams. – Mooing Duck May 22 '14 at 23:50
  • 1
    @DietmarKühl: The question has been added by my edit. Check the original post for the legimity of David Schwartz comment. – agrum May 22 '14 at 23:57
  • @agrum: good point - I hadn't noticed. I have removed my comment. Thanks. – Dietmar Kühl May 22 '14 at 23:59
  • part of my problem was i didn't understand that cin and cout were struct's, not functions. once i realized that it got a hole lot easier. – Ace_Of_John May 25 '14 at 21:52

2 Answers2

9

If all you want to do is to create an std::istream& which reads from a socket instead of one of the predefined stream, you can create a custom std::streambuf: the std::istream doesn't really do any of the reading of characters. That is the job of the stream buffer. All std::istream does is provide an interface to overload input operations, hold formatting flags, error indicators, and a stream buffer.

To create a custom stream buffer for inputting character, you'd override underflow() to read characters into a buffer, e.g., something like this (using the typical UNIX API for sockets; on a different system just the code for accessing the socket really differs):

class socketbuf: public std::streambuf {
    typedef std::streambuf::traits_type traits_type;
    int  d_fd;
    char d_buffer[2000];
    int underflow() {
        if (this->gptr() == this->egptr()) {
            std::streamsize size = ::read(this->d_fd, this->d_buffer, sizeof(this->d_buffer));
            this->setg(this->d_buffer, this->d_buffer, this->d_buffer + size);
        }
        return this->gptr() == this->egptr()
            ? traits_type::eof()
            : traits_type::to_int_type(*this->gptr());
    }
public:
    socketbuf(int fd): d_fd(fd) {}
};

Once you have stream buffer like this, you can just initialize an std::istream with a pointer to this stream buffer. If you are planning to use this set up multiple times, you may want to create a custom isocketstream class which creates the stream buffer and sets up an std::istream with the result. Here is just the unpackage use:

int fd = get_and_setup_socket(); // get a file descriptor for the socket somehow
socketbuf    sbuf(fd);
std::istream sin(&sbuf);

std::istream& in(use_local? std::cin: sin);
if (in >> whatever) {
    std::cout << "received '" << whatever << "'\n";
}

You might want to complement the input operations with output operations. To this end you'd also override the functions overflow() which is called whenever the set up buffer overflows and sync() which is called when the stream if getting flushed.

Mooing Duck
  • 64,318
  • 19
  • 100
  • 158
Dietmar Kühl
  • 150,225
  • 13
  • 225
  • 380
  • I like how a lot of people critisize ostream for doing too much, when in reality all it does is coordinate state between the buffers and facets and such. – Mooing Duck May 22 '14 at 23:52
  • Way more elegant solution to the problem than mine. – agrum May 23 '14 at 00:01
1

Basic C++. Overload the operator >> so it does what you expect it to do.

MySocketClass& MySocketClass::operator>>(std::string&);
agrum
  • 407
  • 2
  • 16
  • 1
    You had it right before, taking one argument. Why'd you change it? – Benjamin Lindley May 22 '14 at 23:32
  • A previous comment made me doubt. This is correct with only the string as input right ? – agrum May 22 '14 at 23:33
  • 2
    If it was a non-member function, it would require two parameters. As a member function, it only requires one, because the first argument is assumed to be the calling object (in this case, a `MySocketClass` object). – Benjamin Lindley May 22 '14 at 23:35
  • Ok, so I put the original version back. I should have checked instead of assuming I was wrong directly. Thanks. – agrum May 22 '14 at 23:37
  • 1
    Overloading `operator>>()` is for parsing specific types. It isn't to read from a specific source. Do **not** overload `operator>>()` for stream to read from another source! The proper way to implement reading from another source is to create a custom stream buffer! – Dietmar Kühl May 22 '14 at 23:47
  • If `MySocketClass` has the socket as member attribute, calling `getLine()` inside the stream insertion operator shouldn't be a problem. And from the class name I choose, it's implicit that it has the socket as a member. – agrum May 22 '14 at 23:51
  • I have added and edit to my original post. but i am thinking that maybe i should be using a custom stream buffer as Dietmar Kühl said. ive found it hard to find resources on this subject. could anyone link me to a tutorial or online information on it? Thankyou – Ace_Of_John May 25 '14 at 21:56