Thread: Drieving from iostream

  1. #1
    & the hat of GPL slaying Thantos's Avatar
    Join Date
    Sep 2001
    Posts
    5,681

    Drieving from iostream

    After some work on that sockio class I did some more reading on OOP and decided it might be best if it could be treated as an iostream. So I'm working on its rebirth using that idea

    I'm starting with the output and it works fine by itself but once I try to use it as an ostream or iostream it segfaults. It appears to be using the ostream's operator << instead of the classes.

    I tried to make the inheritance private but doing so provided me with the following error:
    fields of `iostream' are inaccessible in `SocketInputOutput::SocketInOut' due to private inheritance
    sockio.h
    Code:
    #ifndef SOCKIO_H_
    #define SOCKIO_H_
    #define SOCKIO_NIX_
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <string>
    #include <list>
    #include <cerrno>
    #include <sstream>
    namespace SocketInputOutput {
    class SocketInOut : private iostream{
    	int sock;
    	void SockRecv ();
    	public:
    	 SocketInOut(int x) {
    		sock = x;
    	 }
    	 inline int getsocket() { return sock; }
    	 inline void changesocket(int x) { sock = x; }
    	 inline SocketInOut& operator << ( SocketInOut & (*f)(SocketInOut &) ){
    		return f(*this);
    	 }
    	 // Ouput Functions
    	 template <typename T>
    	 SocketInOut& operator <<(T x) {
    		ostringstream sout;
    		sout<<x;
    		return (*this)<<(sout.str());
    	 }
    	 SocketInOut& operator <<(string x);
    };
    inline SocketInOut &endl (SocketInOut &x){
    	return x<<"\r\n";
    }
    };
    #endif
    sockio.cpp
    Code:
    #include <string>
    #include <cstring>
    #include <cctype>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <sys/time.h>
    #include <netinet/in.h>
    #include <unistd.h>
    #include <sched.h>
    #include "sockio.h"
    using SocketInputOutput::SocketInOut;
    using SocketInputOutput::endl;
    SocketInOut & SocketInOut::operator <<(string s)
    {
    send (sock, s.c_str(), s.size(), 0);
    return (*this);
    }
    sockio_test.cpp
    Code:
    #include "sockio.h"
    #include "sockconn.h"
    using SocketInputOutput::SocketInOut;
    using SocketInputOutput::endl;
    void output (iostream &);
    int main()
    {
    SocketInOut io(getconn());
    output (io);
    }
    void output (iostream &x) {
    x<<"This is a test"<<endl;
    }
    the sockconn.cpp and sockconn.h just provide getconn() which waits for a connect and returns the sock (or throws an exception).

    This is something I would like to figure out on my own as much as possible so please only nudges

  2. #2
    S Sang-drax's Avatar
    Join Date
    May 2002
    Location
    Göteborg, Sweden
    Posts
    2,072
    If you want to use template<T> operator<< you don't have to inherit from ostream.
    It will work anyway.

    However, it is better to inherit from ostream, since you will get the formatting capabilities like setw() and precision().

    Wait a minute and I'll post an example.
    Last edited by Sang-drax : Tomorrow at 02:21 AM. Reason: Time travelling

  3. #3
    S Sang-drax's Avatar
    Join Date
    May 2002
    Location
    Göteborg, Sweden
    Posts
    2,072
    OK, here's how to create a custom cout:
    Just replace the streambuffer functions with functions that read/write to the socket.
    Code:
     
    #include <iostream>
    #include <iomanip>
    #include <cstdlib>
    
    class MyStreamBuf : public std::streambuf {
    public:
    	MyStreamBuf(FILE *file) 
    	: f(file)
    	{
    		 setg(buf, buf+1, buf+1);
    	}
    protected:
    	virtual int underflow()   
    	{
    		setg(buf, buf, buf+1); 
    		return buf[0]=fgetc(f);
    	}
     virtual int overflow (int c = EOF)
    	{
    		return fputc(c, f);
    	}
     virtual int pbackfail(int c = EOF)
    	{
    		return ungetc(c, f);
    	}
    private:
    	FILE *f;
    	char buf[1];
    };
     
    int main()
    {
    	using namespace std;
    	
    	//Create a custsom ostream object with our own
    	//stream buffer
    	ostream myOut( new MyStreamBuf(stdout) );
    	myOut << setw(4) << setfill('0') <<  1;
    	cin.get();
    }
    Last edited by Sang-drax; 06-23-2004 at 03:11 PM. Reason: Stupid tabs
    Last edited by Sang-drax : Tomorrow at 02:21 AM. Reason: Time travelling

  4. #4
    S Sang-drax's Avatar
    Join Date
    May 2002
    Location
    Göteborg, Sweden
    Posts
    2,072
    Here is how to create an object that is capable of both input and output. The example uses the console, but if you just replace the constructors with constructors that takes an IP-address and a port number, it'll work fine.
    Code:
    #include <iostream>
    #include <iomanip>
    #include <cstdlib>
    
    class MyStreamBuf : public std::streambuf {
    public:
    	MyStreamBuf(FILE *outFile, FILE* inFile) 
    	: o(outFile), i(inFile)
    	{
    		setg(buf, buf+1, buf+1);
    	}
    protected:
    	virtual int underflow()   
    	{
    		setg(buf, buf, buf+1); 
    		return buf[0]=fgetc(i);
    	}
    	virtual int overflow (int c = EOF)
    	{
    		return fputc(c, o);
    	}
    private:
    	FILE *o;
    	FILE *i;
    	char buf[1];
    };
     
    class myInOut:
    	public std::iostream
    {
    protected:
    	MyStreamBuf strBuf;
    public:
    	myInOut() 
    	: strBuf(stdout, stdin),
    	  std::iostream( &strBuf )
    	{
    	}
    };
    int main()
    {
    	using namespace std;
    	
    	//Create a custom ostream object with our own
    	//stream buffer
    	myInOut inout;
    	//Print data
    	inout << "Input a number:";
    	//Read data
    	int a;
    	inout >> a;
    	return a;
    }
    Last edited by Sang-drax : Tomorrow at 02:21 AM. Reason: Time travelling

  5. #5
    & the hat of GPL slaying Thantos's Avatar
    Join Date
    Sep 2001
    Posts
    5,681
    I'm trying to do it without treating sockets as files. Thanks for the code and I'll look over it and see what I can learn from it

  6. #6
    S Sang-drax's Avatar
    Join Date
    May 2002
    Location
    Göteborg, Sweden
    Posts
    2,072
    I know, I just provided an example.

    Here's a socket class I just wrote which derives from iostream. I works fine under windows at least.
    Code:
     
    #include <iostream>
    #include <iomanip>
    #include <cstdlib>
    #include <string>
    #include <winsock.h>
    class MyStreamBuf : public std::streambuf {
    public:
    	MyStreamBuf(SOCKET* socket) 
    	: s(socket)
    	{
    		setg(buf, buf+1, buf+1);
    	}
    protected:
    	virtual int underflow() 
    	{
    		setg(buf, buf, buf+1); 
    		if (recv(*s, buf, 1, 0) != 1)
    			return EOF;
    		return buf[0];
    	}
    	virtual int overflow (int c = EOF)
    	{
    		char buf[1];
    		buf[0] = c;
    		send(*s, buf, 1, 0);
    		return c;
    	}
    private:
    	SOCKET* s;
    	char buf[1];
    };
     
    class socketstream:
    	public std::iostream
    {
    protected:
    	MyStreamBuf strBuf;
    	SOCKET s;
    	bool open;
    public:
    	socketstream(std::string address, int port) 
    	: strBuf(&s),
    	 std::iostream( &strBuf )
    	{
    		s = socket(AF_INET, SOCK_STREAM, 0); 
    		sockaddr_in remoteAddr; 
    		remoteAddr.sin_family = AF_INET;
    		remoteAddr.sin_addr.s_addr = inet_addr( address.c_str() );
    		remoteAddr.sin_port = htons( port );
    		memset (&remoteAddr.sin_zero,0, sizeof(remoteAddr.sin_zero));
    		open = connect(s, (sockaddr*)&remoteAddr, sizeof(remoteAddr)) != -1;
    	}
    	bool isOpen()
    	{
    		return open;
    	}
    	void closeConnection()
    	{
    		closesocket(s);
    	}
    };
    int main()
    {
    	using namespace std;
     
    	WSADATA data;
    	WSAStartup(2,&data);
    	//Create a custom ostream object with our own
    	//stream buffer
    	socketstream sock("213.67.169.210", 80);
    	if (!sock.isOpen())
    		return 1;
    	sock << "GET / HTTP/1.1\n\n";
    	std::string s;
    	while (!sock.eof())
    	{
    		getline( sock, s );
    		cout << s;
    	}
    	cout << "\n\n\nConnection closed.";
    	cin.get();
    }
    It connects to my webserver and issues a GET command and prints whatever it recieves. It seems to work but as I've never programmed sockets in C++ and this was made rather hasty I've probably made a few errors in the socket programming.
    But the principle works. I might extend it, as I've thought about creating this kind of class for some time. Only I haven't been able to derive from iostream until now.
    Last edited by Sang-drax; 06-23-2004 at 04:35 PM.
    Last edited by Sang-drax : Tomorrow at 02:21 AM. Reason: Time travelling

  7. #7
    & the hat of GPL slaying Thantos's Avatar
    Join Date
    Sep 2001
    Posts
    5,681
    Ah, so its the overflow and underflow that do the work, thats where I was getting hung up

  8. #8
    S Sang-drax's Avatar
    Join Date
    May 2002
    Location
    Göteborg, Sweden
    Posts
    2,072
    Yup, but perhaps you'd want a larger buffer than one byte, or is the buffer within the socket enough?
    Last edited by Sang-drax : Tomorrow at 02:21 AM. Reason: Time travelling

  9. #9
    & the hat of GPL slaying Thantos's Avatar
    Join Date
    Sep 2001
    Posts
    5,681
    Not sure on size of the buffer yet. I'm thinking 30 or so bytes but I might try to make that adjustable. For example if you are using a telnet connection and are using character by character transfer then a buffer of 1 makes the most sense

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. iostream overloaded operators
    By peckitt99 in forum C++ Programming
    Replies: 1
    Last Post: 08-10-2007, 05:32 AM
  2. iostream & hex?
    By dmlx90 in forum C++ Programming
    Replies: 0
    Last Post: 05-22-2002, 11:51 PM
  3. DJGPP Doesn't include IOSTREAM!!!!!!!!!!!
    By Frenchfry164 in forum Game Programming
    Replies: 12
    Last Post: 10-27-2001, 12:27 PM
  4. << in iostream
    By badman in forum C++ Programming
    Replies: 8
    Last Post: 10-18-2001, 10:19 PM
  5. Is there a C iostream?
    By Khisanth in forum C Programming
    Replies: 1
    Last Post: 09-05-2001, 12:34 AM